Imported Upstream version 3.20.0 upstream/3.20.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 8 Oct 2021 00:20:44 +0000 (09:20 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 8 Oct 2021 00:20:44 +0000 (09:20 +0900)
2237 files changed:
.clang-tidy
Auxiliary/cmake-mode.el
Auxiliary/vim/extract-upper-case.pl
Auxiliary/vim/syntax/cmake.vim
CMakeLists.txt
Copyright.txt
Help/command/DEVICE_LINK_OPTIONS.txt
Help/command/FIND_XXX.txt
Help/command/OPTIONS_SHELL.txt
Help/command/add_custom_command.rst
Help/command/add_custom_target.rst
Help/command/add_dependencies.rst
Help/command/add_executable.rst
Help/command/add_library.rst
Help/command/add_test.rst
Help/command/cmake_host_system_information.rst
Help/command/cmake_minimum_required.rst
Help/command/cmake_parse_arguments.rst
Help/command/cmake_path.rst [new file with mode: 0644]
Help/command/cmake_policy.rst
Help/command/configure_file.rst
Help/command/ctest_build.rst
Help/command/ctest_configure.rst
Help/command/ctest_coverage.rst
Help/command/ctest_memcheck.rst
Help/command/ctest_start.rst
Help/command/ctest_submit.rst
Help/command/ctest_test.rst
Help/command/ctest_update.rst
Help/command/ctest_upload.rst
Help/command/enable_language.rst
Help/command/execute_process.rst
Help/command/export.rst
Help/command/file.rst
Help/command/find_package.rst
Help/command/foreach.rst
Help/command/function.rst
Help/command/get_directory_property.rst
Help/command/get_filename_component.rst
Help/command/get_property.rst
Help/command/get_source_file_property.rst
Help/command/if.rst
Help/command/include_external_msproject.rst
Help/command/install.rst
Help/command/link_directories.rst
Help/command/list.rst
Help/command/macro.rst
Help/command/mark_as_advanced.rst
Help/command/math.rst
Help/command/message.rst
Help/command/project.rst
Help/command/separate_arguments.rst
Help/command/set_property.rst
Help/command/set_source_files_properties.rst
Help/command/site_name.rst
Help/command/source_group.rst
Help/command/string.rst
Help/command/target_compile_definitions.rst
Help/command/target_compile_features.rst
Help/command/target_compile_options.rst
Help/command/target_include_directories.rst
Help/command/target_link_libraries.rst
Help/command/target_link_options.rst
Help/command/target_precompile_headers.rst
Help/command/target_sources.rst
Help/command/try_compile.rst
Help/command/try_run.rst
Help/cpack_gen/archive.rst
Help/cpack_gen/bundle.rst
Help/cpack_gen/cygwin.rst
Help/cpack_gen/deb.rst
Help/cpack_gen/dmg.rst
Help/cpack_gen/external.rst
Help/cpack_gen/freebsd.rst
Help/cpack_gen/ifw.rst
Help/cpack_gen/nsis.rst
Help/cpack_gen/nuget.rst
Help/cpack_gen/packagemaker.rst
Help/cpack_gen/productbuild.rst
Help/cpack_gen/rpm.rst
Help/cpack_gen/wix.rst
Help/dev/README.rst
Help/dev/documentation.rst
Help/dev/experimental.rst [new file with mode: 0644]
Help/dev/maint.rst
Help/envvar/CUDAARCHS.rst [new file with mode: 0644]
Help/envvar/CUDAHOSTCXX.rst
Help/generator/CodeBlocks.rst
Help/generator/CodeLite.rst
Help/generator/Green Hills MULTI.rst
Help/generator/NMake Makefiles JOM.rst
Help/generator/Ninja Multi-Config.rst
Help/generator/Ninja.rst
Help/generator/VS_TOOLSET_HOST_ARCH.txt
Help/generator/Visual Studio 10 2010.rst
Help/generator/Visual Studio 11 2012.rst
Help/generator/Visual Studio 12 2013.rst
Help/generator/Visual Studio 14 2015.rst
Help/generator/Visual Studio 15 2017.rst
Help/generator/Visual Studio 9 2008.rst
Help/generator/Xcode.rst
Help/guide/ide-integration/index.rst
Help/guide/importing-exporting/MathFunctions/CMakeLists.txt
Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt
Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt
Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt
Help/guide/tutorial/index.rst
Help/guide/user-interaction/index.rst
Help/manual/cmake-commands.7.rst
Help/manual/cmake-compile-features.7.rst
Help/manual/cmake-developer.7.rst
Help/manual/cmake-env-variables.7.rst
Help/manual/cmake-file-api.7.rst
Help/manual/cmake-generator-expressions.7.rst
Help/manual/cmake-modules.7.rst
Help/manual/cmake-policies.7.rst
Help/manual/cmake-presets.7.rst
Help/manual/cmake-properties.7.rst
Help/manual/cmake-qt.7.rst
Help/manual/cmake-server.7.rst
Help/manual/cmake-toolchains.7.rst
Help/manual/cmake-variables.7.rst
Help/manual/cmake.1.rst
Help/manual/ctest.1.rst
Help/manual/presets/example.json
Help/manual/presets/schema.json
Help/module/UseJavaClassFilelist.rst
Help/module/UseJavaSymlinks.rst
Help/policy/CMP0026.rst
Help/policy/CMP0051.rst
Help/policy/CMP0115.rst [new file with mode: 0644]
Help/policy/CMP0116.rst [new file with mode: 0644]
Help/policy/CMP0117.rst [new file with mode: 0644]
Help/policy/CMP0118.rst [new file with mode: 0644]
Help/policy/CMP0119.rst [new file with mode: 0644]
Help/policy/CMP0120.rst [new file with mode: 0644]
Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst
Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst
Help/prop_sf/GENERATED.rst
Help/prop_sf/LANGUAGE.rst
Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.rst
Help/prop_tgt/AUTOMOC.rst
Help/prop_tgt/CUDA_STANDARD.rst
Help/prop_tgt/CXX_STANDARD.rst
Help/prop_tgt/EXPORT_COMPILE_COMMANDS.rst [new file with mode: 0644]
Help/prop_tgt/IMPORTED_OBJECTS.rst
Help/prop_tgt/IMPORTED_OBJECTS_CONFIG.rst
Help/prop_tgt/INSTALL_NAME_DIR.rst
Help/prop_tgt/LANG_CLANG_TIDY.rst
Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.rst
Help/prop_tgt/OBJCXX_STANDARD.rst
Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst
Help/prop_tgt/UNITY_BUILD.rst
Help/prop_tgt/UNITY_BUILD_UNIQUE_ID.rst [new file with mode: 0644]
Help/prop_tgt/XCODE_ATTRIBUTE_an-attribute.rst
Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY.rst [new file with mode: 0644]
Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY.rst [new file with mode: 0644]
Help/prop_tgt/XCODE_EMBED_type.rst [new file with mode: 0644]
Help/prop_tgt/XCODE_EMBED_type_PATH.rst [new file with mode: 0644]
Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt
Help/release/3.20.rst [new file with mode: 0644]
Help/release/index.rst
Help/variable/CMAKE_ANDROID_EXCEPTIONS.rst [new file with mode: 0644]
Help/variable/CMAKE_ANDROID_NDK_VERSION.rst [new file with mode: 0644]
Help/variable/CMAKE_ANDROID_RTTI.rst [new file with mode: 0644]
Help/variable/CMAKE_APPLE_SILICON_PROCESSOR.rst
Help/variable/CMAKE_BUILD_TYPE.rst
Help/variable/CMAKE_CUDA_ARCHITECTURES.rst
Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst [new file with mode: 0644]
Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst
Help/variable/CMAKE_LANG_BYTE_ORDER.rst [new file with mode: 0644]
Help/variable/CMAKE_LANG_CLANG_TIDY.rst
Help/variable/CMAKE_LANG_COMPILER_ID.rst
Help/variable/CMAKE_LINK_SEARCH_END_STATIC.rst
Help/variable/CMAKE_LINK_SEARCH_START_STATIC.rst
Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst
Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
Help/variable/CMAKE_UNITY_BUILD_UNIQUE_ID.rst [new file with mode: 0644]
Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst
Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
Help/variable/MSVC.rst
Help/variable/MSVC_IDE.rst
Modules/AddFileDependencies.cmake
Modules/BundleUtilities.cmake
Modules/CMakeCCompiler.cmake.in
Modules/CMakeCCompilerABI.c
Modules/CMakeCUDACompiler.cmake.in
Modules/CMakeCUDACompilerABI.cu
Modules/CMakeCUDACompilerId.cu.in
Modules/CMakeCUDAInformation.cmake
Modules/CMakeCXXCompiler.cmake.in
Modules/CMakeCXXCompilerABI.cpp
Modules/CMakeCXXCompilerId.cpp.in
Modules/CMakeCompilerABI.h
Modules/CMakeCompilerIdDetection.cmake
Modules/CMakeDetermineASMCompiler.cmake
Modules/CMakeDetermineCCompiler.cmake
Modules/CMakeDetermineCUDACompiler.cmake
Modules/CMakeDetermineCXXCompiler.cmake
Modules/CMakeDetermineCompileFeatures.cmake
Modules/CMakeDetermineCompilerABI.cmake
Modules/CMakeDetermineCompilerId.cmake
Modules/CMakeDetermineFortranCompiler.cmake
Modules/CMakeExtraGeneratorDetermineCompilerMacrosAndIncludeDirs.cmake
Modules/CMakeFindBinUtils.cmake
Modules/CMakeFortranCompilerId.F.in
Modules/CMakeGraphVizOptions.cmake
Modules/CMakeOBJCCompiler.cmake.in
Modules/CMakeOBJCCompilerABI.m
Modules/CMakeOBJCXXCompiler.cmake.in
Modules/CMakeOBJCXXCompilerABI.mm
Modules/CMakeOBJCXXCompilerId.mm.in
Modules/CMakePackageConfigHelpers.cmake
Modules/CMakeParseLibraryArchitecture.cmake [new file with mode: 0644]
Modules/CMakePlatformId.h.in
Modules/CMakeTestGNU.c
Modules/CPack.cmake
Modules/CPackIFW.cmake
Modules/CTest.cmake
Modules/CTestCoverageCollectGCOV.cmake
Modules/CTestUseLaunchers.cmake
Modules/CheckCSourceCompiles.cmake
Modules/CheckCSourceRuns.cmake
Modules/CheckCXXSourceCompiles.cmake
Modules/CheckCXXSourceRuns.cmake
Modules/CheckCXXSymbolExists.cmake
Modules/CheckFortranFunctionExists.cmake
Modules/CheckFortranSourceCompiles.cmake
Modules/CheckFunctionExists.cmake
Modules/CheckIPOSupported.cmake
Modules/CheckIncludeFile.cmake
Modules/CheckIncludeFileCXX.cmake
Modules/CheckIncludeFiles.cmake
Modules/CheckLanguage.cmake
Modules/CheckLibraryExists.cmake
Modules/CheckPrototypeDefinition.cmake
Modules/CheckStructHasMember.cmake
Modules/CheckSymbolExists.cmake
Modules/CheckTypeSize.cmake
Modules/CheckVariableExists.cmake
Modules/Compiler/ARMCC.cmake
Modules/Compiler/AppleClang-C.cmake
Modules/Compiler/AppleClang-CXX.cmake
Modules/Compiler/AppleClang-OBJC.cmake
Modules/Compiler/AppleClang-OBJCXX.cmake
Modules/Compiler/CMakeCommonCompilerMacros.cmake
Modules/Compiler/Clang-C.cmake
Modules/Compiler/Clang-CUDA.cmake
Modules/Compiler/Clang-CXX.cmake
Modules/Compiler/Clang-FindBinUtils.cmake
Modules/Compiler/Clang-OBJC.cmake
Modules/Compiler/Clang-OBJCXX.cmake
Modules/Compiler/Clang.cmake
Modules/Compiler/Cray-Fortran.cmake
Modules/Compiler/GNU-ASM.cmake
Modules/Compiler/GNU-C.cmake
Modules/Compiler/GNU-CXX.cmake
Modules/Compiler/GNU-OBJC.cmake
Modules/Compiler/GNU-OBJCXX.cmake
Modules/Compiler/GNU.cmake
Modules/Compiler/IAR-ASM.cmake
Modules/Compiler/IAR-C.cmake
Modules/Compiler/IAR-CXX.cmake
Modules/Compiler/IAR-DetermineCompiler.cmake
Modules/Compiler/IAR-FindBinUtils.cmake
Modules/Compiler/IAR.cmake
Modules/Compiler/Intel-C.cmake
Modules/Compiler/Intel-CXX.cmake
Modules/Compiler/Intel-ISPC.cmake
Modules/Compiler/IntelLLVM-ASM.cmake [new file with mode: 0644]
Modules/Compiler/IntelLLVM-C.cmake [new file with mode: 0644]
Modules/Compiler/IntelLLVM-CXX.cmake [new file with mode: 0644]
Modules/Compiler/IntelLLVM-DetermineCompiler.cmake [new file with mode: 0644]
Modules/Compiler/IntelLLVM-Fortran.cmake [new file with mode: 0644]
Modules/Compiler/IntelLLVM.cmake [new file with mode: 0644]
Modules/Compiler/MSVC-C.cmake
Modules/Compiler/NAG-Fortran.cmake
Modules/Compiler/NVHPC-C.cmake [new file with mode: 0644]
Modules/Compiler/NVHPC-CXX.cmake [new file with mode: 0644]
Modules/Compiler/NVHPC-DetermineCompiler.cmake [new file with mode: 0644]
Modules/Compiler/NVHPC-Fortran.cmake [new file with mode: 0644]
Modules/Compiler/NVHPC.cmake [new file with mode: 0644]
Modules/Compiler/NVIDIA-CUDA.cmake
Modules/Compiler/PGI-CXX.cmake
Modules/Compiler/QCC.cmake
Modules/Compiler/SunPro-C.cmake
Modules/Compiler/SunPro-CXX.cmake
Modules/Compiler/TI.cmake
Modules/Compiler/XL.cmake
Modules/Compiler/XLClang-C.cmake
Modules/Compiler/XLClang-CXX.cmake
Modules/DartConfiguration.tcl.in
Modules/Documentation.cmake
Modules/ExternalData.cmake
Modules/ExternalProject-gitupdate.cmake.in
Modules/ExternalProject.cmake
Modules/FeatureSummary.cmake
Modules/FetchContent.cmake
Modules/FetchContent/CMakeLists.cmake.in
Modules/FindALSA.cmake
Modules/FindArmadillo.cmake
Modules/FindBISON.cmake
Modules/FindBLAS.cmake
Modules/FindBZip2.cmake
Modules/FindBoost.cmake
Modules/FindCUDA.cmake
Modules/FindCUDA/select_compute_arch.cmake
Modules/FindCUDAToolkit.cmake
Modules/FindCURL.cmake
Modules/FindCups.cmake
Modules/FindCurses.cmake
Modules/FindDoxygen.cmake
Modules/FindEXPAT.cmake
Modules/FindFLEX.cmake
Modules/FindFLTK.cmake
Modules/FindFreetype.cmake
Modules/FindGDAL.cmake
Modules/FindGLEW.cmake
Modules/FindGLUT.cmake
Modules/FindGTK2.cmake
Modules/FindGTest.cmake
Modules/FindGettext.cmake
Modules/FindGit.cmake
Modules/FindGnuTLS.cmake
Modules/FindHDF5.cmake
Modules/FindHg.cmake
Modules/FindICU.cmake
Modules/FindIce.cmake
Modules/FindImageMagick.cmake
Modules/FindIntl.cmake
Modules/FindJPEG.cmake
Modules/FindJava.cmake
Modules/FindLAPACK.cmake
Modules/FindLATEX.cmake
Modules/FindLibArchive.cmake
Modules/FindLibLZMA.cmake
Modules/FindLibXml2.cmake
Modules/FindLibXslt.cmake
Modules/FindLua.cmake
Modules/FindMPI.cmake
Modules/FindMatlab.cmake
Modules/FindOpenACC.cmake
Modules/FindOpenCL.cmake
Modules/FindOpenGL.cmake
Modules/FindOpenMP.cmake
Modules/FindOpenSSL.cmake
Modules/FindPNG.cmake
Modules/FindPackageHandleStandardArgs.cmake
Modules/FindPkgConfig.cmake
Modules/FindPostgreSQL.cmake
Modules/FindProtobuf.cmake
Modules/FindPython.cmake
Modules/FindPython/Support.cmake
Modules/FindPython2.cmake
Modules/FindPython3.cmake
Modules/FindQt.cmake
Modules/FindQt3.cmake
Modules/FindRuby.cmake
Modules/FindSDL.cmake
Modules/FindSWIG.cmake
Modules/FindSquish.cmake
Modules/FindSubversion.cmake
Modules/FindTIFF.cmake
Modules/FindThreads.cmake
Modules/FindVulkan.cmake
Modules/FindX11.cmake
Modules/FindXercesC.cmake
Modules/FindZLIB.cmake
Modules/FindwxWidgets.cmake
Modules/FortranCInterface.cmake
Modules/FortranCInterface/Detect.cmake
Modules/GNUInstallDirs.cmake
Modules/GenerateExportHeader.cmake
Modules/GetPrerequisites.cmake
Modules/GoogleTest.cmake
Modules/GoogleTestAddTests.cmake
Modules/InstallRequiredSystemLibraries.cmake
Modules/Internal/CPack/CPack.NuGet.nuspec.in
Modules/Internal/CPack/CPackDeb.cmake
Modules/Internal/CPack/CPackNuGet.cmake
Modules/Internal/CPack/NSIS.template.in
Modules/MacroAddFileDependencies.cmake
Modules/Platform/Android-Clang.cmake
Modules/Platform/Android-Common.cmake
Modules/Platform/Android-Determine.cmake
Modules/Platform/Android-Initialize.cmake
Modules/Platform/Android.cmake
Modules/Platform/Android/Determine-Compiler.cmake
Modules/Platform/Android/abi-arm64-v8a-Clang.cmake
Modules/Platform/Android/abi-armeabi-Clang.cmake
Modules/Platform/Android/abi-armeabi-v6-Clang.cmake
Modules/Platform/Android/abi-armeabi-v7a-Clang.cmake
Modules/Platform/Android/abi-mips-Clang.cmake
Modules/Platform/Android/abi-mips64-Clang.cmake
Modules/Platform/Android/abi-x86-Clang.cmake
Modules/Platform/Android/abi-x86_64-Clang.cmake
Modules/Platform/Apple-IntelLLVM-C.cmake [new file with mode: 0644]
Modules/Platform/Apple-IntelLLVM-CXX.cmake [new file with mode: 0644]
Modules/Platform/Apple-IntelLLVM-Fortran.cmake [new file with mode: 0644]
Modules/Platform/Apple-IntelLLVM.cmake [new file with mode: 0644]
Modules/Platform/Linux-IntelLLVM-C.cmake [new file with mode: 0644]
Modules/Platform/Linux-IntelLLVM-CXX.cmake [new file with mode: 0644]
Modules/Platform/Linux-IntelLLVM-Fortran.cmake [new file with mode: 0644]
Modules/Platform/Linux-IntelLLVM.cmake [new file with mode: 0644]
Modules/Platform/Linux-NVHPC-C.cmake [new file with mode: 0644]
Modules/Platform/Linux-NVHPC-CXX.cmake [new file with mode: 0644]
Modules/Platform/Linux-NVHPC-Fortran.cmake [new file with mode: 0644]
Modules/Platform/Linux-NVHPC.cmake [new file with mode: 0644]
Modules/Platform/Linux.cmake
Modules/Platform/Windows-Clang-C.cmake
Modules/Platform/Windows-Clang-CXX.cmake
Modules/Platform/Windows-Clang.cmake
Modules/Platform/Windows-Embarcadero.cmake
Modules/Platform/Windows-Intel-C.cmake
Modules/Platform/Windows-Intel-CXX.cmake
Modules/Platform/Windows-Intel.cmake
Modules/Platform/Windows-IntelLLVM-ASM.cmake [new file with mode: 0644]
Modules/Platform/Windows-IntelLLVM-C.cmake [new file with mode: 0644]
Modules/Platform/Windows-IntelLLVM-CXX.cmake [new file with mode: 0644]
Modules/Platform/Windows-IntelLLVM-Fortran.cmake [new file with mode: 0644]
Modules/Platform/Windows-IntelLLVM.cmake [new file with mode: 0644]
Modules/Platform/Windows-MSVC-C.cmake
Modules/Platform/Windows-MSVC-CXX.cmake
Modules/Platform/Windows-MSVC.cmake
Modules/ProcessorCount.cmake
Modules/TestBigEndian.cmake
Modules/UseJava.cmake
Modules/UseJava/ClassFilelist.cmake [moved from Modules/UseJavaClassFilelist.cmake with 80% similarity]
Modules/UseJava/Symlinks.cmake [moved from Modules/UseJavaSymlinks.cmake with 72% similarity]
Modules/UseJava/javaTargets.cmake.in [moved from Modules/javaTargets.cmake.in with 96% similarity]
Modules/UseSWIG.cmake
Modules/WriteCompilerDetectionHeader.cmake
Source/CMakeLists.txt
Source/CMakeVersion.cmake
Source/CPack/IFW/cmCPackIFWCommon.cxx
Source/CPack/IFW/cmCPackIFWCommon.h
Source/CPack/IFW/cmCPackIFWInstaller.cxx
Source/CPack/IFW/cmCPackIFWInstaller.h
Source/CPack/IFW/cmCPackIFWPackage.cxx
Source/CPack/IFW/cmCPackIFWPackage.h
Source/CPack/IFW/cmCPackIFWRepository.cxx
Source/CPack/IFW/cmCPackIFWRepository.h
Source/CPack/cmCPackArchiveGenerator.cxx
Source/CPack/cmCPackComponentGroup.cxx
Source/CPack/cmCPackDebGenerator.cxx
Source/CPack/cmCPackExternalGenerator.cxx
Source/CPack/cmCPackGenerator.cxx
Source/CPack/cmCPackNSISGenerator.cxx
Source/CPack/cmCPackNuGetGenerator.cxx
Source/CPack/cmCPackRPMGenerator.cxx
Source/CPack/cmCPackSTGZGenerator.cxx
Source/CTest/cmCTestBZR.cxx
Source/CTest/cmCTestBuildCommand.cxx
Source/CTest/cmCTestCoverageHandler.cxx
Source/CTest/cmCTestLaunch.cxx
Source/CTest/cmCTestLaunch.h
Source/CTest/cmCTestLaunchReporter.cxx
Source/CTest/cmCTestLaunchReporter.h
Source/CTest/cmCTestMemCheckHandler.cxx
Source/CTest/cmCTestMemCheckHandler.h
Source/CTest/cmCTestMultiProcessHandler.cxx
Source/CTest/cmCTestP4.cxx
Source/CTest/cmCTestResourceGroupsLexerHelper.cxx
Source/CTest/cmCTestRunTest.cxx
Source/CTest/cmCTestSVN.cxx
Source/CTest/cmCTestTestHandler.cxx
Source/CTest/cmCTestUpdateCommand.cxx
Source/CTest/cmParseBlanketJSCoverage.cxx
Source/CTest/cmParseCoberturaCoverage.cxx
Source/CTest/cmParseDelphiCoverage.cxx
Source/CTest/cmProcess.cxx
Source/CTest/cmProcess.h
Source/CursesDialog/cmCursesMainForm.cxx
Source/CursesDialog/form/CMakeLists.txt
Source/LexerParser/cmCommandArgumentParser.cxx
Source/LexerParser/cmCommandArgumentParser.y
Source/LexerParser/cmCommandArgumentParserTokens.h
Source/LexerParser/cmDependsJavaParser.cxx
Source/LexerParser/cmDependsJavaParser.y
Source/LexerParser/cmDependsJavaParserTokens.h
Source/LexerParser/cmExprParser.cxx
Source/LexerParser/cmExprParser.y
Source/LexerParser/cmExprParserTokens.h
Source/LexerParser/cmFortranParser.cxx
Source/LexerParser/cmFortranParser.y
Source/LexerParser/cmFortranParserTokens.h
Source/LexerParser/cmGccDepfileLexer.cxx
Source/LexerParser/cmGccDepfileLexer.in.l
Source/QtDialog/CMakeLists.txt
Source/QtDialog/CMakeSetup.cxx
Source/QtDialog/CMakeSetupDialog.cxx
Source/QtDialog/CMakeSetupDialog.ui
Source/QtDialog/EnvironmentDialog.cxx
Source/QtDialog/EnvironmentDialog.ui
Source/QtDialog/QCMake.cxx
Source/QtDialog/QCMakeCacheView.cxx
Source/QtDialog/QCMakeWidgets.cxx
Source/bindexplib.cxx
Source/cmAddCustomCommandCommand.cxx
Source/cmAddCustomTargetCommand.cxx
Source/cmAddLibraryCommand.cxx
Source/cmAlgorithms.h
Source/cmArchiveWrite.cxx
Source/cmArchiveWrite.h
Source/cmAuxSourceDirectoryCommand.cxx
Source/cmBase32.cxx
Source/cmBase32.h
Source/cmCMakePath.cxx
Source/cmCMakePathCommand.cxx
Source/cmCMakePolicyCommand.cxx
Source/cmCMakePresetsFile.cxx
Source/cmCMakePresetsFile.h
Source/cmCPluginAPI.cxx
Source/cmCTest.cxx
Source/cmCTest.h
Source/cmCacheManager.cxx
Source/cmCacheManager.h
Source/cmCheckCustomOutputs.cxx [deleted file]
Source/cmCheckCustomOutputs.h [deleted file]
Source/cmCommandArgumentParserHelper.cxx
Source/cmCommandLineArgument.h [new file with mode: 0644]
Source/cmCommands.cxx
Source/cmCommonTargetGenerator.cxx
Source/cmComputeLinkInformation.cxx
Source/cmComputeTargetDepends.cxx
Source/cmConditionEvaluator.cxx
Source/cmConfigure.cmake.h.in
Source/cmConfigureFileCommand.cxx
Source/cmConnection.cxx [deleted file]
Source/cmConnection.h [deleted file]
Source/cmConsoleBuf.cxx
Source/cmConsoleBuf.h
Source/cmCreateTestSourceList.cxx
Source/cmCryptoHash.cxx
Source/cmCustomCommand.cxx
Source/cmCustomCommand.h
Source/cmCustomCommandGenerator.cxx
Source/cmCustomCommandGenerator.h
Source/cmCustomCommandTypes.h
Source/cmDepends.cxx
Source/cmDepends.h
Source/cmDependsC.cxx
Source/cmDependsCompiler.cxx [new file with mode: 0644]
Source/cmDependsCompiler.h [new file with mode: 0644]
Source/cmDependsFortran.cxx
Source/cmDependsJavaParserHelper.cxx
Source/cmDependsJavaParserHelper.h
Source/cmDocumentation.cxx
Source/cmELF.cxx
Source/cmELF.h
Source/cmExecuteProcessCommand.cxx
Source/cmExportFileGenerator.cxx
Source/cmExportInstallFileGenerator.cxx
Source/cmExprParserHelper.cxx
Source/cmExprParserHelper.h
Source/cmExternalMakefileProjectGenerator.h
Source/cmExtraCodeBlocksGenerator.cxx
Source/cmExtraCodeLiteGenerator.cxx
Source/cmExtraCodeLiteGenerator.h
Source/cmExtraSublimeTextGenerator.cxx
Source/cmFLTKWrapUICommand.cxx
Source/cmFileAPI.cxx
Source/cmFileAPI.h
Source/cmFileAPICMakeFiles.cxx
Source/cmFileAPICache.cxx
Source/cmFileAPICodemodel.cxx
Source/cmFileAPIToolchains.cxx [new file with mode: 0644]
Source/cmFileAPIToolchains.h [new file with mode: 0644]
Source/cmFileCommand.cxx
Source/cmFileLock.cxx
Source/cmFileLock.h
Source/cmFileLockPool.cxx
Source/cmFileLockUnix.cxx
Source/cmFileMonitor.cxx [deleted file]
Source/cmFileMonitor.h [deleted file]
Source/cmFilePathChecksum.cxx
Source/cmFileTimes.cxx
Source/cmFileTimes.h
Source/cmFindCommon.cxx
Source/cmFindLibraryCommand.cxx
Source/cmFindPackageCommand.cxx
Source/cmFindPathCommand.cxx
Source/cmFindPathCommand.h
Source/cmFindProgramCommand.cxx
Source/cmFunctionBlocker.h
Source/cmFunctionCommand.cxx
Source/cmGccDepfileLexerHelper.cxx
Source/cmGccDepfileLexerHelper.h
Source/cmGccDepfileReader.cxx
Source/cmGccDepfileReader.h
Source/cmGeneratedFileStream.cxx
Source/cmGeneratorExpressionDAGChecker.cxx
Source/cmGeneratorExpressionDAGChecker.h
Source/cmGeneratorExpressionEvaluationFile.cxx
Source/cmGeneratorExpressionEvaluationFile.h
Source/cmGeneratorExpressionEvaluator.cxx
Source/cmGeneratorExpressionEvaluator.h
Source/cmGeneratorExpressionLexer.cxx
Source/cmGeneratorExpressionNode.cxx
Source/cmGeneratorExpressionParser.cxx
Source/cmGeneratorExpressionParser.h
Source/cmGeneratorTarget.cxx
Source/cmGeneratorTarget.h
Source/cmGetDirectoryPropertyCommand.cxx
Source/cmGetPropertyCommand.cxx
Source/cmGetSourceFilePropertyCommand.cxx
Source/cmGhsMultiTargetGenerator.cxx
Source/cmGlobalBorlandMakefileGenerator.cxx
Source/cmGlobalGenerator.cxx
Source/cmGlobalGenerator.h
Source/cmGlobalGhsMultiGenerator.cxx
Source/cmGlobalNMakeMakefileGenerator.cxx
Source/cmGlobalNinjaGenerator.cxx
Source/cmGlobalNinjaGenerator.h
Source/cmGlobalUnixMakefileGenerator3.cxx
Source/cmGlobalUnixMakefileGenerator3.h
Source/cmGlobalVisualStudio7Generator.cxx
Source/cmGlobalVisualStudio8Generator.cxx
Source/cmGlobalVisualStudioGenerator.cxx
Source/cmGlobalVisualStudioVersionedGenerator.cxx
Source/cmGlobalWatcomWMakeGenerator.cxx
Source/cmGlobalXCodeGenerator.cxx
Source/cmGlobalXCodeGenerator.h
Source/cmGraphVizWriter.cxx
Source/cmIncludeCommand.cxx
Source/cmInstallCommand.cxx
Source/cmInstallCommandArguments.cxx
Source/cmInstallDirectoryGenerator.cxx
Source/cmInstallDirectoryGenerator.h
Source/cmInstallExportGenerator.cxx
Source/cmInstallExportGenerator.h
Source/cmInstallFilesCommand.cxx
Source/cmInstallFilesGenerator.cxx
Source/cmInstallFilesGenerator.h
Source/cmInstallGenerator.cxx
Source/cmInstallGenerator.h
Source/cmInstallProgramsCommand.cxx
Source/cmInstallScriptGenerator.cxx
Source/cmInstallScriptGenerator.h
Source/cmInstallSubdirectoryGenerator.cxx
Source/cmInstallSubdirectoryGenerator.h
Source/cmInstallTargetGenerator.cxx
Source/cmInstallTargetGenerator.h
Source/cmJsonObjectDictionary.h [deleted file]
Source/cmJsonObjects.cxx [deleted file]
Source/cmJsonObjects.h [deleted file]
Source/cmLinkItemGraphVisitor.cxx
Source/cmLinkLineDeviceComputer.cxx
Source/cmLinkedTree.h
Source/cmListCommand.cxx
Source/cmListFileCache.cxx
Source/cmListFileCache.h
Source/cmLoadCommandCommand.cxx
Source/cmLocalGenerator.cxx
Source/cmLocalGenerator.h
Source/cmLocalNinjaGenerator.cxx
Source/cmLocalNinjaGenerator.h
Source/cmLocalUnixMakefileGenerator3.cxx
Source/cmLocalUnixMakefileGenerator3.h
Source/cmLocalVisualStudio7Generator.cxx
Source/cmMSVC60LinkLineComputer.cxx
Source/cmMachO.h
Source/cmMacroCommand.cxx
Source/cmMakefile.cxx
Source/cmMakefile.h
Source/cmMakefileExecutableTargetGenerator.cxx
Source/cmMakefileLibraryTargetGenerator.cxx
Source/cmMakefileTargetGenerator.cxx
Source/cmMakefileUtilityTargetGenerator.cxx
Source/cmNewLineStyle.cxx
Source/cmNinjaLinkLineComputer.cxx
Source/cmNinjaLinkLineDeviceComputer.cxx
Source/cmNinjaNormalTargetGenerator.cxx
Source/cmNinjaNormalTargetGenerator.h
Source/cmNinjaTargetGenerator.cxx
Source/cmNinjaTargetGenerator.h
Source/cmNinjaUtilityTargetGenerator.cxx
Source/cmNinjaUtilityTargetGenerator.h
Source/cmOSXBundleGenerator.h
Source/cmOutputConverter.cxx
Source/cmOutputConverter.h
Source/cmOutputRequiredFilesCommand.cxx
Source/cmPipeConnection.cxx [deleted file]
Source/cmPipeConnection.h [deleted file]
Source/cmPolicies.h
Source/cmProcessOutput.cxx
Source/cmProcessOutput.h
Source/cmProjectCommand.cxx
Source/cmPropertyMap.cxx
Source/cmQTWrapCPPCommand.cxx
Source/cmQTWrapUICommand.cxx
Source/cmQtAutoGen.h
Source/cmQtAutoGenGlobalInitializer.cxx
Source/cmQtAutoGenGlobalInitializer.h
Source/cmQtAutoGenInitializer.cxx
Source/cmQtAutoGenInitializer.h
Source/cmQtAutoGenerator.cxx
Source/cmQtAutoGenerator.h
Source/cmQtAutoMocUic.cxx
Source/cmQtAutoRcc.cxx
Source/cmRST.cxx
Source/cmRulePlaceholderExpander.cxx
Source/cmRulePlaceholderExpander.h
Source/cmRuntimeDependencyArchive.cxx
Source/cmScanDepFormat.cxx [new file with mode: 0644]
Source/cmScanDepFormat.h [new file with mode: 0644]
Source/cmScriptGenerator.cxx
Source/cmServer.cxx [deleted file]
Source/cmServer.h [deleted file]
Source/cmServerConnection.cxx [deleted file]
Source/cmServerConnection.h [deleted file]
Source/cmServerDictionary.h [deleted file]
Source/cmServerProtocol.cxx [deleted file]
Source/cmServerProtocol.h [deleted file]
Source/cmSetPropertyCommand.cxx
Source/cmSetPropertyCommand.h
Source/cmSetSourceFilesPropertiesCommand.cxx
Source/cmSourceFile.cxx
Source/cmSourceFile.h
Source/cmSourceFileLocation.cxx
Source/cmStandardLevelResolver.cxx
Source/cmStandardLexer.h
Source/cmState.cxx
Source/cmState.h
Source/cmStateDirectory.cxx
Source/cmStateDirectory.h
Source/cmString.cxx
Source/cmString.hxx
Source/cmStringAlgorithms.cxx
Source/cmStringAlgorithms.h
Source/cmStringCommand.cxx
Source/cmSystemTools.cxx
Source/cmSystemTools.h
Source/cmTarget.cxx
Source/cmTarget.h
Source/cmTargetIncludeDirectoriesCommand.cxx
Source/cmTargetPrecompileHeadersCommand.cxx
Source/cmTargetPropCommandBase.cxx
Source/cmTargetPropCommandBase.h
Source/cmTargetSourcesCommand.cxx
Source/cmTestGenerator.cxx
Source/cmTimestamp.cxx
Source/cmTimestamp.h
Source/cmTransformDepfile.cxx [new file with mode: 0644]
Source/cmTransformDepfile.h [new file with mode: 0644]
Source/cmTryRunCommand.cxx
Source/cmTryRunCommand.h
Source/cmUVHandlePtr.cxx
Source/cmUVHandlePtr.h
Source/cmUuid.cxx
Source/cmVersion.h
Source/cmVisualStudio10TargetGenerator.cxx
Source/cmWorkerPool.cxx
Source/cmWorkerPool.h
Source/cmWorkingDirectory.h
Source/cmXCOFF.cxx [new file with mode: 0644]
Source/cmXCOFF.h [new file with mode: 0644]
Source/cmXCodeObject.h
Source/cmXMLSafe.cxx
Source/cmXMLSafe.h
Source/cmXMLWriter.h
Source/cm_codecvt.cxx
Source/cmake.cxx
Source/cmake.h
Source/cmakemain.cxx
Source/cmcmd.cxx
Source/ctest.cxx
Source/kwsys/FStream.hxx.in
Source/kwsys/ProcessWin32.c
Source/kwsys/SystemInformation.cxx
Source/kwsys/testFStream.cxx
Templates/MSBuild/FlagTables/v142_CSharp.json
Templates/MSBuild/FlagTables/v142_Link.json
Templates/MSBuild/FlagTables/v14_LIB.json
Templates/TestDriver.cxx.in
Tests/Architecture/CMakeLists.txt
Tests/ArgumentExpansion/CMakeLists.txt
Tests/Assembler/CMakeLists.txt
Tests/BuildDepends/Project/CMakeLists.txt
Tests/BundleTest/BundleLib.cxx
Tests/BundleTest/BundleSubDir/CMakeLists.txt
Tests/BundleTest/CMakeLists.txt
Tests/BundleUtilities/CMakeLists.txt
Tests/CFBundleTest/CMakeLists.txt
Tests/CMakeCommands/add_compile_options/CMakeLists.txt
Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
Tests/CMakeCommands/target_compile_options/CMakeLists.txt
Tests/CMakeCommands/target_include_directories/CMakeLists.txt
Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
Tests/CMakeLib/run_compile_commands.cxx
Tests/CMakeLib/testCMExtMemory.cxx
Tests/CMakeLib/testGccDepfileReader.cxx
Tests/CMakeLib/testGccDepfileReader_data/deps4.d [new file with mode: 0644]
Tests/CMakeLib/testGccDepfileReader_data/deps5.d [new file with mode: 0644]
Tests/CMakeLib/testGccDepfileReader_data/deps5.txt [new file with mode: 0644]
Tests/CMakeLib/testGccDepfileReader_data/deps7.d [new file with mode: 0644]
Tests/CMakeLib/testGccDepfileReader_data/deps7.txt [new file with mode: 0644]
Tests/CMakeLib/testOptional.cxx
Tests/CMakeLib/testRST.expect
Tests/CMakeLib/testRST.rst
Tests/CMakeLib/testUVProcessChain.cxx
Tests/CMakeLists.txt
Tests/CMakeOnly/CheckCXXCompilerFlag/CMakeLists.txt
Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt
Tests/CMakeOnly/MajorVersionSelection/CMakeLists.txt
Tests/CMakeOnly/find_library/CMakeLists.txt
Tests/CMakeOnly/find_path/CMakeLists.txt
Tests/CMakeServerLib/CMakeLists.txt [deleted file]
Tests/CMakeServerLib/testServerBuffering.cpp [deleted file]
Tests/CMakeTestMultipleConfigures/RunCMake.cmake [deleted file]
Tests/CMakeTests/CMakeLists.txt
Tests/CMakeTests/EndStuffTestScript.cmake
Tests/CMakeTests/FileDownloadTest.cmake.in
Tests/CMakeTests/ListTest.cmake.in
Tests/CPackComponentsDEB/CMakeLists.txt
Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-failure.cmake.in [new file with mode: 0644]
Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-success.cmake.in [new file with mode: 0644]
Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-failure.cmake [new file with mode: 0644]
Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-success.cmake [new file with mode: 0644]
Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake
Tests/CPackComponentsDEB/mylibapp.cpp
Tests/CPackComponentsDEB/shlibdeps-with-private-lib/CMakeLists.txt [new file with mode: 0644]
Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.cpp [new file with mode: 0644]
Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.h [new file with mode: 0644]
Tests/CPackNSISGenerator/CMakeLists.txt
Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
Tests/CPackTestAllGenerators/CMakeLists.txt
Tests/CPackWiXGenerator/CMakeLists.txt
Tests/CTestCoverageCollectGCOV/test.cmake.in
Tests/CTestLimitDashJ/CMakeLists.txt
Tests/CTestTest/SmallAndFast/CMakeLists.txt
Tests/CTestUpdateCVS.cmake.in
Tests/CTestUpdateGIT.cmake.in
Tests/CheckCompilerRelatedVariables/CMakeLists.txt
Tests/CompileDefinitions/CMakeLists.txt
Tests/CompileFeatures/CMakeLists.txt
Tests/CompileFeatures/default_dialect.cpp
Tests/CompileFeatures/genex_test.cpp
Tests/CompileOptions/CMakeLists.txt
Tests/ConfigSources/CMakeLists.txt
Tests/ConfigSources/custom1.cpp.in [new file with mode: 0644]
Tests/ConfigSources/custom2.cpp.in [new file with mode: 0644]
Tests/ConfigSources/custom3.cpp.in [new file with mode: 0644]
Tests/ConfigSources/custom4.cpp.in [new file with mode: 0644]
Tests/ConfigSources/custom5.cpp.in [new file with mode: 0644]
Tests/ConfigSources/main_debug.cpp
Tests/ConfigSources/main_other.cpp
Tests/Contracts/Trilinos/CMakeLists.txt
Tests/Contracts/VTK/CMakeLists.txt
Tests/Cuda/Toolkit/CMakeLists.txt
Tests/CudaOnly/CMakeLists.txt
Tests/CudaOnly/CompileFlags/CMakeLists.txt
Tests/CudaOnly/ExportPTX/CMakeLists.txt
Tests/CudaOnly/Toolkit/CMakeLists.txt
Tests/CudaOnly/ToolkitBeforeLang/CMakeLists.txt [new file with mode: 0644]
Tests/CudaOnly/ToolkitBeforeLang/main.cu [new file with mode: 0644]
Tests/CustomCommand/CMakeLists.txt
Tests/CustomCommand/empty_command.cxx [moved from Tests/Server/empty.cpp with 96% similarity]
Tests/EmptyDepends/CMakeLists.txt
Tests/ExportImport/Import/try_compile/CMakeLists.txt
Tests/ExternalProject/CMakeLists.txt
Tests/ExternalProject/Example/CMakeLists.txt
Tests/ExternalProject/gitrepo-sub-rec.tgz
Tests/ExternalProject/gitrepo-sub.tgz
Tests/ExternalProject/gitrepo.bash [new file with mode: 0755]
Tests/ExternalProject/gitrepo.tgz
Tests/ExternalProjectLocal/CMakeLists.txt
Tests/ExternalProjectUpdate/CMakeLists.txt
Tests/ExternalProjectUpdate/ExternalProjectUpdateTest.cmake
Tests/ExternalProjectUpdate/gitrepo.tgz
Tests/FindGTK2/atk/CMakeLists.txt
Tests/FindGTK2/atkmm/CMakeLists.txt
Tests/FindGTK2/cairo/CMakeLists.txt
Tests/FindGTK2/cairomm/CMakeLists.txt
Tests/FindGTK2/gdk/CMakeLists.txt
Tests/FindGTK2/gdk_pixbuf/CMakeLists.txt
Tests/FindGTK2/gdkmm/CMakeLists.txt
Tests/FindGTK2/gio/CMakeLists.txt
Tests/FindGTK2/giomm/CMakeLists.txt
Tests/FindGTK2/glib/CMakeLists.txt
Tests/FindGTK2/glibmm/CMakeLists.txt
Tests/FindGTK2/gmodule/CMakeLists.txt
Tests/FindGTK2/gobject/CMakeLists.txt
Tests/FindGTK2/gthread/CMakeLists.txt
Tests/FindGTK2/gtk/CMakeLists.txt
Tests/FindGTK2/gtkmm/CMakeLists.txt
Tests/FindGTK2/pango/CMakeLists.txt
Tests/FindGTK2/pangocairo/CMakeLists.txt
Tests/FindGTK2/pangoft2/CMakeLists.txt
Tests/FindGTK2/pangomm/CMakeLists.txt
Tests/FindGTK2/pangoxft/CMakeLists.txt
Tests/FindGTK2/sigc++/CMakeLists.txt
Tests/FindIntl/CMakeLists.txt [new file with mode: 0644]
Tests/FindIntl/Test/CMakeLists.txt [new file with mode: 0644]
Tests/FindIntl/Test/main.cxx [new file with mode: 0644]
Tests/FindPostgreSQL/Test/CMakeLists.txt
Tests/FindPython/CMakeLists.txt
Tests/FindPython/UnversionedNames/CMakeLists.txt [new file with mode: 0644]
Tests/Fortran/CMakeLists.txt
Tests/Fortran/myc.c
Tests/FortranC/CMakeLists.txt
Tests/FortranOnly/CMakeLists.txt
Tests/Fuzzing/README.rst [new file with mode: 0644]
Tests/Fuzzing/xml_parser_fuzzer.cc [new file with mode: 0644]
Tests/IncludeDirectories/CMakeLists.txt
Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
Tests/InterfaceLibrary/CMakeLists.txt
Tests/JavaNativeHeaders/CMakeLists.txt
Tests/JavaNativeHeaders/Import/CMakeLists.txt [new file with mode: 0644]
Tests/LinkDirectory/CMakeLists.txt
Tests/LinkDirectory/External/CMakeLists.txt
Tests/LinkFlags/CMakeLists.txt
Tests/MFC/CMakeLists.txt
Tests/MFC/CMakeLists.txt.in
Tests/MFC/try_compile/CMakeLists.txt
Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt
Tests/MacRuntimePath/A/CMakeLists.txt
Tests/MacRuntimePath/B/CMakeLists.txt
Tests/MissingSourceFile/CMakeLists.txt
Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
Tests/ObjectLibrary/CMakeLists.txt
Tests/ObjectLibrary/ExportLanguages/CMakeLists.txt
Tests/ObjectLibrary/ExportLanguages/ExportLanguagesTest/CMakeLists.txt
Tests/PDBDirectoryAndName/CMakeLists.txt
Tests/Plugin/PluginTest/CMakeLists.txt
Tests/PositionIndependentTargets/CMakeLists.txt
Tests/Preprocess/CMakeLists.txt
Tests/Qt4Targets/CMakeLists.txt
Tests/QtAutogen/AutogenOriginDependsOff/CMakeLists.txt
Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
Tests/QtAutogen/MocOnly/CMakeLists.txt
Tests/QtAutogen/MocOnly/CfgDebug.cpp [new file with mode: 0644]
Tests/QtAutogen/MocOnly/CfgDebug.hpp [new file with mode: 0644]
Tests/QtAutogen/MocOnly/CfgOther.cpp [new file with mode: 0644]
Tests/QtAutogen/MocOnly/CfgOther.hpp [new file with mode: 0644]
Tests/QtAutogen/MocOnly/main.cpp
Tests/QtAutogen/RerunMocBasic/CMakeLists.txt
Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt
Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in
Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in [new file with mode: 0644]
Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp [new file with mode: 0644]
Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h [new file with mode: 0644]
Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in [new file with mode: 0644]
Tests/QtAutogen/TestMacros.cmake
Tests/QtAutomocNoQt/CMakeLists.txt
Tests/RunCMake/ABI/C-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ABI/C.cmake [new file with mode: 0644]
Tests/RunCMake/ABI/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/ABI/CUDA.cmake [new file with mode: 0644]
Tests/RunCMake/ABI/CXX-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ABI/CXX.cmake [new file with mode: 0644]
Tests/RunCMake/ABI/OBJC.cmake [new file with mode: 0644]
Tests/RunCMake/ABI/OBJCXX.cmake [new file with mode: 0644]
Tests/RunCMake/ABI/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/ABI/TestBigEndian-NoLang-result.txt [moved from Tests/RunCMake/cmake_path/HAS_RELATIVE_PATH-wrong-path-result.txt with 100% similarity]
Tests/RunCMake/ABI/TestBigEndian-NoLang-stderr.txt [new file with mode: 0644]
Tests/RunCMake/ABI/TestBigEndian-NoLang.cmake [new file with mode: 0644]
Tests/RunCMake/Android/RunCMakeTest.cmake
Tests/RunCMake/Android/common.cmake
Tests/RunCMake/Android/ndk-search-order.cmake [new file with mode: 0644]
Tests/RunCMake/ArtifactOutputDirs/ArtifactOutputDirs.cmake [new file with mode: 0644]
Tests/RunCMake/ArtifactOutputDirs/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/ArtifactOutputDirs/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/ArtifactOutputDirs/check.cmake [new file with mode: 0644]
Tests/RunCMake/ArtifactOutputDirs/lib.c [moved from Tests/RunCMake/TargetObjects/empty.cpp with 51% similarity]
Tests/RunCMake/ArtifactOutputDirs/main.c [moved from Tests/Server/buildsystem1/foo.cpp with 51% similarity]
Tests/RunCMake/BuildDepends/CMakeLists.txt
Tests/RunCMake/BuildDepends/CompilerDependencies.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt [moved from Tests/RunCMake/cmake_path/HAS_RELATIVE_PATH-unexpected-arg-result.txt with 100% similarity]
Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/BuildDepends/GenerateDepFile.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/MakeDependencies.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/MakeDependencies.step1.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/MakeDependencies.step2.cmake [new file with mode: 0644]
Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
Tests/RunCMake/BuildDepends/WriteDepfile.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0026/LOCATION-and-TARGET_OBJECTS.cmake
Tests/RunCMake/CMP0026/clear-cached-information.cmake
Tests/RunCMake/CMP0104/CMP0104-OLD.cmake
Tests/RunCMake/CMP0106/CMP0106-NEW-stderr.txt
Tests/RunCMake/CMP0106/CMP0106-WARN-stderr.txt
Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt [moved from Tests/RunCMake/cmake_path/HAS_RELATIVE_PATH-missing-output-result.txt with 100% similarity]
Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0115/CMP0115-NEW.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt [moved from Tests/RunCMake/cmake_path/HAS_RELATIVE_PATH-invalid-output-result.txt with 100% similarity]
Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0115/CMP0115-OLD.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt [moved from Tests/RunCMake/cmake_path/GET-RELATIVE_PATH-wrong-path-result.txt with 100% similarity]
Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0115/CMP0115-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0115/CMP0115.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0115/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0115/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0115/main.c [moved from Tests/Server/buildsystem1/subdir/empty.cpp with 51% similarity]
Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-Mixed.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0116/Common.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0116/WriteDepfile.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0116/check.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Helper.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test1.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test10.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test11.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test12.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test13.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test14.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test15.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test2.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test3.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test3b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test4.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test4b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test5.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test6.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test7.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test8.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-Common-Test9.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-result.txt [moved from Tests/RunCMake/cmake_path/GET-RELATIVE_PATH-unexpected-arg-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test1.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test10-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test10.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test11-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test11.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-result.txt [moved from Tests/RunCMake/cmake_path/GET-RELATIVE_PATH-missing-output-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test12.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-result.txt [moved from Tests/RunCMake/cmake_path/GET-RELATIVE_PATH-invalid-output-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test13.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test14-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test14.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test15-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test15.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test2-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test2.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-result.txt [moved from Tests/RunCMake/cmake_path/CONCAT-wrong-path-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test3.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-result.txt [moved from Tests/RunCMake/cmake_path/CONCAT-OUTPUT_VARIABLE-no-arg-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-result.txt [moved from Tests/RunCMake/cmake_path/CONCAT-OUTPUT_VARIABLE-invalid-arg-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test4.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-result.txt [moved from Tests/RunCMake/cmake_path/COMPARE-NOT_EQUAL-wrong-path-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-result.txt [moved from Tests/RunCMake/cmake_path/COMPARE-EQUAL-wrong-path-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test5.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test6-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test6.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-result.txt [moved from Tests/RunCMake/cmake_path/CMAKE_PATH-wrong-path-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test7.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test8-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test8.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-result.txt [moved from Tests/RunCMake/cmake_path/CMAKE_PATH-unexpected-arg-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-NEW-Test9.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-result.txt [moved from Tests/RunCMake/cmake_path/CMAKE_PATH-missing-output-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test1.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-result.txt [moved from Tests/RunCMake/cmake_path/CMAKE_PATH-invalid-output-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test10.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-result.txt [moved from Tests/RunCMake/cmake_path/CMAKE_PATH-OUTPUT_VARIABLE-no-arg-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test11.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-result.txt [moved from Tests/RunCMake/ObjectLibrary/ImportNotSupported-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test12.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-result.txt [moved from Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test13.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-result.txt [moved from Tests/RunCMake/File_Configure/BadArg-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test14.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-result.txt [moved from Tests/RunCMake/ExternalProject/IncludeScope-Add_Step-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test15.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test2.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-result.txt [moved from Tests/RunCMake/ExternalProject/IncludeScope-Add-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test3.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-result.txt [moved from Tests/RunCMake/CommandLine/E_server-arg-result.txt with 100% similarity]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test4.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test5.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test6.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test7.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test8.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-OLD-Test9.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test1.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test10.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test11.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test12.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test13.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test14.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test15.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test2-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test2.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test3.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test4.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test5.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test6.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test7.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test8.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMP0118-WARN-Test9.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-Common.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-NEW.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-OLD-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-OLD.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-WARN-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-WARN-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/GenInSubdir/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0118/source.cpp.in [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test10/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test11/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test12/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test13/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test14/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test15/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test6/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test7/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test8/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0118/subdir-Common-Test9/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0119/AltExtC.zzz [new file with mode: 0644]
Tests/RunCMake/CMP0119/AltExtCXX.zzz [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-Common.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-NEW.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-OLD-build-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-OLD-build-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-OLD.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-WARN-build-result.txt [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-WARN-build-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMP0119-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/CMP0119/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/CMP0119/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/CMakeLists.txt
Tests/RunCMake/CMakePresets/CMakePresets.json.in
Tests/RunCMake/CMakePresets/GoodSpaces-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresets/GoodSpacesEq-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresets/GoodSpacesEq.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresets/ListPresets-stdout.txt
Tests/RunCMake/CMakePresets/ListPresetsHidden-stdout.txt
Tests/RunCMake/CMakePresets/ListPresetsNoSuchPreset-stdout.txt
Tests/RunCMake/CMakePresets/ListPresetsWorkingDir-stdout.txt
Tests/RunCMake/CMakePresets/NoPresetArgument-stderr.txt
Tests/RunCMake/CMakePresets/NoPresetArgumentEq-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresets/NoPresetArgumentEq-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
Tests/RunCMake/CMakePresets/validate_schema.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/CMakeLists.txt.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Good-build-build-other-check.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Good-build-macros-check.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Good-build-noEnvironment-check.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Good-build-withEnvironment-check.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Good.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Good.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/Invalid.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/ListPresets.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/TestVariable.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsBuild/check.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/CMakeLists.txt.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-indexFile.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-test-config-debug-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-test-config-release-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-test-exclude-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-test-index-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-test-indexFile-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-test-noEnvironment-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-test-showOnly-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good-withEnvironment-check.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Good.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/Invalid.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/ListPresets.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoTestsAction.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/NoTestsAction.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-result.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/PresetsUnsupported.json.in [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/CMakePresetsTest/check.cmake [new file with mode: 0644]
Tests/RunCMake/CMakeRelease/FileTable-stdout.txt [deleted file]
Tests/RunCMake/CMakeRelease/FileTable.cmake [deleted file]
Tests/RunCMake/CMakeRelease/RunCMakeTest.cmake [deleted file]
Tests/RunCMake/CPack/CPackTestHelpers.cmake
Tests/RunCMake/CPack/RunCMakeTest.cmake
Tests/RunCMake/CPack/VerifyResult.cmake
Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CPack/tests/THREADED/DEB-Prerequirements.cmake [new file with mode: 0644]
Tests/RunCMake/CPack/tests/THREADED/test.cmake
Tests/RunCMake/CPack/tests/THREADED_ALL/DEB-Prerequirements.cmake [new file with mode: 0644]
Tests/RunCMake/CPack/tests/THREADED_ALL/test.cmake
Tests/RunCMake/CTest/RunCMakeTest.cmake
Tests/RunCMake/CTest/Site.cmake [new file with mode: 0644]
Tests/RunCMake/CTestCommandLine/BadCTestTestfile-stderr.txt
Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
Tests/RunCMake/CTestCommandLine/repeat-until-fail-ctest-stderr.txt
Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-result.txt [new file with mode: 0644]
Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-result.txt [new file with mode: 0644]
Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt [new file with mode: 0644]
Tests/RunCMake/CheckModules/CMP0075-stderr.txt
Tests/RunCMake/ClangTidy/OBJC-Build-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ClangTidy/OBJC-launch-Build-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ClangTidy/OBJC-launch.cmake [new file with mode: 0644]
Tests/RunCMake/ClangTidy/OBJC.cmake [new file with mode: 0644]
Tests/RunCMake/ClangTidy/OBJCXX-Build-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ClangTidy/OBJCXX-launch-Build-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ClangTidy/OBJCXX-launch.cmake [new file with mode: 0644]
Tests/RunCMake/ClangTidy/OBJCXX.cmake [new file with mode: 0644]
Tests/RunCMake/ClangTidy/RunCMakeTest.cmake
Tests/RunCMake/ClangTidy/main.m [new file with mode: 0644]
Tests/RunCMake/ClangTidy/main.mm [moved from Tests/Server/buildsystem1/main.cpp with 96% similarity]
Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build--parallel-large-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-space-bad-number-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build--parallel-zero-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build-jobs-large-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-space-bad-number-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build-jobs-zero-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-first-stderr.txt
Tests/RunCMake/CommandLine/BuildDir--build-multiple-targets-with-clean-second-stderr.txt
Tests/RunCMake/CommandLine/C-no-arg-stderr.txt
Tests/RunCMake/CommandLine/D-no-arg-stderr.txt
Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
Tests/RunCMake/CommandLine/E_server-arg-stderr.txt [deleted file]
Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt [deleted file]
Tests/RunCMake/CommandLine/E_server-result.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/E_server-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/InvalidArg1-result.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/InvalidArg1-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/InvalidArg2-result.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/InvalidArg2-stderr.txt [new file with mode: 0644]
Tests/RunCMake/CommandLine/RunCMakeTest.cmake
Tests/RunCMake/CommandLine/U-no-arg-stderr.txt
Tests/RunCMake/CommandLine/W_bad-arg1-stderr.txt
Tests/RunCMake/CommandLine/W_bad-arg2-stderr.txt
Tests/RunCMake/CommandLine/W_bad-arg3-stderr.txt
Tests/RunCMake/CommandLine/build-no-dir-stderr.txt
Tests/RunCMake/CommandLine/cmake_depends-check.cmake
Tests/RunCMake/DependencyGraph/RunCMakeTest.cmake
Tests/RunCMake/ExportCompileCommands/Properties.cmake [new file with mode: 0644]
Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand-check.cmake [new file with mode: 0644]
Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand.cmake [new file with mode: 0644]
Tests/RunCMake/ExportCompileCommands/RunCMakeTest.cmake
Tests/RunCMake/ExportCompileCommands/expected_file.c [new file with mode: 0644]
Tests/RunCMake/ExternalData/BadArguments-stderr.txt [new file with mode: 0644]
Tests/RunCMake/ExternalData/BadArguments.cmake [new file with mode: 0644]
Tests/RunCMake/ExternalData/RunCMakeTest.cmake
Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake [new file with mode: 0644]
Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake [new file with mode: 0644]
Tests/RunCMake/ExternalProject/FetchGitTags.cmake [new file with mode: 0644]
Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/ExternalProject/IncludeScope-Add-stderr.txt [deleted file]
Tests/RunCMake/ExternalProject/IncludeScope-Add.cmake [deleted file]
Tests/RunCMake/ExternalProject/IncludeScope-Add_Step-stderr.txt [deleted file]
Tests/RunCMake/ExternalProject/IncludeScope-Add_Step.cmake [deleted file]
Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
Tests/RunCMake/FileAPI/RunCMakeTest.cmake
Tests/RunCMake/FileAPI/codemodel-v2-check.py
Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_tgt.json
Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake [new file with mode: 0644]
Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake [new file with mode: 0644]
Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake [new file with mode: 0644]
Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake [new file with mode: 0644]
Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake [new file with mode: 0644]
Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake [new file with mode: 0644]
Tests/RunCMake/FileAPI/toolchains-v1-check.py [new file with mode: 0644]
Tests/RunCMake/FileAPI/toolchains-v1.cmake [new file with mode: 0644]
Tests/RunCMake/File_Configure/AtOnly.cmake [new file with mode: 0644]
Tests/RunCMake/File_Configure/BadArg-stderr.txt [deleted file]
Tests/RunCMake/File_Configure/BadArgContent-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Configure/BadArgContent-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Configure/BadArgContent.cmake [new file with mode: 0644]
Tests/RunCMake/File_Configure/BadArgOutput-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Configure/BadArgOutput.cmake [moved from Tests/RunCMake/File_Configure/BadArg.cmake with 100% similarity]
Tests/RunCMake/File_Configure/EscapeQuotes.cmake [new file with mode: 0644]
Tests/RunCMake/File_Configure/NewLineStyle-ValidArg.cmake
Tests/RunCMake/File_Configure/RunCMakeTest.cmake
Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/CustomFilePermissions.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-Default.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-NoArg-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-NoArg.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-Unix.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/NewLineStyle-Win32.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/NoSourcePermissions.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/RunCMakeTest.cmake
Tests/RunCMake/File_Generate/SourcePermissions1-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions1.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions2-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions2.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions3-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions3.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions4-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions4.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions5-result.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt [new file with mode: 0644]
Tests/RunCMake/File_Generate/SourcePermissions5.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/UseSourcePermissions.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake [new file with mode: 0644]
Tests/RunCMake/File_Generate/VerifyContent.cmake [new file with mode: 0644]
Tests/RunCMake/FindOpenSSL/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/FindOpenSSL/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/FindOpenSSL/version-exact.cmake [new file with mode: 0644]
Tests/RunCMake/FindOpenSSL/version-range.cmake [new file with mode: 0644]
Tests/RunCMake/FindOpenSSL/version.cmake [new file with mode: 0644]
Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt [new file with mode: 0644]
Tests/RunCMake/GNUInstallDirs/GetAbs.cmake [new file with mode: 0644]
Tests/RunCMake/GNUInstallDirs/RunCMakeTest.cmake
Tests/RunCMake/GenerateExportHeader/GEH.cmake
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target-check.cmake [new file with mode: 0644]
Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target.cmake [new file with mode: 0644]
Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target-check.cmake [new file with mode: 0644]
Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target.cmake [new file with mode: 0644]
Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target-check.cmake [new file with mode: 0644]
Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target.cmake [new file with mode: 0644]
Tests/RunCMake/GoogleTest/GoogleTest-test1-stdout.txt
Tests/RunCMake/GoogleTest/GoogleTest-test2-stdout.txt
Tests/RunCMake/GoogleTest/GoogleTest.cmake
Tests/RunCMake/GoogleTest/GoogleTestDiscoveryMultiConfig.cmake
Tests/RunCMake/GoogleTest/GoogleTestDiscoveryTimeout.cmake
Tests/RunCMake/GoogleTest/GoogleTestXML.cmake
Tests/RunCMake/GoogleTest/fake_gtest.cpp
Tests/RunCMake/GoogleTest/xcode_sign_adhoc.cmake [new file with mode: 0644]
Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-NEW.cmake [new file with mode: 0644]
Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-OLD.cmake [new file with mode: 0644]
Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-common.cmake [new file with mode: 0644]
Tests/RunCMake/MSVCRuntimeTypeInfo/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/MSVCRuntimeTypeInfo/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt [deleted file]
Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake [deleted file]
Tests/RunCMake/Make/MakefileConflict.cmake [new file with mode: 0644]
Tests/RunCMake/Make/RunCMakeTest.cmake
Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/Make/TargetMessages-OFF-build-stdout.txt
Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/Make/TargetMessages-ON-build-stdout.txt
Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-stdout.txt
Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/Make/TargetMessages-VAR-ON-build-stdout.txt
Tests/RunCMake/Make/TargetMessages-validation.cmake [new file with mode: 0644]
Tests/RunCMake/Ninja/AssumedSources.cmake
Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake
Tests/RunCMake/Ninja/QtSubDir1/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/Ninja/QtSubDir2/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/Ninja/QtSubDir3/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/Ninja/RunCMakeTest.cmake
Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-clean-again-ninja-check.cmake [moved from Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-clean-ninja-check.cmake with 100% similarity]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-result.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-stderr.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-result.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-stderr.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-result.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-stderr.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-result.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-stderr.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-in-release-graph-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/Qt5.cmake
Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
Tests/RunCMake/NinjaMultiConfig/Simple-targets-debug-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/Simple-targets-default-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/Simple-targets-release-ninja-stdout.txt [new file with mode: 0644]
Tests/RunCMake/NinjaMultiConfig/echo.c [new file with mode: 0644]
Tests/RunCMake/ObjectLibrary/ImportMultiArch-check.cmake [new file with mode: 0644]
Tests/RunCMake/ObjectLibrary/ImportMultiArch.cmake [new file with mode: 0644]
Tests/RunCMake/ObjectLibrary/ImportNotSupported-stderr.txt [deleted file]
Tests/RunCMake/ObjectLibrary/ImportNotSupported.cmake [deleted file]
Tests/RunCMake/ObjectLibrary/LinkObjLHSShared.cmake
Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
Tests/RunCMake/ParseImplicitLinkInfo/ParseImplicitLinkInfo.cmake
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-GNU-7.3.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-Intel-18.0.0.20170811.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-PGI-18.10.1.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-XL-12.1.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-C-XL-16.1.0.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CUDA-NVIDIA-10.1.168-CLANG.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CUDA-NVIDIA-10.1.168-XLClang-v.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CUDA-NVIDIA-9.2.148-GCC.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-GNU-7.3.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-Intel-18.0.0.20170811.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-PGI-18.10.1.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-XL-12.1.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-XL-16.1.0.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-GNU-7.3.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-PGI-18.10.1.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-XL-14.1.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-C-PGI-18.10.1.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-C-XL-12.1.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-CXX-PGI-18.10.1.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-CXX-XL-12.1.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc-Fortran-PGI-18.10.1.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux_nostdinc_i-C-XL-12.1.0.output
Tests/RunCMake/ParseImplicitLinkInfo/results/linux_pgf77-Fortran-PGI-18.10.1.output
Tests/RunCMake/Policy/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidMaxVersion-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidMaxVersion-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidMaxVersion.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidVersion-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidVersion-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/InvalidVersion.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/MinVersionLargerThanMax-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/MinVersionLargerThanMax.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/TooManyVersionsGiven-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/TooManyVersionsGiven-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/TooManyVersionsGiven.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/VersionLowerThan2_4-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/VersionLowerThan2_4-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/VersionLowerThan2_4.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/VersionNotGiven-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/VersionNotGiven-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/VersionNotGiven.cmake [new file with mode: 0644]
Tests/RunCMake/Policy/VeryHighVersion-result.txt [new file with mode: 0644]
Tests/RunCMake/Policy/VeryHighVersion-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Policy/VeryHighVersion.cmake [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
Tests/RunCMake/PrecompileHeaders/include/cxx_pch.h [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/no_pch.c [new file with mode: 0644]
Tests/RunCMake/PrecompileHeaders/use_pch.cxx [new file with mode: 0644]
Tests/RunCMake/RunCMake.cmake
Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt
Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt
Tests/RunCMake/Syntax/ImproperNesting-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/ImproperNesting-stderr.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/ImproperNesting.cmake [new file with mode: 0644]
Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt
Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt
Tests/RunCMake/Syntax/NameWithSpaces-stderr.txt
Tests/RunCMake/Syntax/NameWithTabs-stderr.txt
Tests/RunCMake/Syntax/Override.cmake [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideBreak-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideContinue-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideElse-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideElseIf-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideEndForeach-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideEndFunction-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideEndIf-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideEndMacro-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideEndWhile-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideForeach-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideFunction-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideIf-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideMacro-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideReturn-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/OverrideWhile-result.txt [new file with mode: 0644]
Tests/RunCMake/Syntax/ParenInENV-stderr.txt
Tests/RunCMake/Syntax/RunCMakeTest.cmake
Tests/RunCMake/Syntax/UnterminatedBrace0-stderr.txt
Tests/RunCMake/Syntax/UnterminatedBrace1-stderr.txt
Tests/RunCMake/TargetObjects/CMakeLists.txt
Tests/RunCMake/TargetObjects/RunCMakeTest.cmake
Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-result.txt [new file with mode: 0644]
Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-stderr.txt [new file with mode: 0644]
Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion.cmake [new file with mode: 0644]
Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
Tests/RunCMake/TargetSources/AddCustomTargetCheckProperty.cmake [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetGenx.cmake [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-result.txt [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-stderr.txt [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources.cmake [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetPrivateSources.cmake [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-result.txt [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-stderr.txt [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetPublicSources.cmake [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetSources-result.txt [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetSources-stderr.txt [new file with mode: 0644]
Tests/RunCMake/TargetSources/AddCustomTargetSources.cmake [new file with mode: 0644]
Tests/RunCMake/TargetSources/RunCMakeTest.cmake
Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt [new file with mode: 0644]
Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake [new file with mode: 0644]
Tests/RunCMake/ToolchainFile/CheckLanguage.cmake [new file with mode: 0644]
Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake
Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/deps-unix.d [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/deps-unix.d.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/deps-windows.d [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/deps-windows.d.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/empty.d [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/empty.d.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/empty.tlog.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/gccdepfile.cmake [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/invalid-gcc-result.txt [moved from Tests/RunCMake/CommandLine/E_server-pipe-result.txt with 100% similarity]
Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/invalid.d [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/noexist.d.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/noexist.tlog.txt [new file with mode: 0644]
Tests/RunCMake/TransformDepfile/vstlog.cmake [new file with mode: 0644]
Tests/RunCMake/UnityBuild/RunCMakeTest.cmake
Tests/RunCMake/UnityBuild/f.cxx [new file with mode: 0644]
Tests/RunCMake/UnityBuild/unitybuild_anon_ns-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake [new file with mode: 0644]
Tests/RunCMake/UnityBuild/unitybuild_anon_ns_group_mode.cmake [new file with mode: 0644]
Tests/RunCMake/UnityBuild/unitybuild_anon_ns_no_unity_build.cmake [new file with mode: 0644]
Tests/RunCMake/UnityBuild/unitybuild_anon_ns_test_files.cmake [new file with mode: 0644]
Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake [new file with mode: 0644]
Tests/RunCMake/VS10Project/CustomCommandGenex.cmake [new file with mode: 0644]
Tests/RunCMake/VS10Project/RunCMakeTest.cmake
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-result.txt [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-stderr.txt [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct.cmake [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-result.txt [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-stderr.txt [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW.cmake [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-Direct.cmake [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD.cmake [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct-stderr.txt [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct.cmake [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-stderr.txt [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN.cmake [new file with mode: 0644]
Tests/RunCMake/WriteCompilerDetectionHeader/RunCMakeTest.cmake
Tests/RunCMake/XcodeProject-Embed/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff-check.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-check.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-build-check.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-check.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/ExternalFramework.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/func.m [new file with mode: 0644]
Tests/RunCMake/XcodeProject-Embed/main.m [new file with mode: 0644]
Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
Tests/RunCMake/XcodeProject/SearchPaths-check.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject/SearchPaths.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject/XcodeObjectLibsInTwoProjects.cmake [new file with mode: 0644]
Tests/RunCMake/XcodeProject/subproject_two_object_libs/CMakeLists.txt [new file with mode: 0644]
Tests/RunCMake/XcodeProject/subproject_two_object_libs/dummy.cpp [new file with mode: 0644]
Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt
Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt
Tests/RunCMake/add_custom_command/BadByproduct.cmake
Tests/RunCMake/add_custom_command/BadCommand-result.txt [new file with mode: 0644]
Tests/RunCMake/add_custom_command/BadCommand-stderr.txt [new file with mode: 0644]
Tests/RunCMake/add_custom_command/BadCommand.cmake [new file with mode: 0644]
Tests/RunCMake/add_custom_command/BadOutput-stderr.txt
Tests/RunCMake/add_custom_command/BadOutput.cmake
Tests/RunCMake/add_custom_command/RunCMakeTest.cmake
Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt
Tests/RunCMake/add_custom_target/BadByproduct.cmake
Tests/RunCMake/add_custom_target/BadCommand-result.txt [new file with mode: 0644]
Tests/RunCMake/add_custom_target/BadCommand-stderr.txt [new file with mode: 0644]
Tests/RunCMake/add_custom_target/BadCommand.cmake [new file with mode: 0644]
Tests/RunCMake/add_custom_target/RunCMakeTest.cmake
Tests/RunCMake/add_library/CMP0073-stderr.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-invalid-arg-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-no-arg-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/APPEND_STRING-wrong-path-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/APPEND_STRING.cmake [moved from Tests/RunCMake/cmake_path/CONCAT.cmake with 73% similarity]
Tests/RunCMake/cmake_path/COMPARE.cmake
Tests/RunCMake/cmake_path/GET-RELATIVE_PART-invalid-output-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/GET-RELATIVE_PART-missing-output-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/GET-RELATIVE_PART-unexpected-arg-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/GET-RELATIVE_PART-wrong-path-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/GET.cmake
Tests/RunCMake/cmake_path/HASH.cmake
Tests/RunCMake/cmake_path/HAS_ITEM.cmake
Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-invalid-output-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-missing-output-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-unexpected-arg-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-wrong-path-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/IS_PREFIX.cmake
Tests/RunCMake/cmake_path/PROXIMATE_PATH.cmake [deleted file]
Tests/RunCMake/cmake_path/RunCMakeTest.cmake
Tests/RunCMake/cmake_path/SET-missing-output-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/SET-unexpected-arg-result.txt [new file with mode: 0644]
Tests/RunCMake/cmake_path/SET.cmake [moved from Tests/RunCMake/cmake_path/CMAKE_PATH.cmake with 65% similarity]
Tests/RunCMake/configure_file/RunCMakeTest.cmake
Tests/RunCMake/configure_file/SourcePermissions-result.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissions-stderr.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissions.cmake [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt [new file with mode: 0644]
Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake [new file with mode: 0644]
Tests/RunCMake/configure_file/UseSourcePermissions.cmake [new file with mode: 0644]
Tests/RunCMake/configure_file/sourcefile.txt [new file with mode: 0644]
Tests/RunCMake/ctest_submit/CTestConfig.cmake.in
Tests/RunCMake/file-RPATH/Common.cmake [moved from Tests/CMakeTests/ELFTest.cmake.in with 89% similarity]
Tests/RunCMake/file-RPATH/ELF.cmake [new file with mode: 0644]
Tests/RunCMake/file-RPATH/ELF/elf32lsb.bin [moved from Tests/CMakeTests/ELF/elf32lsb.bin with 100% similarity, mode: 0755]
Tests/RunCMake/file-RPATH/ELF/elf32msb.bin [moved from Tests/CMakeTests/ELF/elf32msb.bin with 100% similarity, mode: 0755]
Tests/RunCMake/file-RPATH/ELF/elf64lsb.bin [moved from Tests/CMakeTests/ELF/elf64lsb.bin with 100% similarity, mode: 0755]
Tests/RunCMake/file-RPATH/ELF/elf64msb.bin [moved from Tests/CMakeTests/ELF/elf64msb.bin with 100% similarity, mode: 0755]
Tests/RunCMake/file-RPATH/RunCMakeTest.cmake [new file with mode: 0644]
Tests/RunCMake/file-RPATH/XCOFF.cmake [new file with mode: 0644]
Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin [new file with mode: 0644]
Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin [new file with mode: 0644]
Tests/RunCMake/get_property/RunCMakeTest.cmake
Tests/RunCMake/get_property/get_directory_property_empty-result.txt [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_empty-stderr.txt [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_empty.cmake [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_missing-result.txt [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_missing-stderr.txt [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_missing.cmake [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_missingWithDir-result.txt [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_missingWithDir-stderr.txt [new file with mode: 0644]
Tests/RunCMake/get_property/get_directory_property_missingWithDir.cmake [new file with mode: 0644]
Tests/RunCMake/if/duplicate-deep-else-stderr.txt
Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt
Tests/RunCMake/if/duplicate-else-stderr.txt
Tests/RunCMake/if/misplaced-elseif-stderr.txt
Tests/RunCMake/include/ExportExportInclude-stderr.txt
Tests/RunCMake/include/IncludeIsDirectory-result.txt [new file with mode: 0644]
Tests/RunCMake/include/IncludeIsDirectory-stderr.txt [new file with mode: 0644]
Tests/RunCMake/include/IncludeIsDirectory.cmake [new file with mode: 0644]
Tests/RunCMake/include/IncludeMalformed-result.txt [new file with mode: 0644]
Tests/RunCMake/include/IncludeMalformed-stderr.txt [new file with mode: 0644]
Tests/RunCMake/include/IncludeMalformed.cmake [new file with mode: 0644]
Tests/RunCMake/include/RunCMakeTest.cmake
Tests/RunCMake/include/malformedInclude.cmake [new file with mode: 0644]
Tests/RunCMake/install/FILES-RENAME-all-check.cmake [new file with mode: 0644]
Tests/RunCMake/install/FILES-RENAME-bad-result.txt [new file with mode: 0644]
Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt [new file with mode: 0644]
Tests/RunCMake/install/FILES-RENAME-bad.cmake [new file with mode: 0644]
Tests/RunCMake/install/FILES-RENAME.cmake [new file with mode: 0644]
Tests/RunCMake/install/RunCMakeTest.cmake
Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake
Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake [new file with mode: 0644]
Tests/RunCMake/list/RunCMakeTest.cmake
Tests/RunCMake/math/MATH-InvalidExpression-stderr.txt
Tests/RunCMake/pseudo_llvm-rc.c [new file with mode: 0644]
Tests/RunCMake/separate_arguments/ProgramCommand.cmake
Tests/RunCMake/separate_arguments/ProgramCommandWithSeparateArgs.cmake
Tests/RunCMake/target_include_directories/RunCMakeTest.cmake
Tests/RunCMake/target_include_directories/include_after.cmake [new file with mode: 0644]
Tests/RunCMake/target_include_directories/include_before.cmake [new file with mode: 0644]
Tests/RunCMake/target_include_directories/include_default.cmake [new file with mode: 0644]
Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/RunCMakeTest.cmake
Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/func.cxx
Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/genex.cmake
Tests/RunCMake/target_link_libraries-LINK_LANGUAGE/main.c
Tests/RunCMake/try_run/RunCMakeTest.cmake
Tests/RunCMake/try_run/WorkingDirArg.cmake [new file with mode: 0644]
Tests/RunCMake/while/EndAlone-stderr.txt
Tests/RunCMake/while/EndAloneArgs-stderr.txt
Tests/RunCMake/while/EndMissing-stderr.txt
Tests/RunCMake/while/MissingArgument-stderr.txt
Tests/RunCMake/while/MissingArgument.cmake
Tests/Server/CMakeLists.txt [deleted file]
Tests/Server/buildsystem1/CMakeLists.txt [deleted file]
Tests/Server/buildsystem1/subdir/CMakeLists.txt [deleted file]
Tests/Server/cmakelib.py [deleted file]
Tests/Server/server-test.py [deleted file]
Tests/Server/tc_buildsystem1.json [deleted file]
Tests/Server/tc_cache.json [deleted file]
Tests/Server/tc_globalSettings.json [deleted file]
Tests/Server/tc_handshake.json [deleted file]
Tests/SetLang/CMakeLists.txt
Tests/SetLang/bar.c
Tests/SetLang/zoom.zzz [new file with mode: 0644]
Tests/UseSWIG/BasicPerl/CMakeLists.txt
Tests/UseSWIG/BasicPython/CMakeLists.txt
Tests/UseSWIG/CMakeLists.txt
Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt
Tests/VSMidl/CMakeLists.txt
Tests/VSMidl/src/CMakeLists.txt
Tests/VSWinStorePhone/CMakeLists.txt
Utilities/Doxygen/CMakeLists.txt
Utilities/Release/README.rst
Utilities/Release/files-sign.bash [deleted file]
Utilities/Release/files-v1.json.in [deleted file]
Utilities/Release/files-v1.rst [deleted file]
Utilities/Release/files.bash [deleted file]
Utilities/Release/linux/aarch64/Dockerfile
Utilities/Release/linux/aarch64/cache.txt
Utilities/Release/linux/x86_64/Dockerfile
Utilities/Release/linux/x86_64/cache.txt
Utilities/Release/win/x86/cache-i386.txt
Utilities/Release/win/x86/cache-x86_64.txt
Utilities/Scripts/regenerate-parsers.bash
Utilities/Scripts/update-curl.bash
Utilities/Sphinx/CMakeLists.txt
Utilities/Sphinx/cmake.py
Utilities/Sphinx/conf.py.in
Utilities/Sphinx/create_identifiers.py
Utilities/Sphinx/static/cmake.css
Utilities/cmbzip2/CMakeLists.txt
Utilities/cmcurl/CMake/CMakeConfigurableFile.in
Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
Utilities/cmcurl/CMake/CurlTests.c
Utilities/cmcurl/CMake/FindBearSSL.cmake
Utilities/cmcurl/CMake/FindBrotli.cmake
Utilities/cmcurl/CMake/FindCARES.cmake
Utilities/cmcurl/CMake/FindGSS.cmake
Utilities/cmcurl/CMake/FindLibSSH2.cmake
Utilities/cmcurl/CMake/FindMbedTLS.cmake
Utilities/cmcurl/CMake/FindNGHTTP2.cmake
Utilities/cmcurl/CMake/FindNGHTTP3.cmake
Utilities/cmcurl/CMake/FindNGTCP2.cmake
Utilities/cmcurl/CMake/FindNSS.cmake
Utilities/cmcurl/CMake/FindQUICHE.cmake
Utilities/cmcurl/CMake/FindWolfSSL.cmake
Utilities/cmcurl/CMake/FindZstd.cmake
Utilities/cmcurl/CMake/Macros.cmake
Utilities/cmcurl/CMake/OtherTests.cmake
Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
Utilities/cmcurl/CMake/Utilities.cmake
Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
Utilities/cmcurl/CMake/curl-config.cmake.in
Utilities/cmcurl/CMakeLists.txt
Utilities/cmcurl/COPYING
Utilities/cmcurl/include/curl/curl.h
Utilities/cmcurl/include/curl/curlver.h
Utilities/cmcurl/include/curl/easy.h
Utilities/cmcurl/include/curl/mprintf.h
Utilities/cmcurl/include/curl/multi.h
Utilities/cmcurl/include/curl/options.h [new file with mode: 0644]
Utilities/cmcurl/include/curl/stdcheaders.h
Utilities/cmcurl/include/curl/system.h
Utilities/cmcurl/include/curl/typecheck-gcc.h
Utilities/cmcurl/include/curl/urlapi.h
Utilities/cmcurl/lib/CMakeLists.txt
Utilities/cmcurl/lib/Makefile.inc
Utilities/cmcurl/lib/altsvc.c
Utilities/cmcurl/lib/altsvc.h
Utilities/cmcurl/lib/amigaos.c
Utilities/cmcurl/lib/amigaos.h
Utilities/cmcurl/lib/arpa_telnet.h
Utilities/cmcurl/lib/asyn-ares.c
Utilities/cmcurl/lib/asyn-thread.c
Utilities/cmcurl/lib/asyn.h
Utilities/cmcurl/lib/base64.c
Utilities/cmcurl/lib/c-hyper.c [new file with mode: 0644]
Utilities/cmcurl/lib/c-hyper.h [new file with mode: 0644]
Utilities/cmcurl/lib/conncache.c
Utilities/cmcurl/lib/conncache.h
Utilities/cmcurl/lib/connect.c
Utilities/cmcurl/lib/connect.h
Utilities/cmcurl/lib/content_encoding.c
Utilities/cmcurl/lib/content_encoding.h
Utilities/cmcurl/lib/cookie.c
Utilities/cmcurl/lib/cookie.h
Utilities/cmcurl/lib/curl_addrinfo.c
Utilities/cmcurl/lib/curl_addrinfo.h
Utilities/cmcurl/lib/curl_base64.h
Utilities/cmcurl/lib/curl_config.h.cmake
Utilities/cmcurl/lib/curl_ctype.c
Utilities/cmcurl/lib/curl_ctype.h
Utilities/cmcurl/lib/curl_des.c
Utilities/cmcurl/lib/curl_des.h
Utilities/cmcurl/lib/curl_endian.c
Utilities/cmcurl/lib/curl_endian.h
Utilities/cmcurl/lib/curl_fnmatch.c
Utilities/cmcurl/lib/curl_fnmatch.h
Utilities/cmcurl/lib/curl_get_line.c
Utilities/cmcurl/lib/curl_get_line.h
Utilities/cmcurl/lib/curl_gethostname.c
Utilities/cmcurl/lib/curl_gethostname.h
Utilities/cmcurl/lib/curl_gssapi.c
Utilities/cmcurl/lib/curl_gssapi.h
Utilities/cmcurl/lib/curl_hmac.h
Utilities/cmcurl/lib/curl_krb5.h [moved from Utilities/cmcurl/lib/curl_sec.h with 76% similarity]
Utilities/cmcurl/lib/curl_ldap.h
Utilities/cmcurl/lib/curl_md4.h
Utilities/cmcurl/lib/curl_md5.h
Utilities/cmcurl/lib/curl_memory.h
Utilities/cmcurl/lib/curl_memrchr.c
Utilities/cmcurl/lib/curl_memrchr.h
Utilities/cmcurl/lib/curl_multibyte.c
Utilities/cmcurl/lib/curl_multibyte.h
Utilities/cmcurl/lib/curl_ntlm_core.c
Utilities/cmcurl/lib/curl_ntlm_core.h
Utilities/cmcurl/lib/curl_ntlm_wb.c
Utilities/cmcurl/lib/curl_ntlm_wb.h
Utilities/cmcurl/lib/curl_path.c
Utilities/cmcurl/lib/curl_path.h
Utilities/cmcurl/lib/curl_printf.h
Utilities/cmcurl/lib/curl_range.c
Utilities/cmcurl/lib/curl_range.h
Utilities/cmcurl/lib/curl_rtmp.c
Utilities/cmcurl/lib/curl_rtmp.h
Utilities/cmcurl/lib/curl_sasl.c
Utilities/cmcurl/lib/curl_sasl.h
Utilities/cmcurl/lib/curl_setup.h
Utilities/cmcurl/lib/curl_setup_once.h
Utilities/cmcurl/lib/curl_sha256.h
Utilities/cmcurl/lib/curl_sspi.c
Utilities/cmcurl/lib/curl_sspi.h
Utilities/cmcurl/lib/curl_threads.c
Utilities/cmcurl/lib/curl_threads.h
Utilities/cmcurl/lib/curlx.h
Utilities/cmcurl/lib/dict.c
Utilities/cmcurl/lib/dict.h
Utilities/cmcurl/lib/doh.c
Utilities/cmcurl/lib/doh.h
Utilities/cmcurl/lib/dotdot.c
Utilities/cmcurl/lib/dotdot.h
Utilities/cmcurl/lib/dynbuf.c
Utilities/cmcurl/lib/dynbuf.h
Utilities/cmcurl/lib/easy.c
Utilities/cmcurl/lib/easygetopt.c [new file with mode: 0644]
Utilities/cmcurl/lib/easyif.h
Utilities/cmcurl/lib/easyoptions.c [new file with mode: 0644]
Utilities/cmcurl/lib/easyoptions.h [new file with mode: 0644]
Utilities/cmcurl/lib/escape.c
Utilities/cmcurl/lib/escape.h
Utilities/cmcurl/lib/file.c
Utilities/cmcurl/lib/file.h
Utilities/cmcurl/lib/fileinfo.c
Utilities/cmcurl/lib/fileinfo.h
Utilities/cmcurl/lib/formdata.c
Utilities/cmcurl/lib/formdata.h
Utilities/cmcurl/lib/ftp.c
Utilities/cmcurl/lib/ftp.h
Utilities/cmcurl/lib/ftplistparser.c
Utilities/cmcurl/lib/ftplistparser.h
Utilities/cmcurl/lib/getenv.c
Utilities/cmcurl/lib/getinfo.c
Utilities/cmcurl/lib/getinfo.h
Utilities/cmcurl/lib/gopher.c
Utilities/cmcurl/lib/gopher.h
Utilities/cmcurl/lib/hash.c
Utilities/cmcurl/lib/hash.h
Utilities/cmcurl/lib/hmac.c
Utilities/cmcurl/lib/hostasyn.c
Utilities/cmcurl/lib/hostcheck.c
Utilities/cmcurl/lib/hostcheck.h
Utilities/cmcurl/lib/hostip.c
Utilities/cmcurl/lib/hostip.h
Utilities/cmcurl/lib/hostip4.c
Utilities/cmcurl/lib/hostip6.c
Utilities/cmcurl/lib/hostsyn.c
Utilities/cmcurl/lib/hsts.c [new file with mode: 0644]
Utilities/cmcurl/lib/hsts.h [new file with mode: 0644]
Utilities/cmcurl/lib/http.c
Utilities/cmcurl/lib/http.h
Utilities/cmcurl/lib/http2.c
Utilities/cmcurl/lib/http2.h
Utilities/cmcurl/lib/http_aws_sigv4.c [new file with mode: 0644]
Utilities/cmcurl/lib/http_aws_sigv4.h [new file with mode: 0644]
Utilities/cmcurl/lib/http_chunks.c
Utilities/cmcurl/lib/http_chunks.h
Utilities/cmcurl/lib/http_digest.c
Utilities/cmcurl/lib/http_digest.h
Utilities/cmcurl/lib/http_negotiate.c
Utilities/cmcurl/lib/http_negotiate.h
Utilities/cmcurl/lib/http_ntlm.c
Utilities/cmcurl/lib/http_ntlm.h
Utilities/cmcurl/lib/http_proxy.c
Utilities/cmcurl/lib/http_proxy.h
Utilities/cmcurl/lib/idn_win32.c
Utilities/cmcurl/lib/if2ip.c
Utilities/cmcurl/lib/if2ip.h
Utilities/cmcurl/lib/imap.c
Utilities/cmcurl/lib/imap.h
Utilities/cmcurl/lib/inet_ntop.h
Utilities/cmcurl/lib/inet_pton.c
Utilities/cmcurl/lib/inet_pton.h
Utilities/cmcurl/lib/krb5.c
Utilities/cmcurl/lib/ldap.c
Utilities/cmcurl/lib/libcurl.rc
Utilities/cmcurl/lib/llist.c
Utilities/cmcurl/lib/llist.h
Utilities/cmcurl/lib/md4.c
Utilities/cmcurl/lib/md5.c
Utilities/cmcurl/lib/memdebug.c
Utilities/cmcurl/lib/memdebug.h
Utilities/cmcurl/lib/mime.c
Utilities/cmcurl/lib/mime.h
Utilities/cmcurl/lib/mprintf.c
Utilities/cmcurl/lib/mqtt.c
Utilities/cmcurl/lib/mqtt.h
Utilities/cmcurl/lib/multi.c
Utilities/cmcurl/lib/multihandle.h
Utilities/cmcurl/lib/multiif.h
Utilities/cmcurl/lib/netrc.c
Utilities/cmcurl/lib/netrc.h
Utilities/cmcurl/lib/non-ascii.c
Utilities/cmcurl/lib/non-ascii.h
Utilities/cmcurl/lib/nonblock.c
Utilities/cmcurl/lib/nonblock.h
Utilities/cmcurl/lib/nwlib.c
Utilities/cmcurl/lib/nwos.c
Utilities/cmcurl/lib/openldap.c
Utilities/cmcurl/lib/parsedate.c
Utilities/cmcurl/lib/parsedate.h
Utilities/cmcurl/lib/pingpong.c
Utilities/cmcurl/lib/pingpong.h
Utilities/cmcurl/lib/pop3.c
Utilities/cmcurl/lib/pop3.h
Utilities/cmcurl/lib/progress.c
Utilities/cmcurl/lib/progress.h
Utilities/cmcurl/lib/psl.c
Utilities/cmcurl/lib/psl.h
Utilities/cmcurl/lib/quic.h
Utilities/cmcurl/lib/rand.c
Utilities/cmcurl/lib/rand.h
Utilities/cmcurl/lib/rename.c
Utilities/cmcurl/lib/rename.h
Utilities/cmcurl/lib/rtsp.c
Utilities/cmcurl/lib/rtsp.h
Utilities/cmcurl/lib/security.c [deleted file]
Utilities/cmcurl/lib/select.c
Utilities/cmcurl/lib/select.h
Utilities/cmcurl/lib/sendf.c
Utilities/cmcurl/lib/sendf.h
Utilities/cmcurl/lib/setopt.c
Utilities/cmcurl/lib/setopt.h
Utilities/cmcurl/lib/setup-os400.h
Utilities/cmcurl/lib/setup-vms.h
Utilities/cmcurl/lib/setup-win32.h
Utilities/cmcurl/lib/sha256.c
Utilities/cmcurl/lib/share.c
Utilities/cmcurl/lib/share.h
Utilities/cmcurl/lib/sigpipe.h
Utilities/cmcurl/lib/slist.c
Utilities/cmcurl/lib/slist.h
Utilities/cmcurl/lib/smb.c
Utilities/cmcurl/lib/smb.h
Utilities/cmcurl/lib/smtp.c
Utilities/cmcurl/lib/smtp.h
Utilities/cmcurl/lib/sockaddr.h
Utilities/cmcurl/lib/socketpair.c
Utilities/cmcurl/lib/socketpair.h
Utilities/cmcurl/lib/socks.c
Utilities/cmcurl/lib/socks.h
Utilities/cmcurl/lib/socks_gssapi.c
Utilities/cmcurl/lib/socks_sspi.c
Utilities/cmcurl/lib/speedcheck.c
Utilities/cmcurl/lib/speedcheck.h
Utilities/cmcurl/lib/splay.c
Utilities/cmcurl/lib/splay.h
Utilities/cmcurl/lib/strcase.c
Utilities/cmcurl/lib/strcase.h
Utilities/cmcurl/lib/strdup.c
Utilities/cmcurl/lib/strdup.h
Utilities/cmcurl/lib/strerror.c
Utilities/cmcurl/lib/strerror.h
Utilities/cmcurl/lib/strtok.c
Utilities/cmcurl/lib/strtok.h
Utilities/cmcurl/lib/strtoofft.c
Utilities/cmcurl/lib/strtoofft.h
Utilities/cmcurl/lib/system_win32.c
Utilities/cmcurl/lib/system_win32.h
Utilities/cmcurl/lib/telnet.c
Utilities/cmcurl/lib/telnet.h
Utilities/cmcurl/lib/tftp.c
Utilities/cmcurl/lib/tftp.h
Utilities/cmcurl/lib/timeval.c
Utilities/cmcurl/lib/timeval.h
Utilities/cmcurl/lib/transfer.c
Utilities/cmcurl/lib/transfer.h
Utilities/cmcurl/lib/url.c
Utilities/cmcurl/lib/url.h
Utilities/cmcurl/lib/urlapi-int.h
Utilities/cmcurl/lib/urlapi.c
Utilities/cmcurl/lib/urldata.h
Utilities/cmcurl/lib/vauth/cleartext.c
Utilities/cmcurl/lib/vauth/cram.c
Utilities/cmcurl/lib/vauth/digest.c
Utilities/cmcurl/lib/vauth/digest.h
Utilities/cmcurl/lib/vauth/digest_sspi.c
Utilities/cmcurl/lib/vauth/krb5_gssapi.c
Utilities/cmcurl/lib/vauth/krb5_sspi.c
Utilities/cmcurl/lib/vauth/ntlm.c
Utilities/cmcurl/lib/vauth/ntlm.h
Utilities/cmcurl/lib/vauth/ntlm_sspi.c
Utilities/cmcurl/lib/vauth/oauth2.c
Utilities/cmcurl/lib/vauth/spnego_gssapi.c
Utilities/cmcurl/lib/vauth/spnego_sspi.c
Utilities/cmcurl/lib/vauth/vauth.c
Utilities/cmcurl/lib/vauth/vauth.h
Utilities/cmcurl/lib/version.c
Utilities/cmcurl/lib/version_win32.c
Utilities/cmcurl/lib/version_win32.h
Utilities/cmcurl/lib/vquic/ngtcp2.c
Utilities/cmcurl/lib/vquic/ngtcp2.h
Utilities/cmcurl/lib/vquic/quiche.c
Utilities/cmcurl/lib/vquic/quiche.h
Utilities/cmcurl/lib/vquic/vquic.c
Utilities/cmcurl/lib/vquic/vquic.h
Utilities/cmcurl/lib/vssh/libssh.c
Utilities/cmcurl/lib/vssh/libssh2.c
Utilities/cmcurl/lib/vssh/ssh.h
Utilities/cmcurl/lib/vssh/wolfssh.c
Utilities/cmcurl/lib/vssh/wolfssh.h
Utilities/cmcurl/lib/vtls/bearssl.c
Utilities/cmcurl/lib/vtls/bearssl.h
Utilities/cmcurl/lib/vtls/gskit.c
Utilities/cmcurl/lib/vtls/gskit.h
Utilities/cmcurl/lib/vtls/gtls.c
Utilities/cmcurl/lib/vtls/gtls.h
Utilities/cmcurl/lib/vtls/keylog.c
Utilities/cmcurl/lib/vtls/keylog.h
Utilities/cmcurl/lib/vtls/mbedtls.c
Utilities/cmcurl/lib/vtls/mbedtls.h
Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h
Utilities/cmcurl/lib/vtls/mesalink.c
Utilities/cmcurl/lib/vtls/mesalink.h
Utilities/cmcurl/lib/vtls/nss.c
Utilities/cmcurl/lib/vtls/nssg.h
Utilities/cmcurl/lib/vtls/openssl.c
Utilities/cmcurl/lib/vtls/openssl.h
Utilities/cmcurl/lib/vtls/schannel.c
Utilities/cmcurl/lib/vtls/schannel.h
Utilities/cmcurl/lib/vtls/schannel_verify.c
Utilities/cmcurl/lib/vtls/sectransp.c
Utilities/cmcurl/lib/vtls/sectransp.h
Utilities/cmcurl/lib/vtls/vtls.c
Utilities/cmcurl/lib/vtls/vtls.h
Utilities/cmcurl/lib/vtls/wolfssl.c
Utilities/cmcurl/lib/vtls/wolfssl.h
Utilities/cmcurl/lib/warnless.c
Utilities/cmcurl/lib/warnless.h
Utilities/cmcurl/lib/wildcard.c
Utilities/cmcurl/lib/wildcard.h
Utilities/cmcurl/lib/x509asn1.c
Utilities/cmcurl/lib/x509asn1.h
Utilities/cmexpat/CMakeLists.txt
Utilities/cmjsoncpp/CMakeLists.txt
Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
Utilities/cmjsoncpp/src/lib_json/json_value.cpp
Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
Utilities/cmlibarchive/CMakeLists.txt
Utilities/cmlibarchive/libarchive/archive_random.c
Utilities/cmliblzma/CMakeLists.txt
Utilities/cmlibrhash/CMakeLists.txt
Utilities/cmlibuv/CMakeLists.txt
Utilities/cmnghttp2/CMakeLists.txt
Utilities/cmzlib/CMakeLists.txt
Utilities/cmzstd/CMakeLists.txt
Utilities/std/cm/optional
bootstrap

index 11e1726..5e513fb 100644 (file)
@@ -4,9 +4,6 @@ bugprone-*,\
 -bugprone-macro-parentheses,\
 -bugprone-misplaced-widening-cast,\
 -bugprone-narrowing-conversions,\
--bugprone-reserved-identifier,\
--bugprone-signed-char-misuse,\
--bugprone-suspicious-include,\
 -bugprone-too-small-loop-variable,\
 google-readability-casting,\
 misc-*,\
@@ -20,8 +17,6 @@ modernize-*,\
 -modernize-use-trailing-return-type,\
 -modernize-use-transparent-functors,\
 performance-*,\
--performance-no-automatic-move,\
--performance-trivially-destructible,\
 readability-*,\
 -readability-convert-member-functions-to-static,\
 -readability-function-size,\
@@ -29,15 +24,9 @@ readability-*,\
 -readability-implicit-bool-conversion,\
 -readability-inconsistent-declaration-parameter-name,\
 -readability-magic-numbers,\
--readability-make-member-function-const,\
 -readability-named-parameter,\
--readability-qualified-auto,\
--readability-redundant-access-specifiers,\
 -readability-redundant-declaration,\
--readability-redundant-string-init,\
--readability-simplify-boolean-expr,\
 -readability-uppercase-literal-suffix,\
--readability-use-anyofallof,\
 "
 HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$'
 CheckOptions:
index caaf0d5..ddc7b40 100644 (file)
@@ -27,6 +27,9 @@
 ;; cmake-command-help Written by James Bigler
 ;;
 
+(require 'rst)
+(require 'rx)
+
 (defcustom cmake-mode-cmake-executable "cmake"
   "*The name of the cmake executable.
 
@@ -188,6 +191,61 @@ the indentation.  Otherwise it retains the same position on the line"
     )
   )
 
+
+;------------------------------------------------------------------------------
+
+;;
+;; Navigation / marking by function or macro
+;;
+
+(defconst cmake--regex-defun-start
+  (rx line-start
+      (zero-or-more space)
+      (or "function" "macro")
+      (zero-or-more space)
+      "("))
+
+(defconst cmake--regex-defun-end
+  (rx line-start
+      (zero-or-more space)
+      "end"
+      (or "function" "macro")
+      (zero-or-more space)
+      "(" (zero-or-more (not-char ")")) ")"))
+
+(defun cmake-beginning-of-defun ()
+  "Move backward to the beginning of a CMake function or macro.
+
+Return t unless search stops due to beginning of buffer."
+  (interactive)
+  (when (not (region-active-p))
+    (push-mark))
+  (let ((case-fold-search t))
+    (when (re-search-backward cmake--regex-defun-start nil 'move)
+      t)))
+
+(defun cmake-end-of-defun ()
+  "Move forward to the end of a CMake function or macro.
+
+Return t unless search stops due to end of buffer."
+  (interactive)
+  (when (not (region-active-p))
+    (push-mark))
+  (let ((case-fold-search t))
+    (when (re-search-forward cmake--regex-defun-end nil 'move)
+      (forward-line)
+      t)))
+
+(defun cmake-mark-defun ()
+  "Mark the current CMake function or macro.
+
+This puts the mark at the end, and point at the beginning."
+  (interactive)
+  (cmake-end-of-defun)
+  (push-mark nil :nomsg :activate)
+  (cmake-beginning-of-defun))
+
+
 ;------------------------------------------------------------------------------
 
 ;;
@@ -240,6 +298,12 @@ the indentation.  Otherwise it retains the same position on the line"
   ; Setup comment syntax.
   (set (make-local-variable 'comment-start) "#"))
 
+;; Default cmake-mode key bindings
+(define-key cmake-mode-map "\e\C-a" #'cmake-beginning-of-defun)
+(define-key cmake-mode-map "\e\C-e" #'cmake-end-of-defun)
+(define-key cmake-mode-map "\e\C-h" #'cmake-mark-defun)
+
+
 ; Help mode starts here
 
 
@@ -258,7 +322,27 @@ optional argument topic will be appended to the argument list."
     (save-selected-window
       (select-window (display-buffer buffer 'not-this-window))
       (cmake-mode)
-      (read-only-mode 1))
+      (read-only-mode 1)
+      (view-mode 1))
+    )
+  )
+
+;;;###autoload
+(defun cmake-command-run-help (type &optional topic buffer)
+  "`cmake-command-run' but rendered in `rst-mode'."
+  (interactive "s")
+  (let* ((bufname (if buffer buffer (concat "*CMake" type (if topic "-") topic "*")))
+         (buffer  (if (get-buffer bufname) (get-buffer bufname) (generate-new-buffer bufname)))
+         (command (concat cmake-mode-cmake-executable " " type " " topic))
+         ;; Turn of resizing of mini-windows for shell-command.
+         (resize-mini-windows nil)
+         )
+    (shell-command command buffer)
+    (save-selected-window
+      (select-window (display-buffer buffer 'not-this-window))
+      (rst-mode)
+      (read-only-mode 1)
+      (view-mode 1))
     )
   )
 
@@ -266,7 +350,7 @@ optional argument topic will be appended to the argument list."
 (defun cmake-help-list-commands ()
   "Prints out a list of the cmake commands."
   (interactive)
-  (cmake-command-run "--help-command-list")
+  (cmake-command-run-help "--help-command-list")
   )
 
 (defvar cmake-commands '() "List of available topics for --help-command.")
@@ -292,7 +376,7 @@ and store the result as a list in LISTVAR."
     (if (not (symbol-value listvar))
         (let ((temp-buffer-name "*CMake Temporary*"))
           (save-window-excursion
-            (cmake-command-run (concat "--help-" listname "-list") nil temp-buffer-name)
+            (cmake-command-run-help (concat "--help-" listname "-list") nil temp-buffer-name)
             (with-current-buffer temp-buffer-name
               ; FIXME: Ignore first line if it is "cmake version ..." from CMake < 3.0.
               (set listvar (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n" t)))))
@@ -326,25 +410,25 @@ and store the result as a list in LISTVAR."
 (defun cmake-help-command ()
   "Prints out the help message for the command the cursor is on."
   (interactive)
-  (cmake-command-run "--help-command" (cmake-help-type "command") "*CMake Help*"))
+  (cmake-command-run-help "--help-command" (cmake-help-type "command") "*CMake Help*"))
 
 ;;;###autoload
 (defun cmake-help-module ()
   "Prints out the help message for the module the cursor is on."
   (interactive)
-  (cmake-command-run "--help-module" (cmake-help-type "module") "*CMake Help*"))
+  (cmake-command-run-help "--help-module" (cmake-help-type "module") "*CMake Help*"))
 
 ;;;###autoload
 (defun cmake-help-variable ()
   "Prints out the help message for the variable the cursor is on."
   (interactive)
-  (cmake-command-run "--help-variable" (cmake-help-type "variable") "*CMake Help*"))
+  (cmake-command-run-help "--help-variable" (cmake-help-type "variable") "*CMake Help*"))
 
 ;;;###autoload
 (defun cmake-help-property ()
   "Prints out the help message for the property the cursor is on."
   (interactive)
-  (cmake-command-run "--help-property" (cmake-help-type "property") "*CMake Help*"))
+  (cmake-command-run-help "--help-property" (cmake-help-type "property") "*CMake Help*"))
 
 ;;;###autoload
 (defun cmake-help ()
@@ -367,13 +451,13 @@ and store the result as a list in LISTVAR."
     (if (string= input "")
         (error "No argument given")
       (if (member input command-list)
-          (cmake-command-run "--help-command" input "*CMake Help*")
+          (cmake-command-run-help "--help-command" input "*CMake Help*")
         (if (member input variable-list)
-            (cmake-command-run "--help-variable" input "*CMake Help*")
+            (cmake-command-run-help "--help-variable" input "*CMake Help*")
           (if (member input module-list)
-              (cmake-command-run "--help-module" input "*CMake Help*")
+              (cmake-command-run-help "--help-module" input "*CMake Help*")
             (if (member input property-list)
-                (cmake-command-run "--help-property" input "*CMake Help*")
+                (cmake-command-run-help "--help-property" input "*CMake Help*")
               (error "Not a know help topic.") ; this really should not happen
               ))))))
   )
index 204b496..1179199 100755 (executable)
@@ -3,6 +3,8 @@
 use strict;
 use warnings;
 use POSIX qw(strftime);
+use JSON;
+use File::Basename;
 
 #my $cmake = "/home/pboettch/devel/upstream/cmake/build/bin/cmake";
 my $cmake = "cmake";
@@ -96,6 +98,28 @@ close(CMAKE);
 # transform all properties in a hash
 my %properties = map { $_ => 1 } @properties;
 
+# read in manually written files
+my $modules_dir =  dirname(__FILE__) . "/modules";
+opendir(DIR, $modules_dir) || die "can't opendir $modules_dir: $!";
+my @json_files = grep { /\.json$/ && -f "$modules_dir/$_" } readdir(DIR);
+closedir DIR;
+
+foreach my $file (@json_files) {
+       local $/; # Enable 'slurp' mode
+       open my $fh, "<", $modules_dir."/".$file;
+       my $json = <$fh>;
+       close $fh;
+
+       my $mod = decode_json($json);
+       foreach my $var (@{$mod->{variables}}) {
+               $variables{$var} = 1;
+       }
+
+       while (my ($cmd, $keywords) = each %{$mod->{commands}}) {
+               $keywords{$cmd} = [ sort @{$keywords} ];
+       }
+}
+
 # version
 open(CMAKE, "$cmake --version|");
 my $version = 'unknown';
index 2dd3174..955beae 100644 (file)
@@ -1,13 +1,13 @@
 " Vim syntax file
 " Program:      CMake - Cross-Platform Makefile Generator
-" Version:      cmake version 3.14.20190529-g067a4f
+" Version:      cmake version 3.19.20201028-gdab947f
 " Language:     CMake
 " Author:       Andy Cedilnik <andy.cedilnik@kitware.com>,
 "               Nicholas Hutchinson <nshutchinson@gmail.com>,
 "               Patrick Boettcher <patrick.boettcher@posteo.de>
 " Maintainer:   Dimitri Merejkowsky <d.merej@gmail.com>
 " Former Maintainer: Karthik Krishnan <karthik.krishnan@kitware.com>
-" Last Change:  2019 May 29
+" Last Change:  2020 oct. 28
 "
 " Licence:      The CMake license applies to this file. See
 "               https://cmake.org/licensing
@@ -44,7 +44,9 @@ syn keyword cmakeProperty contained
             \ ADDITIONAL_CLEAN_FILES
             \ ADDITIONAL_MAKE_CLEAN_FILES
             \ ADVANCED
+            \ AIX_EXPORT_ALL_SYMBOLS
             \ ALIASED_TARGET
+            \ ALIAS_GLOBAL
             \ ALLOW_DUPLICATE_CUSTOM_TARGETS
             \ ANDROID_ANT_ADDITIONAL_OPTIONS
             \ ANDROID_API
@@ -79,6 +81,7 @@ syn keyword cmakeProperty contained
             \ AUTOMOC_EXECUTABLE
             \ AUTOMOC_MACRO_NAMES
             \ AUTOMOC_MOC_OPTIONS
+            \ AUTOMOC_PATH_PREFIX
             \ AUTOMOC_SOURCE_GROUP
             \ AUTOMOC_TARGETS_FOLDER
             \ AUTORCC
@@ -100,8 +103,8 @@ syn keyword cmakeProperty contained
             \ CACHE_VARIABLES
             \ CLEAN_NO_CUSTOM
             \ CMAKE_CONFIGURE_DEPENDS
-            \ CMAKE_CXX_KNOWN_FEATURES
             \ CMAKE_CUDA_KNOWN_FEATURES
+            \ CMAKE_CXX_KNOWN_FEATURES
             \ CMAKE_C_KNOWN_FEATURES
             \ CMAKE_ROLE
             \ COMMON_LANGUAGE_RUNTIME
@@ -123,9 +126,11 @@ syn keyword cmakeProperty contained
             \ CPACK_START_MENU_SHORTCUTS
             \ CPACK_WIX_ACL
             \ CROSSCOMPILING_EMULATOR
+            \ CUDA_ARCHITECTURES
             \ CUDA_EXTENSIONS
             \ CUDA_PTX_COMPILATION
             \ CUDA_RESOLVE_DEVICE_SYMBOLS
+            \ CUDA_RUNTIME_LIBRARY
             \ CUDA_SEPARABLE_COMPILATION
             \ CUDA_STANDARD
             \ CUDA_STANDARD_REQUIRED
@@ -142,8 +147,11 @@ syn keyword cmakeProperty contained
             \ DEPENDS
             \ DEPLOYMENT_ADDITIONAL_FILES
             \ DEPLOYMENT_REMOTE_DIRECTORY
+            \ DEPRECATION
             \ DISABLED
             \ DISABLED_FEATURES
+            \ DISABLE_PRECOMPILE_HEADERS
+            \ DOTNET_TARGET_FRAMEWORK
             \ DOTNET_TARGET_FRAMEWORK_VERSION
             \ ECLIPSE_EXTRA_CPROJECT_CONTENTS
             \ ECLIPSE_EXTRA_NATURES
@@ -202,6 +210,7 @@ syn keyword cmakeProperty contained
             \ INCLUDE_DIRECTORIES
             \ INCLUDE_REGULAR_EXPRESSION
             \ INSTALL_NAME_DIR
+            \ INSTALL_REMOVE_ENVIRONMENT_RPATH
             \ INSTALL_RPATH
             \ INSTALL_RPATH_USE_LINK_PATH
             \ INTERFACE_AUTOUIC_OPTIONS
@@ -214,11 +223,14 @@ syn keyword cmakeProperty contained
             \ INTERFACE_LINK_LIBRARIES
             \ INTERFACE_LINK_OPTIONS
             \ INTERFACE_POSITION_INDEPENDENT_CODE
+            \ INTERFACE_PRECOMPILE_HEADERS
             \ INTERFACE_SOURCES
             \ INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
             \ INTERPROCEDURAL_OPTIMIZATION
             \ IN_TRY_COMPILE
             \ IOS_INSTALL_COMBINED
+            \ ISPC_HEADER_DIRECTORY
+            \ ISPC_INSTRUCTION_SETS
             \ JOB_POOLS
             \ JOB_POOL_COMPILE
             \ JOB_POOL_LINK
@@ -242,6 +254,8 @@ syn keyword cmakeProperty contained
             \ LINK_WHAT_YOU_USE
             \ LISTFILE_STACK
             \ LOCATION
+            \ MACHO_COMPATIBILITY_VERSION
+            \ MACHO_CURRENT_VERSION
             \ MACOSX_BUNDLE
             \ MACOSX_BUNDLE_INFO_PLIST
             \ MACOSX_FRAMEWORK_INFO_PLIST
@@ -255,18 +269,29 @@ syn keyword cmakeProperty contained
             \ NAME
             \ NO_SONAME
             \ NO_SYSTEM_FROM_IMPORTED
+            \ OBJCXX_EXTENSIONS
+            \ OBJCXX_STANDARD
+            \ OBJCXX_STANDARD_REQUIRED
+            \ OBJC_EXTENSIONS
+            \ OBJC_STANDARD
+            \ OBJC_STANDARD_REQUIRED
             \ OBJECT_DEPENDS
             \ OBJECT_OUTPUTS
+            \ OPTIMIZE_DEPENDENCIES
             \ OSX_ARCHITECTURES
             \ OUTPUT_NAME
             \ PACKAGES_FOUND
             \ PACKAGES_NOT_FOUND
             \ PARENT_DIRECTORY
             \ PASS_REGULAR_EXPRESSION
+            \ PCH_INSTANTIATE_TEMPLATES
+            \ PCH_WARN_INVALID
             \ PDB_NAME
             \ PDB_OUTPUT_DIRECTORY
             \ POSITION_INDEPENDENT_CODE
             \ POST_INSTALL_SCRIPT
+            \ PRECOMPILE_HEADERS
+            \ PRECOMPILE_HEADERS_REUSE_FROM
             \ PREDEFINED_TARGETS_FOLDER
             \ PREFIX
             \ PRE_INSTALL_SCRIPT
@@ -278,6 +303,7 @@ syn keyword cmakeProperty contained
             \ REPORT_UNDEFINED_PROPERTIES
             \ REQUIRED_FILES
             \ RESOURCE
+            \ RESOURCE_GROUPS
             \ RESOURCE_LOCK
             \ RULE_LAUNCH_COMPILE
             \ RULE_LAUNCH_CUSTOM
@@ -291,8 +317,10 @@ syn keyword cmakeProperty contained
             \ SKIP_AUTORCC
             \ SKIP_AUTOUIC
             \ SKIP_BUILD_RPATH
+            \ SKIP_PRECOMPILE_HEADERS
             \ SKIP_REGULAR_EXPRESSION
             \ SKIP_RETURN_CODE
+            \ SKIP_UNITY_BUILD_INCLUSION
             \ SOURCES
             \ SOURCE_DIR
             \ SOVERSION
@@ -304,6 +332,7 @@ syn keyword cmakeProperty contained
             \ SYMBOLIC
             \ Swift_DEPENDENCIES_FILE
             \ Swift_DIAGNOSTICS_FILE
+            \ Swift_LANGUAGE_VERSION
             \ Swift_MODULE_DIRECTORY
             \ Swift_MODULE_NAME
             \ TARGET_ARCHIVES_MAY_BE_SHARED_LIBS
@@ -315,6 +344,12 @@ syn keyword cmakeProperty contained
             \ TIMEOUT
             \ TIMEOUT_AFTER_MATCH
             \ TYPE
+            \ UNITY_BUILD
+            \ UNITY_BUILD_BATCH_SIZE
+            \ UNITY_BUILD_CODE_AFTER_INCLUDE
+            \ UNITY_BUILD_CODE_BEFORE_INCLUDE
+            \ UNITY_BUILD_MODE
+            \ UNITY_GROUP
             \ USE_FOLDERS
             \ VALUE
             \ VARIABLES
@@ -329,9 +364,11 @@ syn keyword cmakeProperty contained
             \ VS_DEPLOYMENT_CONTENT
             \ VS_DEPLOYMENT_LOCATION
             \ VS_DESKTOP_EXTENSIONS_VERSION
+            \ VS_DOTNET_DOCUMENTATION_FILE
             \ VS_DOTNET_REFERENCES
             \ VS_DOTNET_REFERENCES_COPY_LOCAL
             \ VS_DOTNET_TARGET_FRAMEWORK_VERSION
+            \ VS_DPI_AWARE
             \ VS_GLOBAL_KEYWORD
             \ VS_GLOBAL_PROJECT_TYPES
             \ VS_GLOBAL_ROOTNAMESPACE
@@ -342,6 +379,8 @@ syn keyword cmakeProperty contained
             \ VS_KEYWORD
             \ VS_MOBILE_EXTENSIONS_VERSION
             \ VS_NO_SOLUTION_DEPLOY
+            \ VS_PACKAGE_REFERENCES
+            \ VS_PLATFORM_TOOLSET
             \ VS_PROJECT_IMPORT
             \ VS_RESOURCE_GENERATOR
             \ VS_SCC_AUXPATH
@@ -349,6 +388,7 @@ syn keyword cmakeProperty contained
             \ VS_SCC_PROJECTNAME
             \ VS_SCC_PROVIDER
             \ VS_SDK_REFERENCES
+            \ VS_SETTINGS
             \ VS_SHADER_DISABLE_OPTIMIZATIONS
             \ VS_SHADER_ENABLE_DEBUG
             \ VS_SHADER_ENTRYPOINT
@@ -358,6 +398,7 @@ syn keyword cmakeProperty contained
             \ VS_SHADER_OUTPUT_HEADER_FILE
             \ VS_SHADER_TYPE
             \ VS_SHADER_VARIABLE_NAME
+            \ VS_SOLUTION_DEPLOY
             \ VS_STARTUP_PROJECT
             \ VS_TOOL_OVERRIDE
             \ VS_USER_PROPS
@@ -376,11 +417,13 @@ syn keyword cmakeProperty contained
             \ XCODE_FILE_ATTRIBUTES
             \ XCODE_GENERATE_SCHEME
             \ XCODE_LAST_KNOWN_FILE_TYPE
+            \ XCODE_LINK_BUILD_PHASE_MODE
             \ XCODE_PRODUCT_TYPE
             \ XCODE_SCHEME_ADDRESS_SANITIZER
             \ XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
             \ XCODE_SCHEME_ARGUMENTS
             \ XCODE_SCHEME_DEBUG_AS_ROOT
+            \ XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
             \ XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
             \ XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
             \ XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
@@ -395,6 +438,7 @@ syn keyword cmakeProperty contained
             \ XCODE_SCHEME_THREAD_SANITIZER_STOP
             \ XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
             \ XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+            \ XCODE_SCHEME_WORKING_DIRECTORY
             \ XCODE_SCHEME_ZOMBIE_OBJECTS
             \ XCTEST
 
@@ -405,6 +449,7 @@ syn keyword cmakeVariable contained
             \ BUILD_SHARED_LIBS
             \ CACHE
             \ CMAKE_ABSOLUTE_DESTINATION_FILES
+            \ CMAKE_AIX_EXPORT_ALL_SYMBOLS
             \ CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
             \ CMAKE_ANDROID_API
             \ CMAKE_ANDROID_API_MIN
@@ -485,6 +530,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_ASM_LINKER_WRAPPER_FLAG
             \ CMAKE_ASM_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_ASM_LINK_EXECUTABLE
+            \ CMAKE_ASM_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_ASM_LINK_LIBRARY_FLAG
+            \ CMAKE_ASM_LINK_LIBRARY_SUFFIX
             \ CMAKE_ASM_MASM
             \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_PREFIX
@@ -535,6 +583,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG
             \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_ASM_MASM_LINK_EXECUTABLE
+            \ CMAKE_ASM_MASM_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_ASM_MASM_LINK_LIBRARY_FLAG
+            \ CMAKE_ASM_MASM_LINK_LIBRARY_SUFFIX
             \ CMAKE_ASM_MASM_OUTPUT_EXTENSION
             \ CMAKE_ASM_MASM_PLATFORM_ID
             \ CMAKE_ASM_MASM_SIMULATE_ID
@@ -594,6 +645,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG
             \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_ASM_NASM_LINK_EXECUTABLE
+            \ CMAKE_ASM_NASM_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_ASM_NASM_LINK_LIBRARY_FLAG
+            \ CMAKE_ASM_NASM_LINK_LIBRARY_SUFFIX
             \ CMAKE_ASM_NASM_OUTPUT_EXTENSION
             \ CMAKE_ASM_NASM_PLATFORM_ID
             \ CMAKE_ASM_NASM_SIMULATE_ID
@@ -620,6 +674,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_AUTOMOC_DEPEND_FILTERS
             \ CMAKE_AUTOMOC_MACRO_NAMES
             \ CMAKE_AUTOMOC_MOC_OPTIONS
+            \ CMAKE_AUTOMOC_PATH_PREFIX
             \ CMAKE_AUTOMOC_RELAXED_MODE
             \ CMAKE_AUTORCC
             \ CMAKE_AUTORCC_OPTIONS
@@ -640,6 +695,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_CACHE_MINOR_VERSION
             \ CMAKE_CACHE_PATCH_VERSION
             \ CMAKE_CFG_INTDIR
+            \ CMAKE_CLANG_VFS_OVERLAY
             \ CMAKE_CL_64
             \ CMAKE_CODEBLOCKS_COMPILER_ID
             \ CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES
@@ -655,6 +711,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_CPACK_COMMAND
             \ CMAKE_CROSSCOMPILING
             \ CMAKE_CROSSCOMPILING_EMULATOR
+            \ CMAKE_CROSS_CONFIGS
             \ CMAKE_CSharp
             \ CMAKE_CSharp_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_CSharp_ANDROID_TOOLCHAIN_PREFIX
@@ -705,6 +762,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_CSharp_LINKER_WRAPPER_FLAG
             \ CMAKE_CSharp_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_CSharp_LINK_EXECUTABLE
+            \ CMAKE_CSharp_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_CSharp_LINK_LIBRARY_FLAG
+            \ CMAKE_CSharp_LINK_LIBRARY_SUFFIX
             \ CMAKE_CSharp_OUTPUT_EXTENSION
             \ CMAKE_CSharp_PLATFORM_ID
             \ CMAKE_CSharp_SIMULATE_ID
@@ -714,11 +774,13 @@ syn keyword cmakeVariable contained
             \ CMAKE_CSharp_STANDARD_INCLUDE_DIRECTORIES
             \ CMAKE_CSharp_STANDARD_LIBRARIES
             \ CMAKE_CSharp_VISIBILITY_PRESET
+            \ CMAKE_CTEST_ARGUMENTS
             \ CMAKE_CTEST_COMMAND
             \ CMAKE_CUDA
             \ CMAKE_CUDA_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_CUDA_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_CUDA_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_CUDA_ARCHITECTURES
             \ CMAKE_CUDA_ARCHIVE_APPEND
             \ CMAKE_CUDA_ARCHIVE_CREATE
             \ CMAKE_CUDA_ARCHIVE_FINISH
@@ -728,7 +790,6 @@ syn keyword cmakeVariable contained
             \ CMAKE_CUDA_COMPILER_AR
             \ CMAKE_CUDA_COMPILER_ARCHITECTURE_ID
             \ CMAKE_CUDA_COMPILER_EXTERNAL_TOOLCHAIN
-            \ CMAKE_CUDA_COMPILE_FEATURES
             \ CMAKE_CUDA_COMPILER_ID
             \ CMAKE_CUDA_COMPILER_LAUNCHER
             \ CMAKE_CUDA_COMPILER_LOADED
@@ -737,6 +798,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_CUDA_COMPILER_TARGET
             \ CMAKE_CUDA_COMPILER_VERSION
             \ CMAKE_CUDA_COMPILER_VERSION_INTERNAL
+            \ CMAKE_CUDA_COMPILE_FEATURES
             \ CMAKE_CUDA_COMPILE_OBJECT
             \ CMAKE_CUDA_CPPCHECK
             \ CMAKE_CUDA_CPPLINT
@@ -768,8 +830,13 @@ syn keyword cmakeVariable contained
             \ CMAKE_CUDA_LINKER_WRAPPER_FLAG
             \ CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_CUDA_LINK_EXECUTABLE
+            \ CMAKE_CUDA_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_CUDA_LINK_LIBRARY_FLAG
+            \ CMAKE_CUDA_LINK_LIBRARY_SUFFIX
             \ CMAKE_CUDA_OUTPUT_EXTENSION
             \ CMAKE_CUDA_PLATFORM_ID
+            \ CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
+            \ CMAKE_CUDA_RUNTIME_LIBRARY
             \ CMAKE_CUDA_SEPARABLE_COMPILATION
             \ CMAKE_CUDA_SIMULATE_ID
             \ CMAKE_CUDA_SIMULATE_VERSION
@@ -782,6 +849,10 @@ syn keyword cmakeVariable contained
             \ CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
             \ CMAKE_CUDA_VISIBILITY_PRESET
             \ CMAKE_CURRENT_BINARY_DIR
+            \ CMAKE_CURRENT_FUNCTION
+            \ CMAKE_CURRENT_FUNCTION_LIST_DIR
+            \ CMAKE_CURRENT_FUNCTION_LIST_FILE
+            \ CMAKE_CURRENT_FUNCTION_LIST_LINE
             \ CMAKE_CURRENT_LIST_DIR
             \ CMAKE_CURRENT_LIST_FILE
             \ CMAKE_CURRENT_LIST_LINE
@@ -838,6 +909,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_CXX_LINKER_WRAPPER_FLAG
             \ CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_CXX_LINK_EXECUTABLE
+            \ CMAKE_CXX_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_CXX_LINK_LIBRARY_FLAG
+            \ CMAKE_CXX_LINK_LIBRARY_SUFFIX
             \ CMAKE_CXX_OUTPUT_EXTENSION
             \ CMAKE_CXX_PLATFORM_ID
             \ CMAKE_CXX_SIMULATE_ID
@@ -900,6 +974,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_C_LINKER_WRAPPER_FLAG
             \ CMAKE_C_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_C_LINK_EXECUTABLE
+            \ CMAKE_C_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_C_LINK_LIBRARY_FLAG
+            \ CMAKE_C_LINK_LIBRARY_SUFFIX
             \ CMAKE_C_OUTPUT_EXTENSION
             \ CMAKE_C_PLATFORM_ID
             \ CMAKE_C_SIMULATE_ID
@@ -913,9 +990,13 @@ syn keyword cmakeVariable contained
             \ CMAKE_C_VISIBILITY_PRESET
             \ CMAKE_DEBUG_POSTFIX
             \ CMAKE_DEBUG_TARGET_PROPERTIES
+            \ CMAKE_DEFAULT_BUILD_TYPE
+            \ CMAKE_DEFAULT_CONFIGS
             \ CMAKE_DEPENDS_IN_PROJECT_ONLY
             \ CMAKE_DIRECTORY_LABELS
+            \ CMAKE_DISABLE_PRECOMPILE_HEADERS
             \ CMAKE_DL_LIBS
+            \ CMAKE_DOTNET_TARGET_FRAMEWORK
             \ CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
             \ CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
             \ CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT
@@ -936,6 +1017,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_EXTRA_GENERATOR
             \ CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
             \ CMAKE_FIND_APPBUNDLE
+            \ CMAKE_FIND_DEBUG_MODE
             \ CMAKE_FIND_FRAMEWORK
             \ CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX
             \ CMAKE_FIND_LIBRARY_PREFIXES
@@ -960,6 +1042,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_FIND_USE_PACKAGE_REGISTRY
             \ CMAKE_FIND_USE_PACKAGE_ROOT_PATH
             \ CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH
+            \ CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY
             \ CMAKE_FOLDER
             \ CMAKE_FRAMEWORK
             \ CMAKE_FRAMEWORK_PATH
@@ -1014,6 +1097,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_Fortran_LINKER_WRAPPER_FLAG
             \ CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_Fortran_LINK_EXECUTABLE
+            \ CMAKE_Fortran_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_Fortran_LINK_LIBRARY_FLAG
+            \ CMAKE_Fortran_LINK_LIBRARY_SUFFIX
             \ CMAKE_Fortran_MODDIR_DEFAULT
             \ CMAKE_Fortran_MODDIR_FLAG
             \ CMAKE_Fortran_MODOUT_FLAG
@@ -1048,7 +1134,6 @@ syn keyword cmakeVariable contained
             \ CMAKE_HOST_UNIX
             \ CMAKE_HOST_WIN32
             \ CMAKE_IGNORE_PATH
-            \ CMAKE_ISPC_HEADER_DIRECTORY
             \ CMAKE_IMPORT_LIBRARY_PREFIX
             \ CMAKE_IMPORT_LIBRARY_SUFFIX
             \ CMAKE_INCLUDE_CURRENT_DIR
@@ -1062,11 +1147,14 @@ syn keyword cmakeVariable contained
             \ CMAKE_INSTALL_NAME_DIR
             \ CMAKE_INSTALL_PREFIX
             \ CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
+            \ CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH
             \ CMAKE_INSTALL_RPATH
             \ CMAKE_INSTALL_RPATH_USE_LINK_PATH
             \ CMAKE_INTERNAL_PLATFORM_ABI
             \ CMAKE_INTERPROCEDURAL_OPTIMIZATION
             \ CMAKE_IOS_INSTALL_COMBINED
+            \ CMAKE_ISPC_HEADER_DIRECTORY
+            \ CMAKE_ISPC_INSTRUCTION_SETS
             \ CMAKE_JOB_POOLS
             \ CMAKE_JOB_POOL_COMPILE
             \ CMAKE_JOB_POOL_LINK
@@ -1121,6 +1209,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_Java_LINKER_WRAPPER_FLAG
             \ CMAKE_Java_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_Java_LINK_EXECUTABLE
+            \ CMAKE_Java_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_Java_LINK_LIBRARY_FLAG
+            \ CMAKE_Java_LINK_LIBRARY_SUFFIX
             \ CMAKE_Java_OUTPUT_EXTENSION
             \ CMAKE_Java_PLATFORM_ID
             \ CMAKE_Java_SIMULATE_ID
@@ -1151,6 +1242,10 @@ syn keyword cmakeVariable contained
             \ CMAKE_MAKE_PROGRAM
             \ CMAKE_MATCH_COUNT
             \ CMAKE_MAXIMUM_RECURSION_DEPTH
+            \ CMAKE_MESSAGE_CONTEXT
+            \ CMAKE_MESSAGE_CONTEXT_SHOW
+            \ CMAKE_MESSAGE_INDENT
+            \ CMAKE_MESSAGE_LOG_LEVEL
             \ CMAKE_MFC_FLAG
             \ CMAKE_MINIMUM_REQUIRED_VERSION
             \ CMAKE_MINOR_VERSION
@@ -1165,12 +1260,23 @@ syn keyword cmakeVariable contained
             \ CMAKE_NOT_USING_CONFIG_FLAGS
             \ CMAKE_NO_BUILTIN_CHRPATH
             \ CMAKE_NO_SYSTEM_FROM_IMPORTED
+            \ CMAKE_OBJCXX_CLANG_TIDY
+            \ CMAKE_OBJCXX_EXTENSIONS
+            \ CMAKE_OBJCXX_STANDARD
+            \ CMAKE_OBJCXX_STANDARD_REQUIRED
+            \ CMAKE_OBJC_CLANG_TIDY
+            \ CMAKE_OBJC_EXTENSIONS
+            \ CMAKE_OBJC_STANDARD
+            \ CMAKE_OBJC_STANDARD_REQUIRED
             \ CMAKE_OBJECT_PATH_MAX
+            \ CMAKE_OPTIMIZE_DEPENDENCIES
             \ CMAKE_OSX_ARCHITECTURES
             \ CMAKE_OSX_DEPLOYMENT_TARGET
             \ CMAKE_OSX_SYSROOT
             \ CMAKE_PARENT_LIST_FILE
             \ CMAKE_PATCH_VERSION
+            \ CMAKE_PCH_INSTANTIATE_TEMPLATES
+            \ CMAKE_PCH_WARN_INVALID
             \ CMAKE_PDB_OUTPUT_DIRECTORY
             \ CMAKE_POSITION_INDEPENDENT_CODE
             \ CMAKE_PREFIX_PATH
@@ -1236,6 +1342,9 @@ syn keyword cmakeVariable contained
             \ CMAKE_RC_LINKER_WRAPPER_FLAG
             \ CMAKE_RC_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_RC_LINK_EXECUTABLE
+            \ CMAKE_RC_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_RC_LINK_LIBRARY_FLAG
+            \ CMAKE_RC_LINK_LIBRARY_SUFFIX
             \ CMAKE_RC_OUTPUT_EXTENSION
             \ CMAKE_RC_PLATFORM_ID
             \ CMAKE_RC_SIMULATE_ID
@@ -1335,7 +1444,11 @@ syn keyword cmakeVariable contained
             \ CMAKE_Swift_LINKER_WRAPPER_FLAG
             \ CMAKE_Swift_LINKER_WRAPPER_FLAG_SEP
             \ CMAKE_Swift_LINK_EXECUTABLE
+            \ CMAKE_Swift_LINK_LIBRARY_FILE_FLAG
+            \ CMAKE_Swift_LINK_LIBRARY_FLAG
+            \ CMAKE_Swift_LINK_LIBRARY_SUFFIX
             \ CMAKE_Swift_MODULE_DIRECTORY
+            \ CMAKE_Swift_NUM_THREADS
             \ CMAKE_Swift_OUTPUT_EXTENSION
             \ CMAKE_Swift_PLATFORM_ID
             \ CMAKE_Swift_SIMULATE_ID
@@ -1350,6 +1463,8 @@ syn keyword cmakeVariable contained
             \ CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
             \ CMAKE_TRY_COMPILE_TARGET_TYPE
             \ CMAKE_TWEAK_VERSION
+            \ CMAKE_UNITY_BUILD
+            \ CMAKE_UNITY_BUILD_BATCH_SIZE
             \ CMAKE_USER_MAKE_RULES_OVERRIDE
             \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM
             \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM_MASM
@@ -1378,6 +1493,7 @@ syn keyword cmakeVariable contained
             \ CMAKE_VS_PLATFORM_NAME_DEFAULT
             \ CMAKE_VS_PLATFORM_TOOLSET
             \ CMAKE_VS_PLATFORM_TOOLSET_CUDA
+            \ CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR
             \ CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
             \ CMAKE_VS_PLATFORM_TOOLSET_VERSION
             \ CMAKE_VS_SDK_EXCLUDE_DIRECTORIES
@@ -1388,19 +1504,24 @@ syn keyword cmakeVariable contained
             \ CMAKE_VS_SDK_REFERENCE_DIRECTORIES
             \ CMAKE_VS_SDK_SOURCE_DIRECTORIES
             \ CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
+            \ CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM
             \ CMAKE_VS_WINRT_BY_DEFAULT
             \ CMAKE_WARN_DEPRECATED
             \ CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
             \ CMAKE_WIN32_EXECUTABLE
             \ CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
+            \ CMAKE_XCODE_BUILD_SYSTEM
             \ CMAKE_XCODE_GENERATE_SCHEME
             \ CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY
+            \ CMAKE_XCODE_LINK_BUILD_PHASE_MODE
             \ CMAKE_XCODE_PLATFORM_TOOLSET
             \ CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER
             \ CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
+            \ CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
             \ CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
             \ CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
             \ CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+            \ CMAKE_XCODE_SCHEME_ENVIRONMENT
             \ CMAKE_XCODE_SCHEME_GUARD_MALLOC
             \ CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
             \ CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
@@ -1410,13 +1531,13 @@ syn keyword cmakeVariable contained
             \ CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP
             \ CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
             \ CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+            \ CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
             \ CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS
             \ CPACK_ABSOLUTE_DESTINATION_FILES
             \ CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY
             \ CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
             \ CPACK_INCLUDE_TOPLEVEL_DIRECTORY
             \ CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
-            \ CPACK_INSTALL_SCRIPT
             \ CPACK_PACKAGING_INSTALL_PREFIX
             \ CPACK_SET_DESTDIR
             \ CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION
@@ -1476,6 +1597,7 @@ syn keyword cmakeVariable contained
             \ CTEST_P4_COMMAND
             \ CTEST_P4_OPTIONS
             \ CTEST_P4_UPDATE_OPTIONS
+            \ CTEST_RESOURCE_SPEC_FILE
             \ CTEST_RUN_CURRENT_SCRIPT
             \ CTEST_SCP_COMMAND
             \ CTEST_SITE
@@ -1493,6 +1615,283 @@ syn keyword cmakeVariable contained
             \ CTEST_UPDATE_VERSION_OVERRIDE
             \ CTEST_USE_LAUNCHERS
             \ CYGWIN
+            \ DOXYGEN_ABBREVIATE_BRIEF
+            \ DOXYGEN_ALIASES
+            \ DOXYGEN_ALLEXTERNALS
+            \ DOXYGEN_ALLOW_UNICODE_NAMES
+            \ DOXYGEN_ALPHABETICAL_INDEX
+            \ DOXYGEN_ALWAYS_DETAILED_SEC
+            \ DOXYGEN_AUTOLINK_SUPPORT
+            \ DOXYGEN_BINARY_TOC
+            \ DOXYGEN_BRIEF_MEMBER_DESC
+            \ DOXYGEN_BUILTIN_STL_SUPPORT
+            \ DOXYGEN_CALLER_GRAPH
+            \ DOXYGEN_CALL_GRAPH
+            \ DOXYGEN_CASE_SENSE_NAMES
+            \ DOXYGEN_CHM_FILE
+            \ DOXYGEN_CHM_INDEX_ENCODING
+            \ DOXYGEN_CITE_BIB_FILES
+            \ DOXYGEN_CLANG_ASSISTED_PARSING
+            \ DOXYGEN_CLANG_DATABASE_PATH
+            \ DOXYGEN_CLANG_OPTIONS
+            \ DOXYGEN_CLASS_DIAGRAMS
+            \ DOXYGEN_CLASS_GRAPH
+            \ DOXYGEN_COLLABORATION_GRAPH
+            \ DOXYGEN_COLS_IN_ALPHA_INDEX
+            \ DOXYGEN_COMPACT_LATEX
+            \ DOXYGEN_COMPACT_RTF
+            \ DOXYGEN_CPP_CLI_SUPPORT
+            \ DOXYGEN_CREATE_SUBDIRS
+            \ DOXYGEN_DIAFILE_DIRS
+            \ DOXYGEN_DIA_PATH
+            \ DOXYGEN_DIRECTORY_GRAPH
+            \ DOXYGEN_DISABLE_INDEX
+            \ DOXYGEN_DISTRIBUTE_GROUP_DOC
+            \ DOXYGEN_DOCBOOK_OUTPUT
+            \ DOXYGEN_DOCBOOK_PROGRAMLISTING
+            \ DOXYGEN_DOCSET_BUNDLE_ID
+            \ DOXYGEN_DOCSET_FEEDNAME
+            \ DOXYGEN_DOCSET_PUBLISHER_ID
+            \ DOXYGEN_DOCSET_PUBLISHER_NAME
+            \ DOXYGEN_DOTFILE_DIRS
+            \ DOXYGEN_DOT_CLEANUP
+            \ DOXYGEN_DOT_FONTNAME
+            \ DOXYGEN_DOT_FONTPATH
+            \ DOXYGEN_DOT_FONTSIZE
+            \ DOXYGEN_DOT_GRAPH_MAX_NODES
+            \ DOXYGEN_DOT_IMAGE_FORMAT
+            \ DOXYGEN_DOT_MULTI_TARGETS
+            \ DOXYGEN_DOT_NUM_THREADS
+            \ DOXYGEN_DOT_PATH
+            \ DOXYGEN_DOT_TRANSPARENT
+            \ DOXYGEN_DOXYFILE_ENCODING
+            \ DOXYGEN_ECLIPSE_DOC_ID
+            \ DOXYGEN_ENABLED_SECTIONS
+            \ DOXYGEN_ENABLE_PREPROCESSING
+            \ DOXYGEN_ENUM_VALUES_PER_LINE
+            \ DOXYGEN_EXAMPLE_PATH
+            \ DOXYGEN_EXAMPLE_PATTERNS
+            \ DOXYGEN_EXAMPLE_RECURSIVE
+            \ DOXYGEN_EXCLUDE
+            \ DOXYGEN_EXCLUDE_PATTERNS
+            \ DOXYGEN_EXCLUDE_SYMBOLS
+            \ DOXYGEN_EXCLUDE_SYMLINKS
+            \ DOXYGEN_EXPAND_AS_DEFINED
+            \ DOXYGEN_EXPAND_ONLY_PREDEF
+            \ DOXYGEN_EXTENSION_MAPPING
+            \ DOXYGEN_EXTERNAL_GROUPS
+            \ DOXYGEN_EXTERNAL_PAGES
+            \ DOXYGEN_EXTERNAL_SEARCH
+            \ DOXYGEN_EXTERNAL_SEARCH_ID
+            \ DOXYGEN_EXTRACT_ALL
+            \ DOXYGEN_EXTRACT_ANON_NSPACES
+            \ DOXYGEN_EXTRACT_LOCAL_CLASSES
+            \ DOXYGEN_EXTRACT_LOCAL_METHODS
+            \ DOXYGEN_EXTRACT_PACKAGE
+            \ DOXYGEN_EXTRACT_PRIVATE
+            \ DOXYGEN_EXTRACT_PRIV_VIRTUAL
+            \ DOXYGEN_EXTRACT_STATIC
+            \ DOXYGEN_EXTRA_PACKAGES
+            \ DOXYGEN_EXTRA_SEARCH_MAPPINGS
+            \ DOXYGEN_EXT_LINKS_IN_WINDOW
+            \ DOXYGEN_FILE_PATTERNS
+            \ DOXYGEN_FILE_VERSION_FILTER
+            \ DOXYGEN_FILTER_PATTERNS
+            \ DOXYGEN_FILTER_SOURCE_FILES
+            \ DOXYGEN_FILTER_SOURCE_PATTERNS
+            \ DOXYGEN_FORCE_LOCAL_INCLUDES
+            \ DOXYGEN_FORMULA_FONTSIZE
+            \ DOXYGEN_FORMULA_TRANSPARENT
+            \ DOXYGEN_FULL_PATH_NAMES
+            \ DOXYGEN_GENERATE_AUTOGEN_DEF
+            \ DOXYGEN_GENERATE_BUGLIST
+            \ DOXYGEN_GENERATE_CHI
+            \ DOXYGEN_GENERATE_DEPRECATEDLIST
+            \ DOXYGEN_GENERATE_DOCBOOK
+            \ DOXYGEN_GENERATE_DOCSET
+            \ DOXYGEN_GENERATE_ECLIPSEHELP
+            \ DOXYGEN_GENERATE_HTML
+            \ DOXYGEN_GENERATE_HTMLHELP
+            \ DOXYGEN_GENERATE_LATEX
+            \ DOXYGEN_GENERATE_LEGEND
+            \ DOXYGEN_GENERATE_MAN
+            \ DOXYGEN_GENERATE_PERLMOD
+            \ DOXYGEN_GENERATE_QHP
+            \ DOXYGEN_GENERATE_RTF
+            \ DOXYGEN_GENERATE_TAGFILE
+            \ DOXYGEN_GENERATE_TESTLIST
+            \ DOXYGEN_GENERATE_TODOLIST
+            \ DOXYGEN_GENERATE_TREEVIEW
+            \ DOXYGEN_GENERATE_XML
+            \ DOXYGEN_GRAPHICAL_HIERARCHY
+            \ DOXYGEN_GROUP_GRAPHS
+            \ DOXYGEN_GROUP_NESTED_COMPOUNDS
+            \ DOXYGEN_HAVE_DOT
+            \ DOXYGEN_HHC_LOCATION
+            \ DOXYGEN_HIDE_COMPOUND_REFERENCE
+            \ DOXYGEN_HIDE_FRIEND_COMPOUNDS
+            \ DOXYGEN_HIDE_IN_BODY_DOCS
+            \ DOXYGEN_HIDE_SCOPE_NAMES
+            \ DOXYGEN_HIDE_UNDOC_CLASSES
+            \ DOXYGEN_HIDE_UNDOC_MEMBERS
+            \ DOXYGEN_HIDE_UNDOC_RELATIONS
+            \ DOXYGEN_HTML_COLORSTYLE_GAMMA
+            \ DOXYGEN_HTML_COLORSTYLE_HUE
+            \ DOXYGEN_HTML_COLORSTYLE_SAT
+            \ DOXYGEN_HTML_DYNAMIC_MENUS
+            \ DOXYGEN_HTML_DYNAMIC_SECTIONS
+            \ DOXYGEN_HTML_EXTRA_FILES
+            \ DOXYGEN_HTML_EXTRA_STYLESHEET
+            \ DOXYGEN_HTML_FILE_EXTENSION
+            \ DOXYGEN_HTML_FOOTER
+            \ DOXYGEN_HTML_HEADER
+            \ DOXYGEN_HTML_INDEX_NUM_ENTRIES
+            \ DOXYGEN_HTML_OUTPUT
+            \ DOXYGEN_HTML_STYLESHEET
+            \ DOXYGEN_HTML_TIMESTAMP
+            \ DOXYGEN_IDL_PROPERTY_SUPPORT
+            \ DOXYGEN_IGNORE_PREFIX
+            \ DOXYGEN_IMAGE_PATH
+            \ DOXYGEN_INCLUDED_BY_GRAPH
+            \ DOXYGEN_INCLUDE_FILE_PATTERNS
+            \ DOXYGEN_INCLUDE_GRAPH
+            \ DOXYGEN_INCLUDE_PATH
+            \ DOXYGEN_INHERIT_DOCS
+            \ DOXYGEN_INLINE_GROUPED_CLASSES
+            \ DOXYGEN_INLINE_INFO
+            \ DOXYGEN_INLINE_INHERITED_MEMB
+            \ DOXYGEN_INLINE_SIMPLE_STRUCTS
+            \ DOXYGEN_INLINE_SOURCES
+            \ DOXYGEN_INPUT
+            \ DOXYGEN_INPUT_ENCODING
+            \ DOXYGEN_INPUT_FILTER
+            \ DOXYGEN_INTERACTIVE_SVG
+            \ DOXYGEN_INTERNAL_DOCS
+            \ DOXYGEN_JAVADOC_AUTOBRIEF
+            \ DOXYGEN_JAVADOC_BANNER
+            \ DOXYGEN_LATEX_BATCHMODE
+            \ DOXYGEN_LATEX_BIB_STYLE
+            \ DOXYGEN_LATEX_CMD_NAME
+            \ DOXYGEN_LATEX_EMOJI_DIRECTORY
+            \ DOXYGEN_LATEX_EXTRA_FILES
+            \ DOXYGEN_LATEX_EXTRA_STYLESHEET
+            \ DOXYGEN_LATEX_FOOTER
+            \ DOXYGEN_LATEX_HEADER
+            \ DOXYGEN_LATEX_HIDE_INDICES
+            \ DOXYGEN_LATEX_MAKEINDEX_CMD
+            \ DOXYGEN_LATEX_OUTPUT
+            \ DOXYGEN_LATEX_SOURCE_CODE
+            \ DOXYGEN_LATEX_TIMESTAMP
+            \ DOXYGEN_LAYOUT_FILE
+            \ DOXYGEN_LOOKUP_CACHE_SIZE
+            \ DOXYGEN_MACRO_EXPANSION
+            \ DOXYGEN_MAKEINDEX_CMD_NAME
+            \ DOXYGEN_MAN_EXTENSION
+            \ DOXYGEN_MAN_LINKS
+            \ DOXYGEN_MAN_OUTPUT
+            \ DOXYGEN_MAN_SUBDIR
+            \ DOXYGEN_MARKDOWN_SUPPORT
+            \ DOXYGEN_MATHJAX_CODEFILE
+            \ DOXYGEN_MATHJAX_EXTENSIONS
+            \ DOXYGEN_MATHJAX_FORMAT
+            \ DOXYGEN_MATHJAX_RELPATH
+            \ DOXYGEN_MAX_DOT_GRAPH_DEPTH
+            \ DOXYGEN_MAX_INITIALIZER_LINES
+            \ DOXYGEN_MSCFILE_DIRS
+            \ DOXYGEN_MULTILINE_CPP_IS_BRIEF
+            \ DOXYGEN_OPTIMIZE_FOR_FORTRAN
+            \ DOXYGEN_OPTIMIZE_OUTPUT_FOR_C
+            \ DOXYGEN_OPTIMIZE_OUTPUT_JAVA
+            \ DOXYGEN_OPTIMIZE_OUTPUT_SLICE
+            \ DOXYGEN_OPTIMIZE_OUTPUT_VHDL
+            \ DOXYGEN_OUTPUT_DIRECTORY
+            \ DOXYGEN_OUTPUT_LANGUAGE
+            \ DOXYGEN_OUTPUT_TEXT_DIRECTION
+            \ DOXYGEN_PAPER_TYPE
+            \ DOXYGEN_PDF_HYPERLINKS
+            \ DOXYGEN_PERLMOD_LATEX
+            \ DOXYGEN_PERLMOD_MAKEVAR_PREFIX
+            \ DOXYGEN_PERLMOD_PRETTY
+            \ DOXYGEN_PLANTUML_CFG_FILE
+            \ DOXYGEN_PLANTUML_INCLUDE_PATH
+            \ DOXYGEN_PLANTUML_JAR_PATH
+            \ DOXYGEN_PREDEFINED
+            \ DOXYGEN_PROJECT_BRIEF
+            \ DOXYGEN_PROJECT_LOGO
+            \ DOXYGEN_PROJECT_NAME
+            \ DOXYGEN_PROJECT_NUMBER
+            \ DOXYGEN_QCH_FILE
+            \ DOXYGEN_QHG_LOCATION
+            \ DOXYGEN_QHP_CUST_FILTER_ATTRS
+            \ DOXYGEN_QHP_CUST_FILTER_NAME
+            \ DOXYGEN_QHP_NAMESPACE
+            \ DOXYGEN_QHP_SECT_FILTER_ATTRS
+            \ DOXYGEN_QHP_VIRTUAL_FOLDER
+            \ DOXYGEN_QT_AUTOBRIEF
+            \ DOXYGEN_QUIET
+            \ DOXYGEN_RECURSIVE
+            \ DOXYGEN_REFERENCED_BY_RELATION
+            \ DOXYGEN_REFERENCES_LINK_SOURCE
+            \ DOXYGEN_REFERENCES_RELATION
+            \ DOXYGEN_REPEAT_BRIEF
+            \ DOXYGEN_RTF_EXTENSIONS_FILE
+            \ DOXYGEN_RTF_HYPERLINKS
+            \ DOXYGEN_RTF_OUTPUT
+            \ DOXYGEN_RTF_SOURCE_CODE
+            \ DOXYGEN_RTF_STYLESHEET_FILE
+            \ DOXYGEN_SEARCHDATA_FILE
+            \ DOXYGEN_SEARCHENGINE
+            \ DOXYGEN_SEARCHENGINE_URL
+            \ DOXYGEN_SEARCH_INCLUDES
+            \ DOXYGEN_SEPARATE_MEMBER_PAGES
+            \ DOXYGEN_SERVER_BASED_SEARCH
+            \ DOXYGEN_SHORT_NAMES
+            \ DOXYGEN_SHOW_FILES
+            \ DOXYGEN_SHOW_GROUPED_MEMB_INC
+            \ DOXYGEN_SHOW_INCLUDE_FILES
+            \ DOXYGEN_SHOW_NAMESPACES
+            \ DOXYGEN_SHOW_USED_FILES
+            \ DOXYGEN_SIP_SUPPORT
+            \ DOXYGEN_SKIP_FUNCTION_MACROS
+            \ DOXYGEN_SORT_BRIEF_DOCS
+            \ DOXYGEN_SORT_BY_SCOPE_NAME
+            \ DOXYGEN_SORT_GROUP_NAMES
+            \ DOXYGEN_SORT_MEMBERS_CTORS_1ST
+            \ DOXYGEN_SORT_MEMBER_DOCS
+            \ DOXYGEN_SOURCE_BROWSER
+            \ DOXYGEN_SOURCE_TOOLTIPS
+            \ DOXYGEN_STRICT_PROTO_MATCHING
+            \ DOXYGEN_STRIP_CODE_COMMENTS
+            \ DOXYGEN_STRIP_FROM_INC_PATH
+            \ DOXYGEN_STRIP_FROM_PATH
+            \ DOXYGEN_SUBGROUPING
+            \ DOXYGEN_TAB_SIZE
+            \ DOXYGEN_TAGFILES
+            \ DOXYGEN_TCL_SUBST
+            \ DOXYGEN_TEMPLATE_RELATIONS
+            \ DOXYGEN_TOC_EXPAND
+            \ DOXYGEN_TOC_INCLUDE_HEADINGS
+            \ DOXYGEN_TREEVIEW_WIDTH
+            \ DOXYGEN_TYPEDEF_HIDES_STRUCT
+            \ DOXYGEN_UML_LIMIT_NUM_FIELDS
+            \ DOXYGEN_UML_LOOK
+            \ DOXYGEN_USE_HTAGS
+            \ DOXYGEN_USE_MATHJAX
+            \ DOXYGEN_USE_MDFILE_AS_MAINPAGE
+            \ DOXYGEN_USE_PDFLATEX
+            \ DOXYGEN_VERBATIM_HEADERS
+            \ DOXYGEN_VERBATIM_VARS
+            \ DOXYGEN_VERSION
+            \ DOXYGEN_WARNINGS
+            \ DOXYGEN_WARN_AS_ERROR
+            \ DOXYGEN_WARN_FORMAT
+            \ DOXYGEN_WARN_IF_DOC_ERROR
+            \ DOXYGEN_WARN_IF_UNDOCUMENTED
+            \ DOXYGEN_WARN_LOGFILE
+            \ DOXYGEN_WARN_NO_PARAMDOC
+            \ DOXYGEN_XML_NS_MEMB_FILE_SCOPE
+            \ DOXYGEN_XML_OUTPUT
+            \ DOXYGEN_XML_PROGRAMLISTING
             \ ENV
             \ EXECUTABLE_OUTPUT_PATH
             \ GHS-MULTI
@@ -1541,9 +1940,11 @@ syn keyword cmakeKWExternalProject contained
             \ BUILD_BYPRODUCTS
             \ BUILD_COMMAND
             \ BUILD_IN_SOURCE
+            \ CHECKOUT
             \ CMAKE_ARGS
             \ CMAKE_CACHE_ARGS
             \ CMAKE_CACHE_DEFAULT_ARGS
+            \ CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY
             \ CMAKE_TLS_CAINFO
             \ CMAKE_TLS_VERIFY
             \ COMMENT
@@ -1568,14 +1969,17 @@ syn keyword cmakeKWExternalProject contained
             \ EP_STEP_TARGETS
             \ EP_UPDATE_DISCONNECTED
             \ EXCLUDE_FROM_ALL
+            \ FALSE
             \ FORCE
             \ GHS
             \ GIT_CONFIG
             \ GIT_PROGRESS
             \ GIT_REMOTE_NAME
+            \ GIT_REMOTE_UPDATE_STRATEGY
             \ GIT_REPOSITORY
             \ GIT_SHALLOW
             \ GIT_SUBMODULES
+            \ GIT_SUBMODULES_RECURSE
             \ GIT_TAG
             \ HG_REPOSITORY
             \ HG_TAG
@@ -1583,6 +1987,7 @@ syn keyword cmakeKWExternalProject contained
             \ HTTP_PASSWORD
             \ HTTP_USERNAME
             \ IGNORED
+            \ INACTIVITY_TIMEOUT
             \ INDEPENDENT_STEP_TARGETS
             \ INSTALL_COMMAND
             \ INSTALL_DIR
@@ -1609,6 +2014,8 @@ syn keyword cmakeKWExternalProject contained
             \ PATCH_COMMAND
             \ PREFIX
             \ PROPERTY
+            \ REBASE
+            \ REBASE_CHECKOUT
             \ REQUIRED
             \ SOURCE_DIR
             \ SOURCE_SUBDIR
@@ -1633,6 +2040,7 @@ syn keyword cmakeKWExternalProject contained
             \ UPDATE_DISCONNECTED
             \ URL
             \ URL_HASH
+            \ URL_MD5
             \ USES_TERMINAL_BUILD
             \ USES_TERMINAL_CONFIGURE
             \ USES_TERMINAL_DOWNLOAD
@@ -1671,12 +2079,16 @@ syn keyword cmakeKWadd_custom_command contained
             \ MAIN_DEPENDENCY
             \ NOT
             \ OUTPUT
+            \ PATH
             \ POST_BUILD
             \ PRE_BUILD
             \ PRE_LINK
             \ SYMBOLIC
             \ TARGET_FILE
+            \ TARGET_LINKER_FILE
+            \ TARGET_PDB_FILE
             \ TARGET_PROPERTY
+            \ TARGET_SONAME_FILE
             \ USES_TERMINAL
             \ VERBATIM
             \ WORKING_DIRECTORY
@@ -1695,8 +2107,13 @@ syn keyword cmakeKWadd_custom_target contained
             \ JOB_POOL
             \ JOB_POOLS
             \ JOIN
+            \ PATH
             \ SOURCES
+            \ TARGET_FILE
+            \ TARGET_LINKER_FILE
+            \ TARGET_PDB_FILE
             \ TARGET_PROPERTY
+            \ TARGET_SONAME_FILE
             \ USES_TERMINAL
             \ VERBATIM
             \ WORKING_DIRECTORY
@@ -1710,6 +2127,7 @@ syn keyword cmakeKWadd_dependencies contained
 
 syn keyword cmakeKWadd_executable contained
             \ ALIAS
+            \ ALIAS_GLOBAL
             \ CONFIG
             \ EXCLUDE_FROM_ALL
             \ GLOBAL
@@ -1725,6 +2143,7 @@ syn keyword cmakeKWadd_executable contained
 
 syn keyword cmakeKWadd_library contained
             \ ALIAS
+            \ ALIAS_GLOBAL
             \ ARCHIVE_OUTPUT_DIRECTORY
             \ CLI
             \ CONFIG
@@ -1735,11 +2154,15 @@ syn keyword cmakeKWadd_library contained
             \ HEADER_FILE_ONLY
             \ IMPORTED
             \ IMPORTED_
+            \ IMPORTED_IMPLIB
+            \ IMPORTED_IMPLIB_
             \ IMPORTED_LOCATION
             \ IMPORTED_LOCATION_
             \ IMPORTED_OBJECTS
             \ IMPORTED_OBJECTS_
+            \ INTERFACE
             \ INTERFACE_
+            \ INTERFACE_SOURCES
             \ LIBRARY_OUTPUT_DIRECTORY
             \ MODULE
             \ OBJECT
@@ -1749,17 +2172,23 @@ syn keyword cmakeKWadd_library contained
             \ POST_BUILD
             \ PRE_BUILD
             \ PRE_LINK
-            \ PUBLIC_HEADER
+            \ PRIVATE
+            \ PUBLIC
             \ RUNTIME_OUTPUT_DIRECTORY
             \ SHARED
+            \ SOURCES
             \ STATIC
             \ TARGET_OBJECTS
             \ UNKNOWN
 
 syn keyword cmakeKWadd_link_options contained
             \ CMAKE_
+            \ CUDA_RESOLVE_DEVICE_SYMBOLS
+            \ CUDA_SEPARABLE_COMPILATION
+            \ DEVICE_LINK
             \ GCC
             \ GNU
+            \ HOST_LINK
             \ LANG
             \ LINKER
             \ LINK_OPTIONS
@@ -1775,6 +2204,7 @@ syn keyword cmakeKWadd_subdirectory contained
 syn keyword cmakeKWadd_test contained
             \ BUILD_TESTING
             \ COMMAND
+            \ COMMAND_EXPAND_LISTS
             \ CONFIGURATIONS
             \ FAIL_REGULAR_EXPRESSION
             \ NAME
@@ -1816,6 +2246,23 @@ syn keyword cmakeKWcmake_host_system_information contained
             \ TOTAL_PHYSICAL_MEMORY
             \ TOTAL_VIRTUAL_MEMORY
 
+syn keyword cmakeKWcmake_language contained
+            \ AND
+            \ CALL
+            \ CANCEL_CALL
+            \ CODE
+            \ DEFER
+            \ DIRECTORY
+            \ EVAL
+            \ FALSE
+            \ GET_CALL_IDS
+            \ ID
+            \ ID_VAR
+            \ OR
+            \ STATUS
+            \ TRUE
+            \ WRITE
+
 syn keyword cmakeKWcmake_minimum_required contained
             \ FATAL_ERROR
             \ VERSION
@@ -1845,6 +2292,72 @@ syn keyword cmakeKWcmake_parse_arguments contained
             \ _KEYWORDS_MISSING_VALUES
             \ _UNPARSED_ARGUMENTS
 
+syn keyword cmakeKWcmake_path contained
+            \ ABSOLUTE_PATH
+            \ AND
+            \ APPEND
+            \ BASE_DIRECTORY
+            \ CMAKE_PATH
+            \ COMPARE
+            \ CONCAT
+            \ CONVERT
+            \ ELSEIF
+            \ ENDIF
+            \ EXTENSION
+            \ EXTENSION_DEF
+            \ FALSE
+            \ FILENAME_DEF
+            \ GET
+            \ GET_EXTENSION
+            \ GET_FILENAME
+            \ GET_PARENT_PATH
+            \ GET_RELATIVE_PATH
+            \ GET_ROOT_DIRECTORY
+            \ GET_ROOT_NAME
+            \ GET_ROOT_PATH
+            \ GET_STEM
+            \ HASH
+            \ HAS_EXTENSION
+            \ HAS_FILENAME
+            \ HAS_PARENT_PATH
+            \ HAS_RELATIVE_PATH
+            \ HAS_ROOT_DIRECTORY
+            \ HAS_ROOT_NAME
+            \ HAS_ROOT_PATH
+            \ HAS_STEM
+            \ IF
+            \ IS_ABSOLUTE
+            \ IS_PREFIX
+            \ IS_RELATIVE
+            \ LAST_ONLY
+            \ MATCHES
+            \ NATIVE_PATH
+            \ NORMALIZE
+            \ NORMAL_PATH
+            \ NOT
+            \ NOT_EQUAL
+            \ OP
+            \ OS
+            \ OUTPUT_VARIABLE
+            \ PARENT_PATH
+            \ PROXIMATE_PATH
+            \ REAL_PATH
+            \ RELATIVE_PATH
+            \ REMOVE_EXTENSION
+            \ REMOVE_FILENAME
+            \ REPLACE_EXTENSION
+            \ REPLACE_FILENAME
+            \ RETURN
+            \ ROOT_DIRECTORY
+            \ ROOT_NAME
+            \ ROOT_PATH
+            \ STEM
+            \ STREQUAL
+            \ TO_CMAKE_PATH_LIST
+            \ TO_NATIVE_PATH_LIST
+            \ TRUE
+            \ XOR
+
 syn keyword cmakeKWcmake_policy contained
             \ CMAKE_POLICY_DEFAULT_CMP
             \ CMP
@@ -1862,10 +2375,13 @@ syn keyword cmakeKWconfigure_file contained
             \ CRLF
             \ DOS
             \ ESCAPE_QUOTES
+            \ FILE_PERMISSIONS
             \ FOO_ENABLE
             \ FOO_STRING
             \ LF
             \ NEWLINE_STYLE
+            \ NO_SOURCE_PERMISSIONS
+            \ USE_SOURCE_PERMISSIONS
             \ VAR
 
 syn keyword cmakeKWcreate_test_sourcelist contained
@@ -1935,6 +2451,7 @@ syn keyword cmakeKWctest_run_script contained
 
 syn keyword cmakeKWctest_start contained
             \ APPEND
+            \ GROUP
             \ QUIET
             \ TAG
             \ TRACK
@@ -1957,6 +2474,7 @@ syn keyword cmakeKWctest_submit contained
             \ SUBMIT_URL
 
 syn keyword cmakeKWctest_test contained
+            \ AFTER_TIMEOUT
             \ APPEND
             \ BUILD
             \ CAPTURE_CMAKE_ERROR
@@ -1972,12 +2490,17 @@ syn keyword cmakeKWctest_test contained
             \ ON
             \ PARALLEL_LEVEL
             \ QUIET
+            \ REPEAT
+            \ RESOURCE_SPEC_FILE
             \ RETURN_VALUE
             \ SCHEDULE_RANDOM
             \ START
+            \ STOP_ON_FAILURE
             \ STOP_TIME
             \ STRIDE
             \ TEST_LOAD
+            \ UNTIL_FAIL
+            \ UNTIL_PASS
 
 syn keyword cmakeKWctest_update contained
             \ CAPTURE_CMAKE_ERROR
@@ -2005,9 +2528,18 @@ syn keyword cmakeKWdefine_property contained
             \ TEST
             \ VARIABLE
 
+syn keyword cmakeKWdoxygen_add_docs contained
+            \ ALL
+            \ COMMENT
+            \ USE_STAMP_FILE
+            \ WORKING_DIRECTORY
+
 syn keyword cmakeKWenable_language contained
             \ ASM
             \ CUDA
+            \ ISPC
+            \ OBJC
+            \ OBJCXX
             \ OPTIONAL
 
 syn keyword cmakeKWenable_testing contained
@@ -2020,15 +2552,20 @@ syn keyword cmakeKWexec_program contained
 
 syn keyword cmakeKWexecute_process contained
             \ ANSI
+            \ ANY
             \ AUTO
             \ COMMAND
             \ COMMAND_ECHO
+            \ COMMAND_ERROR_IS_FATAL
+            \ ECHO_ERROR_VARIABLE
+            \ ECHO_OUTPUT_VARIABLE
             \ ENCODING
             \ ERROR_FILE
             \ ERROR_QUIET
             \ ERROR_STRIP_TRAILING_WHITESPACE
             \ ERROR_VARIABLE
             \ INPUT_FILE
+            \ LAST
             \ NONE
             \ OEM
             \ OUTPUT_FILE
@@ -2070,63 +2607,107 @@ syn keyword cmakeKWexport_library_dependencies contained
 syn keyword cmakeKWfile contained
             \ ALGO
             \ APPEND
+            \ ARCHIVE_CREATE
+            \ ARCHIVE_EXTRACT
             \ ASCII
+            \ BASE_DIRECTORY
+            \ BUNDLE_EXECUTABLE
+            \ CHMOD
+            \ CHMOD_RECURSE
+            \ CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND
+            \ CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM
+            \ CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL
+            \ CMAKE_OBJDUMP
             \ CMAKE_TLS_CAINFO
             \ CMAKE_TLS_VERIFY
+            \ CODE
+            \ COMPILE_FEATURES
+            \ COMPRESSION
+            \ COMPRESSION_LEVEL
             \ CONDITION
-            \ CONFIG
+            \ CONFIGURE
             \ CONFIGURE_DEPENDS
+            \ CONFLICTING_DEPENDENCIES_PREFIX
             \ CONTENT
+            \ CONVERT
             \ COPY
             \ COPY_ON_ERROR
             \ CREATE_LINK
+            \ CRLF
             \ DESTINATION
+            \ DIRECTORIES
             \ DIRECTORY_PERMISSIONS
+            \ DLL
+            \ DOS
             \ DOWNLOAD
             \ ENCODING
-            \ EXCLUDE
+            \ ESCAPE_QUOTES
+            \ EXECUTABLES
             \ EXPECTED_HASH
             \ FILES_MATCHING
             \ FILE_PERMISSIONS
             \ FOLLOW_SYMLINKS
             \ FOLLOW_SYMLINK_CHAIN
+            \ FORMAT
             \ FUNCTION
             \ GENERATE
+            \ GET_RUNTIME_DEPENDENCIES
             \ GLOB
             \ GLOB_RECURSE
+            \ GROUP_EXECUTE
+            \ GROUP_READ
+            \ GROUP_WRITE
             \ GUARD
             \ HASH
             \ HEX
             \ HTTPHEADER
             \ IGNORED
             \ INACTIVITY_TIMEOUT
+            \ INPUT
             \ INSTALL
             \ IS_ABSOLUTE
             \ LENGTH_MAXIMUM
             \ LENGTH_MINIMUM
             \ LF
+            \ LIBRARIES
             \ LIMIT
             \ LIMIT_COUNT
             \ LIMIT_INPUT
             \ LIMIT_OUTPUT
             \ LIST_DIRECTORIES
+            \ LIST_ONLY
             \ LOCK
             \ LOG
             \ MAKE_DIRECTORY
+            \ MODULES
+            \ MTIME
+            \ MYLIBRARY
             \ NETRC
             \ NETRC_FILE
             \ NEWLINE_CONSUME
+            \ NEWLINE_STYLE
             \ NOT
             \ NO_HEX_CONVERSION
             \ NO_SOURCE_PERMISSIONS
             \ OFFSET
-            \ OLD
+            \ ONLY
             \ OPTIONAL
             \ OUTPUT
+            \ OWNER_EXECUTE
+            \ OWNER_READ
+            \ OWNER_WRITE
+            \ PATHS
             \ PATTERN
+            \ PATTERNS
+            \ PERMISSIONS
+            \ POST_EXCLUDE_REGEXES
+            \ POST_INCLUDE_REGEXES
+            \ PRE_EXCLUDE_REGEXES
+            \ PRE_INCLUDE_REGEXES
             \ PROCESS
             \ READ
             \ READ_SYMLINK
+            \ REAL_PATH
             \ REGEX
             \ RELATIVE_PATH
             \ RELEASE
@@ -2134,33 +2715,51 @@ syn keyword cmakeKWfile contained
             \ REMOVE_RECURSE
             \ RENAME
             \ REQUIRED
+            \ RESOLVED_DEPENDENCIES_VAR
             \ RESULT
             \ RESULT_VARIABLE
+            \ RPATH
+            \ RUNPATH
+            \ SCRIPT
+            \ SHARED
             \ SHOW_PROGRESS
             \ SIZE
             \ SSL
+            \ STATIC
             \ STATUS
             \ STRINGS
             \ SYMBOLIC
+            \ TARGET
+            \ TARGET_PROPERTY
             \ TIMESTAMP
             \ TLS_CAINFO
             \ TLS_VERIFY
             \ TOUCH
             \ TOUCH_NOCREATE
             \ TO_CMAKE_PATH
+            \ TO_CMAKE_PATH_LIST
             \ TO_NATIVE_PATH
+            \ TO_NATIVE_PATH_LIST
+            \ UNRESOLVED_DEPENDENCIES_VAR
             \ UPLOAD
             \ URL
             \ USERPWD
             \ USE_SOURCE_PERMISSIONS
             \ UTC
             \ UTF
+            \ VERBOSE
+            \ WORLD_EXECUTE
+            \ WORLD_READ
+            \ WORLD_WRITE
             \ WRITE
+            \ XZ
+            \ _FILENAMES
 
 syn keyword cmakeKWfind_file contained
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ DOC
             \ DVAR
+            \ FALSE
             \ HINTS
             \ INCLUDE
             \ NAMES
@@ -2174,14 +2773,16 @@ syn keyword cmakeKWfind_file contained
             \ ONLY_CMAKE_FIND_ROOT_PATH
             \ PATHS
             \ PATH_SUFFIXES
+            \ REQUIRED
             \ VAR
 
 syn keyword cmakeKWfind_library contained
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ DOC
             \ DVAR
+            \ FALSE
             \ HINTS
-            \ LIB
+            \ INCLUDE
             \ NAMES
             \ NAMES_PER_DIR
             \ NO_CMAKE_ENVIRONMENT_PATH
@@ -2194,6 +2795,7 @@ syn keyword cmakeKWfind_library contained
             \ ONLY_CMAKE_FIND_ROOT_PATH
             \ PATHS
             \ PATH_SUFFIXES
+            \ REQUIRED
             \ VAR
 
 syn keyword cmakeKWfind_package contained
@@ -2207,8 +2809,12 @@ syn keyword cmakeKWfind_package contained
             \ DEC
             \ DVAR
             \ EXACT
+            \ EXCLUDE
+            \ FALSE
+            \ FIND_PACKAGE_VERSION_FORMAT
             \ FRAMEWORK
             \ HINTS
+            \ INCLUDE
             \ MODULE
             \ NAMES
             \ NATURAL
@@ -2228,12 +2834,26 @@ syn keyword cmakeKWfind_package contained
             \ OPTIONAL_COMPONENTS
             \ PACKAGE_FIND_NAME
             \ PACKAGE_FIND_VERSION
+            \ PACKAGE_FIND_VERSION_COMPLETE
             \ PACKAGE_FIND_VERSION_COUNT
             \ PACKAGE_FIND_VERSION_MAJOR
+            \ PACKAGE_FIND_VERSION_MAX
+            \ PACKAGE_FIND_VERSION_MAX_COUNT
+            \ PACKAGE_FIND_VERSION_MAX_MAJOR
+            \ PACKAGE_FIND_VERSION_MAX_MINOR
+            \ PACKAGE_FIND_VERSION_MAX_PATCH
+            \ PACKAGE_FIND_VERSION_MAX_TWEAK
             \ PACKAGE_FIND_VERSION_MINOR
+            \ PACKAGE_FIND_VERSION_MIN_COUNT
+            \ PACKAGE_FIND_VERSION_MIN_MAJOR
+            \ PACKAGE_FIND_VERSION_MIN_MINOR
+            \ PACKAGE_FIND_VERSION_MIN_PATCH
+            \ PACKAGE_FIND_VERSION_MIN_TWEAK
             \ PACKAGE_FIND_VERSION_PATCH
+            \ PACKAGE_FIND_VERSION_RANGE
+            \ PACKAGE_FIND_VERSION_RANGE_MAX
+            \ PACKAGE_FIND_VERSION_RANGE_MIN
             \ PACKAGE_FIND_VERSION_TWEAK
-            \ PACKAGE_VERSION
             \ PACKAGE_VERSION_COMPATIBLE
             \ PACKAGE_VERSION_EXACT
             \ PACKAGE_VERSION_UNSUITABLE
@@ -2258,6 +2878,7 @@ syn keyword cmakeKWfind_path contained
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ DOC
             \ DVAR
+            \ FALSE
             \ HINTS
             \ INCLUDE
             \ NAMES
@@ -2271,12 +2892,14 @@ syn keyword cmakeKWfind_path contained
             \ ONLY_CMAKE_FIND_ROOT_PATH
             \ PATHS
             \ PATH_SUFFIXES
+            \ REQUIRED
             \ VAR
 
 syn keyword cmakeKWfind_program contained
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ DOC
             \ DVAR
+            \ FALSE
             \ HINTS
             \ NAMES
             \ NAMES_PER_DIR
@@ -2290,22 +2913,26 @@ syn keyword cmakeKWfind_program contained
             \ ONLY_CMAKE_FIND_ROOT_PATH
             \ PATHS
             \ PATH_SUFFIXES
+            \ REQUIRED
             \ VAR
 
 syn keyword cmakeKWfltk_wrap_ui contained
             \ FLTK
 
 syn keyword cmakeKWforeach contained
+            \ APPEND
             \ IN
             \ ITEMS
             \ LISTS
             \ RANGE
             \ STATUS
+            \ ZIP_LISTS
 
 syn keyword cmakeKWfunction contained
             \ ARGC
             \ ARGN
             \ ARGV
+            \ CALL
             \ FOO
             \ PARENT_SCOPE
 
@@ -2333,6 +2960,7 @@ syn keyword cmakeKWget_filename_component contained
             \ PROGRAM
             \ PROGRAM_ARGS
             \ REALPATH
+            \ REAL_PATH
 
 syn keyword cmakeKWget_property contained
             \ BRIEF_DOCS
@@ -2345,13 +2973,15 @@ syn keyword cmakeKWget_property contained
             \ SET
             \ SOURCE
             \ TARGET
+            \ TARGET_DIRECTORY
             \ TEST
             \ VARIABLE
 
 syn keyword cmakeKWget_source_file_property contained
+            \ DIRECTORY
             \ INHERITED
             \ LOCATION
-            \ VAR
+            \ TARGET_DIRECTORY
 
 syn keyword cmakeKWget_target_property contained
             \ INHERITED
@@ -2427,6 +3057,7 @@ syn keyword cmakeKWinclude_guard contained
 
 syn keyword cmakeKWinstall contained
             \ AFTER
+            \ AIX
             \ APT
             \ ARCHIVE
             \ BEFORE
@@ -2460,6 +3091,7 @@ syn keyword cmakeKWinstall contained
             \ DIRECTORY_PERMISSIONS
             \ DLL
             \ DOC
+            \ ENABLE_EXPORTS
             \ EXCLUDE_FROM_ALL
             \ EXPORT
             \ EXPORT_ANDROID_MK
@@ -2565,6 +3197,7 @@ syn keyword cmakeKWlist contained
             \ INTERNAL
             \ JOIN
             \ LENGTH
+            \ NATURAL
             \ ORDER
             \ OUTPUT_VARIABLE
             \ PARENT_SCOPE
@@ -2600,6 +3233,7 @@ syn keyword cmakeKWmacro contained
             \ ARGC
             \ ARGN
             \ ARGV
+            \ CALL
             \ DEFINED
             \ FOO
             \ GREATER
@@ -2616,12 +3250,18 @@ syn keyword cmakeKWmath contained
             \ OUTPUT_FORMAT
 
 syn keyword cmakeKWmessage contained
+            \ APPEND
             \ AUTHOR_WARNING
+            \ CHECK_
+            \ CHECK_FAIL
+            \ CHECK_PASS
+            \ CHECK_START
             \ DEBUG
             \ DEPRECATION
             \ FATAL_ERROR
             \ GUI
             \ NOTICE
+            \ POP_BACK
             \ SEND_ERROR
             \ STATUS
             \ TRACE
@@ -2638,15 +3278,18 @@ syn keyword cmakeKWproject contained
             \ CUDA
             \ DESCRIPTION
             \ HOMEPAGE_URL
+            \ ISPC
             \ LANGUAGES
             \ NAME
             \ NONE
+            \ OBJC
+            \ OBJCXX
             \ PROJECT
             \ VERSION
             \ _BINARY_DIR
             \ _DESCRIPTION
             \ _HOMEPAGE_URL
-            \ _INCLUDE
+            \ _INCLUDE_BEFORE
             \ _SOURCE_DIR
             \ _VERSION
             \ _VERSION_MAJOR
@@ -2664,9 +3307,14 @@ syn keyword cmakeKWremove contained
             \ VALUE
             \ VAR
 
+syn keyword cmakeKWreturn contained
+            \ DEFER
+
 syn keyword cmakeKWseparate_arguments contained
             \ MSDN
             \ NATIVE_COMMAND
+            \ PROGRAM
+            \ SEPARATE_ARGS
             \ UNIX_COMMAND
             \ WINDOWS_COMMAND
 
@@ -2695,12 +3343,15 @@ syn keyword cmakeKWset_property contained
             \ PROPERTY
             \ SOURCE
             \ TARGET
+            \ TARGET_DIRECTORY
             \ TEST
             \ WIX
 
 syn keyword cmakeKWset_source_files_properties contained
+            \ DIRECTORY
             \ PROPERTIES
             \ SOURCE
+            \ TARGET_DIRECTORY
 
 syn keyword cmakeKWset_target_properties contained
             \ PROPERTIES
@@ -2710,6 +3361,9 @@ syn keyword cmakeKWset_tests_properties contained
             \ PROPERTIES
             \ TEST
 
+syn keyword cmakeKWsite_name contained
+            \ HOSTNAME
+
 syn keyword cmakeKWsource_group contained
             \ FILES
             \ PREFIX
@@ -2719,20 +3373,27 @@ syn keyword cmakeKWsource_group contained
 syn keyword cmakeKWstring contained
             \ ALPHABET
             \ APPEND
+            \ ARRAY
             \ ASCII
+            \ BOOLEAN
             \ CMAKE_MATCH_
             \ COMPARE
             \ CONCAT
             \ CONFIGURE
             \ EQUAL
+            \ ERROR_VARIABLE
             \ ESCAPE_QUOTES
             \ FIND
             \ GENEX_STRIP
+            \ GET
             \ GREATER
             \ GREATER_EQUAL
             \ GUID
             \ HASH
+            \ HEX
             \ JOIN
+            \ JSON
+            \ JSONLENGTH
             \ LENGTH
             \ LESS
             \ LESS_EQUAL
@@ -2740,17 +3401,24 @@ syn keyword cmakeKWstring contained
             \ MATCH
             \ MATCHALL
             \ MATCHES
+            \ MEMBER
             \ NAMESPACE
             \ NOTEQUAL
+            \ NULL
+            \ NUMBER
+            \ OBJECT
+            \ OFF
             \ ONLY
             \ PREPEND
             \ RANDOM
             \ RANDOM_SEED
             \ REGEX
+            \ REMOVE
             \ REPEAT
             \ REPLACE
             \ REVERSE
             \ RFC
+            \ SET
             \ SHA
             \ SOURCE_DATE_EPOCH
             \ STRIP
@@ -2853,8 +3521,12 @@ syn keyword cmakeKWtarget_link_options contained
             \ ALIAS
             \ BEFORE
             \ CMAKE_
+            \ CUDA_RESOLVE_DEVICE_SYMBOLS
+            \ CUDA_SEPARABLE_COMPILATION
+            \ DEVICE_LINK
             \ GCC
             \ GNU
+            \ HOST_LINK
             \ IMPORTED
             \ INTERFACE
             \ INTERFACE_LINK_OPTIONS
@@ -2870,9 +3542,23 @@ syn keyword cmakeKWtarget_link_options contained
             \ _LINKER_WRAPPER_FLAG_SEP
 
 syn keyword cmakeKWtarget_precompile_headers contained
+            \ ALIAS
+            \ ANGLE
+            \ BUILD_INTERFACE
+            \ COMPILE_LANGUAGE
+            \ DISABLE_PRECOMPILE_HEADERS
+            \ EXPORT
+            \ FI
+            \ GCC
+            \ IMPORTED
             \ INTERFACE
+            \ INTERFACE_PRECOMPILE_HEADERS
+            \ PRECOMPILE_HEADERS
+            \ PRECOMPILE_HEADERS_REUSE_FROM
             \ PRIVATE
             \ PUBLIC
+            \ REUSE_FROM
+            \ SKIP_PRECOMPILE_HEADERS
 
 syn keyword cmakeKWtarget_sources contained
             \ ALIAS
@@ -2911,6 +3597,12 @@ syn keyword cmakeKWtry_compile contained
             \ LINK_OPTIONS
             \ MULTI
             \ NOT
+            \ OBJCXX_EXTENSIONS
+            \ OBJCXX_STANDARD
+            \ OBJCXX_STANDARD_REQUIRED
+            \ OBJC_EXTENSIONS
+            \ OBJC_STANDARD
+            \ OBJC_STANDARD_REQUIRED
             \ OUTPUT_VARIABLE
             \ PRIVATE
             \ SOURCES
@@ -2956,7 +3648,14 @@ syn keyword cmakeKWvariable_requires contained
             \ TEST_VARIABLE
 
 syn keyword cmakeKWvariable_watch contained
+            \ APPEND
             \ COMMAND
+            \ DEFINED
+            \ MODIFIED_ACCESS
+            \ READ_ACCESS
+            \ REMOVED_ACCESS
+            \ UNKNOWN_MODIFIED_ACCESS
+            \ UNKNOWN_READ_ACCESS
 
 syn keyword cmakeKWwrite_file contained
             \ APPEND
@@ -2988,39 +3687,49 @@ syn keyword cmakeGeneratorExpressions contained
             \ CONFIGURATION
             \ CUDA_COMPILER_ID
             \ CUDA_COMPILER_VERSION
+            \ CUDA_RESOLVE_DEVICE_SYMBOLS
+            \ CUDA_SEPARABLE_COMPILATION
             \ CUSTOM_KEYS
             \ CXX_COMPILER_ID
             \ CXX_COMPILER_VERSION
+            \ CXX_CONFIG
             \ CXX_STANDARD
             \ C_COMPILER_ID
             \ C_COMPILER_VERSION
             \ C_STANDARD
             \ DEBUG_MODE
             \ DEBUG_POSTFIX
+            \ DEVICE_LINK
+            \ DLL
             \ EXCLUDE
             \ EXPORT
             \ FALSE
             \ FILTER
             \ FOO_EXTRA_THINGS
-            \ Fortran_COMPILER_ID
-            \ Fortran_COMPILER_VERSION
             \ GENERATE
             \ GENEX_EVAL
             \ GNU
+            \ HOST_LINK
             \ IF
             \ IGNORE
             \ IMPORT_PREFIX
             \ IMPORT_SUFFIX
             \ INCLUDE_DIRECTORIES
             \ INSTALL_INTERFACE
+            \ INSTALL_NAME_DIR
             \ INSTALL_PREFIX
+            \ INTERFACE
             \ INTERFACE_LINK_LIBRARIES
             \ IN_LIST
+            \ ISPC_COMPILER_ID
+            \ ISPC_COMPILER_VERSION
             \ JOIN
             \ LANG
             \ LANG_COMPILER_ID
             \ LIBRARY_OUTPUT_NAME
             \ LIBRARY_OUTPUT_NAME_
+            \ LINK_LANGUAGE
+            \ LINK_LANG_AND_ID
             \ LINK_LIBRARIES
             \ LINK_ONLY
             \ LOWER_CASE
@@ -3028,6 +3737,10 @@ syn keyword cmakeGeneratorExpressions contained
             \ MAP_IMPORTED_CONFIG_
             \ NO
             \ NOT
+            \ OBJCXX_COMPILER_ID
+            \ OBJCXX_COMPILER_VERSION
+            \ OBJC_COMPILER_ID
+            \ OBJC_COMPILER_VERSION
             \ OFF
             \ OLD_COMPILER
             \ OUTPUT_NAME
@@ -3046,6 +3759,7 @@ syn keyword cmakeGeneratorExpressions contained
             \ SDK
             \ SEMICOLON
             \ SHELL_PATH
+            \ STATIC
             \ STREQUAL
             \ TARGET_BUNDLE_CONTENT_DIR
             \ TARGET_BUNDLE_DIR
@@ -3100,8 +3814,10 @@ syn keyword cmakeCommand
             \ break
             \ build_command
             \ cmake_host_system_information
+            \ cmake_language
             \ cmake_minimum_required
             \ cmake_parse_arguments
+            \ cmake_path
             \ cmake_policy
             \ configure_file
             \ continue
@@ -3258,8 +3974,10 @@ hi def link cmakeKWadd_subdirectory ModeMsg
 hi def link cmakeKWadd_test ModeMsg
 hi def link cmakeKWbuild_command ModeMsg
 hi def link cmakeKWcmake_host_system_information ModeMsg
+hi def link cmakeKWcmake_language ModeMsg
 hi def link cmakeKWcmake_minimum_required ModeMsg
 hi def link cmakeKWcmake_parse_arguments ModeMsg
+hi def link cmakeKWcmake_path ModeMsg
 hi def link cmakeKWcmake_policy ModeMsg
 hi def link cmakeKWconfigure_file ModeMsg
 hi def link cmakeKWcreate_test_sourcelist ModeMsg
@@ -3274,6 +3992,7 @@ hi def link cmakeKWctest_test ModeMsg
 hi def link cmakeKWctest_update ModeMsg
 hi def link cmakeKWctest_upload ModeMsg
 hi def link cmakeKWdefine_property ModeMsg
+hi def link cmakeKWdoxygen_add_docs ModeMsg
 hi def link cmakeKWenable_language ModeMsg
 hi def link cmakeKWenable_testing ModeMsg
 hi def link cmakeKWexec_program ModeMsg
@@ -3318,6 +4037,7 @@ hi def link cmakeKWproject ModeMsg
 hi def link cmakeKWqt_wrap_cpp ModeMsg
 hi def link cmakeKWqt_wrap_ui ModeMsg
 hi def link cmakeKWremove ModeMsg
+hi def link cmakeKWreturn ModeMsg
 hi def link cmakeKWseparate_arguments ModeMsg
 hi def link cmakeKWset ModeMsg
 hi def link cmakeKWset_directory_properties ModeMsg
@@ -3325,6 +4045,7 @@ hi def link cmakeKWset_property ModeMsg
 hi def link cmakeKWset_source_files_properties ModeMsg
 hi def link cmakeKWset_target_properties ModeMsg
 hi def link cmakeKWset_tests_properties ModeMsg
+hi def link cmakeKWsite_name ModeMsg
 hi def link cmakeKWsource_group ModeMsg
 hi def link cmakeKWstring ModeMsg
 hi def link cmakeKWsubdirs ModeMsg
index 2d860d4..a2fcf2e 100644 (file)
@@ -1,7 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.1...3.15 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.1...3.18 FATAL_ERROR)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
 project(CMake)
index b867d01..7f51293 100644 (file)
@@ -1,5 +1,5 @@
 CMake - Cross Platform Makefile Generator
-Copyright 2000-2020 Kitware, Inc. and Contributors
+Copyright 2000-2021 Kitware, Inc. and Contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -65,8 +65,8 @@ The following individuals and institutions are among the Contributors:
 * Jan Woetzel
 * Julien Schueller
 * Kelly Thompson <kgt@lanl.gov>
-* Laurent Montel <montel@kde.org>
 * Konstantin Podsvirov <konstantin@podsvirov.pro>
+* Laurent Montel <montel@kde.org>
 * Mario Bensi <mbensi@ipsquad.net>
 * Martin Gräßlin <mgraesslin@kde.org>
 * Mathieu Malaterre <mathieu.malaterre@gmail.com>
index 3f0226f..1297cd0 100644 (file)
@@ -1,11 +1,12 @@
 
-When a device link step is involved, which is controlled by
-:prop_tgt:`CUDA_SEPARABLE_COMPILATION` and
-:prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and policy :policy:`CMP0105`,
-the raw options will be delivered to the host and device link steps (wrapped in
-``-Xcompiler`` or equivalent for device link). Options wrapped with
-``$<DEVICE_LINK:...>``
-:manual:`generator expression <cmake-generator-expressions(7)>` will be used
-only for the device link step. Options wrapped with ``$<HOST_LINK:...>``
-:manual:`generator expression <cmake-generator-expressions(7)>` will be used
-only for the host link step.
+.. versionadded:: 3.18
+  When a device link step is involved, which is controlled by
+  :prop_tgt:`CUDA_SEPARABLE_COMPILATION` and
+  :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and policy :policy:`CMP0105`,
+  the raw options will be delivered to the host and device link steps (wrapped in
+  ``-Xcompiler`` or equivalent for device link). Options wrapped with
+  ``$<DEVICE_LINK:...>``
+  :manual:`generator expression <cmake-generator-expressions(7)>` will be used
+  only for the device link step. Options wrapped with ``$<HOST_LINK:...>``
+  :manual:`generator expression <cmake-generator-expressions(7)>` will be used
+  only for the host link step.
index 4a62c5b..97eecfc 100644 (file)
@@ -33,9 +33,6 @@ of this command.
 If the |SEARCH_XXX| is found the result is stored in the variable
 and the search will not be repeated unless the variable is cleared.
 If nothing is found, the result will be ``<VAR>-NOTFOUND``.
-The ``REQUIRED`` option stops processing with an error message if nothing
-is found, otherwise the search will be attempted again the
-next time |FIND_XXX| is invoked with the same variable.
 
 Options include:
 
@@ -60,7 +57,11 @@ Options include:
   Specify the documentation string for the ``<VAR>`` cache entry.
 
 ``REQUIRED``
-  Stop processing with an error message if nothing is found.
+  .. versionadded:: 3.18
+
+  Stop processing with an error message if nothing is found, otherwise
+  the search will be attempted again the next time |FIND_XXX| is invoked
+  with the same variable.
 
 If ``NO_DEFAULT_PATH`` is specified, then no additional paths are
 added to the search.
@@ -84,20 +85,21 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
    |prefix_XXX_SUBDIR| for each ``<prefix>`` in
    :variable:`CMAKE_SYSTEM_PREFIX_PATH`
 
-1. If called from within a find module or any other script loaded by a call to
-   :command:`find_package(<PackageName>)`, search prefixes unique to the
-   current package being found.  Specifically, look in the
-   :variable:`<PackageName>_ROOT` CMake variable and the
-   :envvar:`<PackageName>_ROOT` environment variable.
-   The package root variables are maintained as a stack, so if called from
-   nested find modules or config packages, root paths from the parent's find
-   module or config package will be searched after paths from the current
-   module or package.  In other words, the search order would be
-   ``<CurrentPackage>_ROOT``, ``ENV{<CurrentPackage>_ROOT}``,
-   ``<ParentPackage>_ROOT``, ``ENV{<ParentPackage>_ROOT}``, etc.
-   This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed or by setting
-   the :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` to ``FALSE``.
-   See policy :policy:`CMP0074`.
+1. .. versionadded:: 3.12
+    If called from within a find module or any other script loaded by a call to
+    :command:`find_package(<PackageName>)`, search prefixes unique to the
+    current package being found.  Specifically, look in the
+    :variable:`<PackageName>_ROOT` CMake variable and the
+    :envvar:`<PackageName>_ROOT` environment variable.
+    The package root variables are maintained as a stack, so if called from
+    nested find modules or config packages, root paths from the parent's find
+    module or config package will be searched after paths from the current
+    module or package.  In other words, the search order would be
+    ``<CurrentPackage>_ROOT``, ``ENV{<CurrentPackage>_ROOT}``,
+    ``<ParentPackage>_ROOT``, ``ENV{<ParentPackage>_ROOT}``, etc.
+    This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed or by setting
+    the :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` to ``FALSE``.
+    See policy :policy:`CMP0074`.
 
    * |FIND_PACKAGE_ROOT_PREFIX_PATH_XXX|
 
@@ -151,6 +153,10 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
    or in the short-hand version of the command.
    These are typically hard-coded guesses.
 
+.. versionadded:: 3.16
+  Added ``CMAKE_FIND_USE_<CATEGORY>_PATH`` variables to globally disable
+  various search locations.
+
 .. |FIND_ARGS_XXX| replace:: <VAR> NAMES name
 
 On macOS the :variable:`CMAKE_FIND_FRAMEWORK` and
index 0f8ec32..4051ffe 100644 (file)
@@ -1,9 +1,11 @@
 The final set of compile or link options used for a target is constructed by
 accumulating options from the current target and the usage requirements of
 its dependencies.  The set of options is de-duplicated to avoid repetition.
-While beneficial for individual options, the de-duplication step can break
-up option groups.  For example, ``-D A -D B`` becomes ``-D A B``.  One may
-specify a group of options using shell-like quoting along with a ``SHELL:``
-prefix.  The ``SHELL:`` prefix is dropped, and the rest of the option string
-is parsed using the :command:`separate_arguments` ``UNIX_COMMAND`` mode.
-For example, ``"SHELL:-D A" "SHELL:-D B"`` becomes ``-D A -D B``.
+
+.. versionadded:: 3.12
+  While beneficial for individual options, the de-duplication step can break
+  up option groups.  For example, ``-D A -D B`` becomes ``-D A B``.  One may
+  specify a group of options using shell-like quoting along with a ``SHELL:``
+  prefix.  The ``SHELL:`` prefix is dropped, and the rest of the option string
+  is parsed using the :command:`separate_arguments` ``UNIX_COMMAND`` mode.
+  For example, ``"SHELL:-D A" "SHELL:-D B"`` becomes ``-D A -D B``.
index 231f9da..183bb72 100644 (file)
@@ -46,11 +46,19 @@ The options are:
   Append the ``COMMAND`` and ``DEPENDS`` option values to the custom
   command for the first output specified.  There must have already
   been a previous call to this command with the same output.
+
+  If the previous call specified the output via a generator expression,
+  the output specified by the current call must match in at least one
+  configuration after evaluating generator expressions.  In this case,
+  the appended commands and dependencies apply to all configurations.
+
   The ``COMMENT``, ``MAIN_DEPENDENCY``, and ``WORKING_DIRECTORY``
   options are currently ignored when APPEND is given, but may be
   used in the future.
 
 ``BYPRODUCTS``
+  .. versionadded:: 3.2
+
   Specify the files the command is expected to produce but whose
   modification time may or may not be newer than the dependencies.
   If a byproduct name is a relative path it will be interpreted
@@ -71,6 +79,10 @@ The options are:
   The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
   :prop_sf:`GENERATED` files during ``make clean``.
 
+  .. versionadded:: 3.20
+    Arguments to ``BYPRODUCTS`` may use
+    :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
 ``COMMAND``
   Specify the command-line(s) to execute at build time.
   If more than one ``COMMAND`` is specified they will be executed in order,
@@ -88,18 +100,19 @@ The options are:
 
   * The target is not being cross-compiled (i.e. the
     :variable:`CMAKE_CROSSCOMPILING` variable is not set to true).
-  * The target is being cross-compiled and an emulator is provided (i.e.
-    its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
-    In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
-    prepended to the command before the location of the target executable.
+  * .. versionadded:: 3.6
+      The target is being cross-compiled and an emulator is provided (i.e.
+      its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
+      In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
+      prepended to the command before the location of the target executable.
 
   If neither of the above conditions are met, it is assumed that the
   command name is a program to be found on the ``PATH`` at build time.
 
   Arguments to ``COMMAND`` may use
   :manual:`generator expressions <cmake-generator-expressions(7)>`.
-  Use the ``TARGET_FILE`` generator expression to refer to the location of
-  a target later in the command line (i.e. as a command argument rather
+  Use the :genex:`TARGET_FILE` generator expression to refer to the location
+  of a target later in the command line (i.e. as a command argument rather
   than as the command to execute).
 
   Whenever one of the following target based generator expressions are used as
@@ -153,18 +166,23 @@ The options are:
   If any dependency is an ``OUTPUT`` of another custom command in the same
   directory (``CMakeLists.txt`` file), CMake automatically brings the other
   custom command into the target in which this command is built.
-  A target-level dependency is added if any dependency is listed as
-  ``BYPRODUCTS`` of a target or any of its build events in the same
-  directory to ensure the byproducts will be available.
+
+  .. versionadded:: 3.16
+    A target-level dependency is added if any dependency is listed as
+    ``BYPRODUCTS`` of a target or any of its build events in the same
+    directory to ensure the byproducts will be available.
 
   If ``DEPENDS`` is not specified, the command will run whenever
   the ``OUTPUT`` is missing; if the command does not actually
   create the ``OUTPUT``, the rule will always run.
 
-  Arguments to ``DEPENDS`` may use
-  :manual:`generator expressions <cmake-generator-expressions(7)>`.
+  .. versionadded:: 3.1
+    Arguments to ``DEPENDS`` may use
+    :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
 ``COMMAND_EXPAND_LISTS``
+  .. versionadded:: 3.8
+
   Lists in ``COMMAND`` arguments will be expanded, including those
   created with
   :manual:`generator expressions <cmake-generator-expressions(7)>`,
@@ -183,7 +201,13 @@ The options are:
   Note that the ``IMPLICIT_DEPENDS`` option is currently supported
   only for Makefile generators and will be ignored by other generators.
 
+  .. note::
+
+    This option cannot be specified at the same time as ``DEPFILE`` option.
+
 ``JOB_POOL``
+  .. versionadded:: 3.15
+
   Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
   generator. Incompatible with ``USES_TERMINAL``, which implies
   the ``console`` pool.
@@ -210,7 +234,13 @@ The options are:
   as a file on disk it should be marked with the :prop_sf:`SYMBOLIC`
   source file property.
 
+  .. versionadded:: 3.20
+    Arguments to ``OUTPUT`` may use
+    :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
 ``USES_TERMINAL``
+  .. versionadded:: 3.2
+
   The command will be given direct access to the terminal if possible.
   With the :generator:`Ninja` generator, this places the command in
   the ``console`` :prop_gbl:`pool <JOB_POOLS>`.
@@ -230,14 +260,72 @@ The options are:
   If it is a relative path it will be interpreted relative to the
   build tree directory corresponding to the current source directory.
 
-  Arguments to ``WORKING_DIRECTORY`` may use
-  :manual:`generator expressions <cmake-generator-expressions(7)>`.
+  .. versionadded:: 3.13
+    Arguments to ``WORKING_DIRECTORY`` may use
+    :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
 ``DEPFILE``
-  Specify a ``.d`` depfile for the :generator:`Ninja` generator.
+  .. versionadded:: 3.7
+
+  Specify a ``.d`` depfile for the :generator:`Ninja` generator and
+  :ref:`Makefile Generators`.
   A ``.d`` file holds dependencies usually emitted by the custom
   command itself.
-  Using ``DEPFILE`` with other generators than Ninja is an error.
+  Using ``DEPFILE`` with other generators than :generator:`Ninja` or
+  :ref:`Makefile Generators` is an error.
+
+  .. versionadded:: 3.20
+    Added the support of :ref:`Makefile Generators`.
+
+  If the ``DEPFILE`` argument is relative, it should be relative to
+  :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
+  ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`
+  (see policy :policy:`CMP0116`. This policy is always ``NEW`` for
+  :ref:`Makefile Generators`).
+
+  .. note::
+
+    For :ref:`Makefile Generators`, this option cannot be specified at the
+    same time as ``IMPLICIT_DEPENDS`` option.
+
+Examples: Generating Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Custom commands may be used to generate source files.
+For example, the code:
+
+.. code-block:: cmake
+
+  add_custom_command(
+    OUTPUT out.c
+    COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+                     -o out.c
+    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+    VERBATIM)
+  add_library(myLib out.c)
+
+adds a custom command to run ``someTool`` to generate ``out.c`` and then
+compile the generated source as part of a library.  The generation rule
+will re-run whenever ``in.txt`` changes.
+
+.. versionadded:: 3.20
+  One may use generator expressions to specify per-configuration outputs.
+  For example, the code:
+
+  .. code-block:: cmake
+
+    add_custom_command(
+      OUTPUT "out-$<CONFIG>.c"
+      COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+                       -o "out-$<CONFIG>.c"
+                       -c "$<CONFIG>"
+      DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
+      VERBATIM)
+    add_library(myLib "out-$<CONFIG>.c")
+
+  adds a custom command to run ``someTool`` to generate ``out-<config>.c``,
+  where ``<config>`` is the build configuration, and then compile the generated
+  source as part of a library.
 
 Build Events
 ^^^^^^^^^^^^
@@ -288,3 +376,49 @@ of the following is specified:
   configuration and no "empty-string-command" will be added.
 
   This allows to add individual build events for every configuration.
+
+Examples: Build Events
+^^^^^^^^^^^^^^^^^^^^^^
+
+A ``POST_BUILD`` event may be used to post-process a binary after linking.
+For example, the code:
+
+.. code-block:: cmake
+
+  add_executable(myExe myExe.c)
+  add_custom_command(
+    TARGET myExe POST_BUILD
+    COMMAND someHasher -i "$<TARGET_FILE:myExe>"
+                       -o "$<TARGET_FILE:myExe>.hash"
+    VERBATIM)
+
+will run ``someHasher`` to produce a ``.hash`` file next to the executable
+after linking.
+
+.. versionadded:: 3.20
+  One may use generator expressions to specify per-configuration byproducts.
+  For example, the code:
+
+  .. code-block:: cmake
+
+    add_library(myPlugin MODULE myPlugin.c)
+    add_custom_command(
+      TARGET myPlugin POST_BUILD
+      COMMAND someHasher -i "$<TARGET_FILE:myPlugin>"
+                         --as-code "myPlugin-hash-$<CONFIG>.c"
+      BYPRODUCTS "myPlugin-hash-$<CONFIG>.c"
+      VERBATIM)
+    add_executable(myExe myExe.c "myPlugin-hash-$<CONFIG>.c")
+
+  will run ``someHasher`` after linking ``myPlugin``, e.g. to produce a ``.c``
+  file containing code to check the hash of ``myPlugin`` that the ``myExe``
+  executable can use to verify it before loading.
+
+Ninja Multi-Config
+^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+  ``add_custom_command`` supports the :generator:`Ninja Multi-Config`
+  generator's cross-config capabilities. See the generator documentation
+  for more information.
index 2eb0c88..22d3f29 100644 (file)
@@ -32,6 +32,8 @@ The options are:
   called ``ALL``).
 
 ``BYPRODUCTS``
+  .. versionadded:: 3.2
+
   Specify the files the command is expected to produce but whose
   modification time may or may not be updated on subsequent builds.
   If a byproduct name is a relative path it will be interpreted
@@ -52,6 +54,10 @@ The options are:
   The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
   :prop_sf:`GENERATED` files during ``make clean``.
 
+  .. versionadded:: 3.20
+    Arguments to ``BYPRODUCTS`` may use
+    :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
 ``COMMAND``
   Specify the command-line(s) to execute at build time.
   If more than one ``COMMAND`` is specified they will be executed in order,
@@ -67,18 +73,19 @@ The options are:
 
   * The target is not being cross-compiled (i.e. the
     :variable:`CMAKE_CROSSCOMPILING` variable is not set to true).
-  * The target is being cross-compiled and an emulator is provided (i.e.
-    its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
-    In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
-    prepended to the command before the location of the target executable.
+  * .. versionadded:: 3.6
+      The target is being cross-compiled and an emulator is provided (i.e.
+      its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
+      In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
+      prepended to the command before the location of the target executable.
 
   If neither of the above conditions are met, it is assumed that the
   command name is a program to be found on the ``PATH`` at build time.
 
   Arguments to ``COMMAND`` may use
   :manual:`generator expressions <cmake-generator-expressions(7)>`.
-  Use the ``TARGET_FILE`` generator expression to refer to the location of
-  a target later in the command line (i.e. as a command argument rather
+  Use the :genex:`TARGET_FILE` generator expression to refer to the location
+  of a target later in the command line (i.e. as a command argument rather
   than as the command to execute).
 
   Whenever one of the following target based generator expressions are used as
@@ -103,14 +110,18 @@ The options are:
   :command:`add_custom_command` command calls in the same directory
   (``CMakeLists.txt`` file).  They will be brought up to date when
   the target is built.
-  A target-level dependency is added if any dependency is a byproduct
-  of a target or any of its build events in the same directory to ensure
-  the byproducts will be available before this target is built.
+
+  .. versionchanged:: 3.16
+    A target-level dependency is added if any dependency is a byproduct
+    of a target or any of its build events in the same directory to ensure
+    the byproducts will be available before this target is built.
 
   Use the :command:`add_dependencies` command to add dependencies
   on other targets.
 
 ``COMMAND_EXPAND_LISTS``
+  .. versionadded:: 3.8
+
   Lists in ``COMMAND`` arguments will be expanded, including those
   created with
   :manual:`generator expressions <cmake-generator-expressions(7)>`,
@@ -119,6 +130,8 @@ The options are:
   to be properly expanded.
 
 ``JOB_POOL``
+  .. versionadded:: 3.15
+
   Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
   generator. Incompatible with ``USES_TERMINAL``, which implies
   the ``console`` pool.
@@ -141,6 +154,8 @@ The options are:
   tool-specific special characters.
 
 ``USES_TERMINAL``
+  .. versionadded:: 3.2
+
   The command will be given direct access to the terminal if possible.
   With the :generator:`Ninja` generator, this places the command in
   the ``console`` :prop_gbl:`pool <JOB_POOLS>`.
@@ -150,5 +165,15 @@ The options are:
   If it is a relative path it will be interpreted relative to the
   build tree directory corresponding to the current source directory.
 
-  Arguments to ``WORKING_DIRECTORY`` may use
-  :manual:`generator expressions <cmake-generator-expressions(7)>`.
+  .. versionadded:: 3.13
+    Arguments to ``WORKING_DIRECTORY`` may use
+    :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+Ninja Multi-Config
+^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+  ``add_custom_target`` supports the :generator:`Ninja Multi-Config`
+  generator's cross-config capabilities. See the generator documentation
+  for more information.
index de219a5..14c0183 100644 (file)
@@ -17,6 +17,9 @@ Dependencies added to an :ref:`imported target <Imported Targets>`
 or an :ref:`interface library <Interface Libraries>` are followed
 transitively in its place since the target itself does not build.
 
+.. versionadded:: 3.3
+  Allow adding dependencies to interface libraries.
+
 See the ``DEPENDS`` option of :command:`add_custom_target` and
 :command:`add_custom_command` commands for adding file-level
 dependencies in custom rules.  See the :prop_sf:`OBJECT_DEPENDS`
index e073228..dde9429 100644 (file)
@@ -17,13 +17,21 @@ Normal Executables
                  [source1] [source2 ...])
 
 Adds an executable target called ``<name>`` to be built from the source
-files listed in the command invocation.  (The source files can be omitted
-here if they are added later using :command:`target_sources`.)  The
+files listed in the command invocation.  The
 ``<name>`` corresponds to the logical target name and must be globally
 unique within a project.  The actual file name of the executable built is
 constructed based on conventions of the native platform (such as
 ``<name>.exe`` or just ``<name>``).
 
+.. versionadded:: 3.1
+  Source arguments to ``add_executable`` may use "generator expressions" with
+  the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+  manual for available expressions.
+
+.. versionadded:: 3.11
+  The source files can be omitted if they are added later using
+  :command:`target_sources`.
+
 By default the executable file will be created in the build tree
 directory corresponding to the source tree directory in which the
 command was invoked.  See documentation of the
@@ -43,10 +51,8 @@ If ``EXCLUDE_FROM_ALL`` is given the corresponding property will be set on
 the created target.  See documentation of the :prop_tgt:`EXCLUDE_FROM_ALL`
 target property for details.
 
-Source arguments to ``add_executable`` may use "generator expressions" with
-the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
-manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
-manual for more on defining buildsystem properties.
+See the :manual:`cmake-buildsystem(7)` manual for more on defining
+buildsystem properties.
 
 See also :prop_sf:`HEADER_FILE_ONLY` on what to do if some sources are
 pre-processed, and you want to have the original sources reachable from
@@ -85,10 +91,14 @@ be used to refer to ``<target>`` in subsequent commands.  The ``<name>``
 does not appear in the generated buildsystem as a make target.  The
 ``<target>`` may not be an ``ALIAS``.
 
-An ``ALIAS`` to a non-``GLOBAL`` :ref:`Imported Target <Imported Targets>`
-has scope in the directory in which the alias is created and below.
-The :prop_tgt:`ALIAS_GLOBAL` target property can be used to check if the
-alias is global or not.
+.. versionadded:: 3.11
+  An ``ALIAS`` can target a ``GLOBAL`` :ref:`Imported Target <Imported Targets>`
+
+.. versionadded:: 3.18
+  An ``ALIAS`` can target a non-``GLOBAL`` Imported Target. Such alias is
+  scoped to the directory in which it is created and subdirectories.
+  The :prop_tgt:`ALIAS_GLOBAL` target property can be used to check if the
+  alias is global or not.
 
 ``ALIAS`` targets can be used as targets to read properties
 from, executables for custom commands and custom targets.  They can also be
index b7dfabc..d3fbdcf 100644 (file)
@@ -17,13 +17,21 @@ Normal Libraries
               [<source>...])
 
 Adds a library target called ``<name>`` to be built from the source files
-listed in the command invocation.  (The source files can be omitted here
-if they are added later using :command:`target_sources`.)  The ``<name>``
+listed in the command invocation.  The ``<name>``
 corresponds to the logical target name and must be globally unique within
 a project.  The actual file name of the library built is constructed based
 on conventions of the native platform (such as ``lib<name>.a`` or
 ``<name>.lib``).
 
+.. versionadded:: 3.1
+  Source arguments to ``add_library`` may use "generator expressions" with
+  the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+  manual for available expressions.
+
+.. versionadded:: 3.11
+  The source files can be omitted if they are added later using
+  :command:`target_sources`.
+
 ``STATIC``, ``SHARED``, or ``MODULE`` may be given to specify the type of
 library to be created.  ``STATIC`` libraries are archives of object files
 for use when linking other targets.  ``SHARED`` libraries are linked
@@ -34,9 +42,13 @@ type is ``STATIC`` or ``SHARED`` based on whether the current value of the
 variable :variable:`BUILD_SHARED_LIBS` is ``ON``.  For ``SHARED`` and
 ``MODULE`` libraries the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
 property is set to ``ON`` automatically.
-A ``SHARED`` or ``STATIC`` library may be marked with the :prop_tgt:`FRAMEWORK`
+A ``SHARED`` library may be marked with the :prop_tgt:`FRAMEWORK`
 target property to create an macOS Framework.
 
+.. versionadded:: 3.8
+  A ``STATIC`` library may be marked with the :prop_tgt:`FRAMEWORK`
+  target property to create a static Framework.
+
 If a library does not export any symbols, it must not be declared as a
 ``SHARED`` library.  For example, a Windows resource DLL or a managed C++/CLI
 DLL that exports no unmanaged symbols would need to be a ``MODULE`` library.
@@ -55,10 +67,8 @@ If ``EXCLUDE_FROM_ALL`` is given the corresponding property will be set on
 the created target.  See documentation of the :prop_tgt:`EXCLUDE_FROM_ALL`
 target property for details.
 
-Source arguments to ``add_library`` may use "generator expressions" with
-the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
-manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
-manual for more on defining buildsystem properties.
+See the :manual:`cmake-buildsystem(7)` manual for more on defining
+buildsystem properties.
 
 See also :prop_sf:`HEADER_FILE_ONLY` on what to do if some sources are
 pre-processed, and you want to have the original sources reachable from
@@ -93,6 +103,9 @@ systems (such as Xcode) may not like targets that have only object files, so
 consider adding at least one real source file to any target that references
 ``$<TARGET_OBJECTS:objlib>``.
 
+.. versionadded:: 3.12
+  Object libraries can be linked to with :command:`target_link_libraries`.
+
 Interface Libraries
 ^^^^^^^^^^^^^^^^^^^
 
@@ -121,23 +134,28 @@ like any other target.
 An interface library created with the above signature has no source files
 itself and is not included as a target in the generated buildsystem.
 
-Since CMake 3.19, an interface library target may be created with
-source files:
+.. versionadded:: 3.15
+  An interface library can have :prop_tgt:`PUBLIC_HEADER` and
+  :prop_tgt:`PRIVATE_HEADER` properties.  The headers specified by those
+  properties can be installed using the :command:`install(TARGETS)` command.
 
-.. code-block:: cmake
+.. versionadded:: 3.19
+  An interface library target may be created with source files:
+
+  .. code-block:: cmake
 
-  add_library(<name> INTERFACE [<source>...] [EXCLUDE_FROM_ALL])
+    add_library(<name> INTERFACE [<source>...] [EXCLUDE_FROM_ALL])
 
-Source files may be listed directly in the ``add_library`` call or added
-later by calls to :command:`target_sources` with the ``PRIVATE`` or
-``PUBLIC`` keywords.
+  Source files may be listed directly in the ``add_library`` call or added
+  later by calls to :command:`target_sources` with the ``PRIVATE`` or
+  ``PUBLIC`` keywords.
 
-If an interface library has source files (i.e. the :prop_tgt:`SOURCES`
-target property is set), it will appear in the generated buildsystem
-as a build target much like a target defined by the
-:command:`add_custom_target` command.  It does not compile any sources,
-but does contain build rules for custom commands created by the
-:command:`add_custom_command` command.
+  If an interface library has source files (i.e. the :prop_tgt:`SOURCES`
+  target property is set), it will appear in the generated buildsystem
+  as a build target much like a target defined by the
+  :command:`add_custom_target` command.  It does not compile any sources,
+  but does contain build rules for custom commands created by the
+  :command:`add_custom_command` command.
 
 .. note::
   In most command signatures where the ``INTERFACE`` keyword appears,
@@ -211,10 +229,14 @@ used to refer to ``<target>`` in subsequent commands.  The ``<name>`` does
 not appear in the generated buildsystem as a make target.  The ``<target>``
 may not be an ``ALIAS``.
 
-An ``ALIAS`` to a non-``GLOBAL`` :ref:`Imported Target <Imported Targets>`
-has scope in the directory in which the alias is created and below.
-The :prop_tgt:`ALIAS_GLOBAL` target property can be used to check if the
-alias is global or not.
+.. versionadded:: 3.11
+  An ``ALIAS`` can target a ``GLOBAL`` :ref:`Imported Target <Imported Targets>`
+
+.. versionadded:: 3.18
+  An ``ALIAS`` can target a non-``GLOBAL`` Imported Target. Such alias is
+  scoped to the directory in which it is created and below.
+  The :prop_tgt:`ALIAS_GLOBAL` target property can be used to check if the
+  alias is global or not.
 
 ``ALIAS`` targets can be used as linkable targets and as targets to
 read properties from.  They can also be tested for existence with the
index 2b4d082..95cd037 100644 (file)
@@ -31,6 +31,8 @@ if necessary.  See policy :policy:`CMP0110`.  The options are:
   current source directory.
 
 ``COMMAND_EXPAND_LISTS``
+  .. versionadded:: 3.16
+
   Lists in ``COMMAND`` arguments will be expanded, including those
   created with
   :manual:`generator expressions <cmake-generator-expressions(7)>`.
@@ -43,6 +45,9 @@ unless the :prop_test:`PASS_REGULAR_EXPRESSION`,
 :prop_test:`FAIL_REGULAR_EXPRESSION` or
 :prop_test:`SKIP_REGULAR_EXPRESSION` test property is used.
 
+.. versionadded:: 3.16
+  Added :prop_test:`SKIP_REGULAR_EXPRESSION` property.
+
 The ``COMMAND`` and ``WORKING_DIRECTORY`` options may use "generator
 expressions" with the syntax ``$<...>``.  See the
 :manual:`cmake-generator-expressions(7)` manual for available expressions.
@@ -52,7 +57,7 @@ Example usage:
 .. code-block:: cmake
 
   add_test(NAME mytest
-           COMMAND testDriver --config $<CONFIGURATION>
+           COMMAND testDriver --config $<CONFIG>
                               --exe $<TARGET_FILE:myexe>)
 
 This creates a test ``mytest`` whose command runs a ``testDriver`` tool
index 2e9563a..2b902a9 100644 (file)
@@ -24,6 +24,14 @@ Key                           Description
 ``AVAILABLE_VIRTUAL_MEMORY``  Available virtual memory in MiB [#mebibytes]_
 ``TOTAL_PHYSICAL_MEMORY``     Total physical memory in MiB [#mebibytes]_
 ``AVAILABLE_PHYSICAL_MEMORY`` Available physical memory in MiB [#mebibytes]_
+============================= ================================================
+
+.. versionadded:: 3.10
+  Additional ``<key>`` values are available:
+
+============================= ================================================
+Key                           Description
+============================= ================================================
 ``IS_64BIT``                  One if processor is 64Bit
 ``HAS_FPU``                   One if processor has floating point unit
 ``HAS_MMX``                   One if processor supports MMX instructions
index f3326b8..c3b3e73 100644 (file)
@@ -7,6 +7,9 @@ Require a minimum version of cmake.
 
   cmake_minimum_required(VERSION <min>[...<max>] [FATAL_ERROR])
 
+.. versionadded:: 3.12
+  The optional ``<max>`` version.
+
 Sets the minimum required version of cmake for a project.
 Also updates the policy settings as explained below.
 
index 8803ec8..7c85da6 100644 (file)
@@ -1,8 +1,6 @@
 cmake_parse_arguments
 ---------------------
 
-.. versionadded:: 3.5
-
 Parse function or macro arguments.
 
 .. code-block:: cmake
@@ -13,6 +11,10 @@ Parse function or macro arguments.
   cmake_parse_arguments(PARSE_ARGV <N> <prefix> <options>
                         <one_value_keywords> <multi_value_keywords>)
 
+.. versionadded:: 3.5
+  This command is implemented natively.  Previously, it has been defined in the
+  module :module:`CMakeParseArguments`.
+
 This command is for use in macros or functions.
 It processes the arguments given to that macro or function,
 and defines a set of variables which hold the values of the
@@ -21,11 +23,12 @@ respective options.
 The first signature reads processes arguments passed in the ``<args>...``.
 This may be used in either a :command:`macro` or a :command:`function`.
 
-The ``PARSE_ARGV`` signature is only for use in a :command:`function`
-body.  In this case the arguments that are parsed come from the
-``ARGV#`` variables of the calling function.  The parsing starts with
-the ``<N>``-th argument, where ``<N>`` is an unsigned integer.  This allows for
-the values to have special characters like ``;`` in them.
+.. versionadded:: 3.7
+  The ``PARSE_ARGV`` signature is only for use in a :command:`function`
+  body.  In this case the arguments that are parsed come from the
+  ``ARGV#`` variables of the calling function.  The parsing starts with
+  the ``<N>``-th argument, where ``<N>`` is an unsigned integer.
+  This allows for the values to have special characters like ``;`` in them.
 
 The ``<options>`` argument contains all options for the respective macro,
 i.e.  keywords which can be used when calling the macro without any value
@@ -40,12 +43,11 @@ The ``<multi_value_keywords>`` argument contains all keywords for this
 macro which can be followed by more than one value, like e.g. the
 ``TARGETS`` or ``FILES`` keywords of the :command:`install` command.
 
-.. note::
-
-   All keywords shall be unique. I.e. every keyword shall only be specified
-   once in either ``<options>``, ``<one_value_keywords>`` or
-   ``<multi_value_keywords>``. A warning will be emitted if uniqueness is
-   violated.
+.. versionchanged:: 3.5
+  All keywords shall be unique. I.e. every keyword shall only be specified
+  once in either ``<options>``, ``<one_value_keywords>`` or
+  ``<multi_value_keywords>``. A warning will be emitted if uniqueness is
+  violated.
 
 When done, ``cmake_parse_arguments`` will consider for each of the
 keywords listed in ``<options>``, ``<one_value_keywords>`` and
@@ -61,10 +63,12 @@ All remaining arguments are collected in a variable
 were recognized. This can be checked afterwards to see
 whether your macro was called with unrecognized parameters.
 
-``<one_value_keywords>`` and ``<multi_value_keywords>`` that were given no
-values at all are collected in a variable ``<prefix>_KEYWORDS_MISSING_VALUES``
-that will be undefined if all keywords received values. This can be checked
-to see if there were keywords without any values given.
+.. versionadded:: 3.15
+   ``<one_value_keywords>`` and ``<multi_value_keywords>`` that were given no
+   values at all are collected in a variable
+   ``<prefix>_KEYWORDS_MISSING_VALUES`` that will be undefined if all keywords
+   received values. This can be checked to see if there were keywords without
+   any values given.
 
 Consider the following example macro, ``my_install()``, which takes similar
 arguments to the real :command:`install` command:
diff --git a/Help/command/cmake_path.rst b/Help/command/cmake_path.rst
new file mode 100644 (file)
index 0000000..a8999f3
--- /dev/null
@@ -0,0 +1,784 @@
+cmake_path
+----------
+
+.. versionadded:: 3.20
+
+This command is for the manipulation of paths.  Only syntactic aspects of
+paths are handled, there is no interaction of any kind with any underlying
+file system.  The path may represent a non-existing path or even one that
+is not allowed to exist on the current file system or platform.
+For operations that do interact with the filesystem, see the :command:`file`
+command.
+
+.. note::
+
+  The ``cmake_path`` command handles paths in the format of the build system
+  (i.e. the host platform), not the target system.  When cross-compiling,
+  if the path contains elements that are not representable on the host
+  platform (e.g. a drive letter when the host is not Windows), the results
+  will be unpredictable.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+  `Conventions`_
+
+  `Path Structure And Terminology`_
+
+  `Normalization`_
+
+  `Decomposition`_
+    cmake_path(`GET`_ <path-var> :ref:`ROOT_NAME <GET_ROOT_NAME>` <out-var>)
+    cmake_path(`GET`_ <path-var> :ref:`ROOT_DIRECTORY <GET_ROOT_DIRECTORY>` <out-var>)
+    cmake_path(`GET`_ <path-var> :ref:`ROOT_PATH <GET_ROOT_PATH>` <out-var>)
+    cmake_path(`GET`_ <path-var> :ref:`FILENAME <GET_FILENAME>` <out-var>)
+    cmake_path(`GET`_ <path-var> :ref:`EXTENSION <GET_EXTENSION>` [LAST_ONLY] <out-var>)
+    cmake_path(`GET`_ <path-var> :ref:`STEM <GET_STEM>` [LAST_ONLY] <out-var>)
+    cmake_path(`GET`_ <path-var> :ref:`RELATIVE_PART <GET_RELATIVE_PART>` <out-var>)
+    cmake_path(`GET`_ <path-var> :ref:`PARENT_PATH <GET_PARENT_PATH>` <out-var>)
+
+  `Query`_
+    cmake_path(`HAS_ROOT_NAME`_ <path-var> <out-var>)
+    cmake_path(`HAS_ROOT_DIRECTORY`_ <path-var> <out-var>)
+    cmake_path(`HAS_ROOT_PATH`_ <path-var> <out-var>)
+    cmake_path(`HAS_FILENAME`_ <path-var> <out-var>)
+    cmake_path(`HAS_EXTENSION`_ <path-var> <out-var>)
+    cmake_path(`HAS_STEM`_ <path-var> <out-var>)
+    cmake_path(`HAS_RELATIVE_PART`_ <path-var> <out-var>)
+    cmake_path(`HAS_PARENT_PATH`_ <path-var> <out-var>)
+    cmake_path(`IS_ABSOLUTE`_ <path-var> <out-var>)
+    cmake_path(`IS_RELATIVE`_ <path-var> <out-var>)
+    cmake_path(`IS_PREFIX`_ <path-var> <input> [NORMALIZE] <out-var>)
+    cmake_path(`COMPARE`_ <input1> <OP> <input2> <out-var>)
+
+  `Modification`_
+    cmake_path(:ref:`SET <cmake_path-SET>` <path-var> [NORMALIZE] <input>)
+    cmake_path(`APPEND`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+    cmake_path(`APPEND_STRING`_ <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+    cmake_path(`REMOVE_FILENAME`_ <path-var> [OUTPUT_VARIABLE <out-var>])
+    cmake_path(`REPLACE_FILENAME`_ <path-var> <input> [OUTPUT_VARIABLE <out-var>])
+    cmake_path(`REMOVE_EXTENSION`_ <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>])
+    cmake_path(`REPLACE_EXTENSION`_ <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>])
+
+  `Generation`_
+    cmake_path(`NORMAL_PATH`_ <path-var> [OUTPUT_VARIABLE <out-var>])
+    cmake_path(`RELATIVE_PATH`_ <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>])
+    cmake_path(`ABSOLUTE_PATH`_ <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>])
+
+  `Native Conversion`_
+    cmake_path(`NATIVE_PATH`_ <path-var> [NORMALIZE] <out-var>)
+    cmake_path(`CONVERT`_ <input> `TO_CMAKE_PATH_LIST`_ <out-var>)
+    cmake_path(`CONVERT`_ <input> `TO_NATIVE_PATH_LIST`_ <out-var>)
+
+  `Hashing`_
+    cmake_path(`HASH`_ <path-var> <out-var>)
+
+Conventions
+^^^^^^^^^^^
+
+The following conventions are used in this command's documentation:
+
+``<path-var>``
+  Always the name of a variable.  For commands that expect a ``<path-var>``
+  as input, the variable must exist and it is expected to hold a single path.
+
+``<input>``
+  A string literal which may contain a path, path fragment, or multiple paths
+  with a special separator depending on the command.  See the description of
+  each command to see how this is interpreted.
+
+``<input>...``
+  Zero or more string literal arguments.
+
+``<out-var>``
+  The name of a variable into which the result of a command will be written.
+
+
+Path Structure And Terminology
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A path has the following structure (all components are optional, with some
+constraints):
+
+::
+
+  root-name root-directory-separator (item-name directory-separator)* filename
+
+``root-name``
+  Identifies the root on a filesystem with multiple roots (such as ``"C:"``
+  or ``"//myserver"``). It is optional.
+
+``root-directory-separator``
+  A directory separator that, if present, indicates that this path is
+  absolute.  If it is missing and the first element other than the
+  ``root-name`` is an ``item-name``, then the path is relative.
+
+``item-name``
+  A sequence of characters that aren't directory separators.  This name may
+  identify a file, a hard link, a symbolic link, or a directory.  Two special
+  cases are recognized:
+
+    * The item name consisting of a single dot character ``.`` is a
+      directory name that refers to the current directory.
+
+    * The item name consisting of two dot characters ``..`` is a
+      directory name that refers to the parent directory.
+
+  The ``(...)*`` pattern shown above is to indicate that there can be zero
+  or more item names, with multiple items separated by a
+  ``directory-separator``.  The ``()*`` characters are not part of the path.
+
+``directory-separator``
+  The only recognized directory separator is a forward slash character ``/``.
+  If this character is repeated, it is treated as a single directory
+  separator.  In other words, ``/usr///////lib`` is the same as ``/usr/lib``.
+
+.. _FILENAME_DEF:
+.. _EXTENSION_DEF:
+.. _STEM_DEF:
+
+``filename``
+  A path has a ``filename`` if it does not end with a ``directory-separator``.
+  The ``filename`` is effectively the last ``item-name`` of the path, so it
+  can also be a hard link, symbolic link or a directory.
+
+  A ``filename`` can have an *extension*.  By default, the extension is
+  defined as the sub-string beginning at the left-most period (including
+  the period) and until the end of the ``filename``.  In commands that
+  accept a ``LAST_ONLY`` keyword, ``LAST_ONLY`` changes the interpretation
+  to the sub-string beginning at the right-most period.
+
+  The following exceptions apply to the above interpretation:
+
+    * If the first character in the ``filename`` is a period, that period is
+      ignored (i.e. a ``filename`` like ``".profile"`` is treated as having
+      no extension).
+
+    * If the ``filename`` is either ``.`` or ``..``, it has no extension.
+
+  The *stem* is the part of the ``filename`` before the extension.
+
+Some commands refer to a ``root-path``.  This is the concatenation of
+``root-name`` and ``root-directory-separator``, either or both of which can
+be empty.  A ``relative-part`` refers to the full path with any ``root-path``
+removed.
+
+
+Creating A Path Variable
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+While a path can be created with care using an ordinary :command:`set`
+command, it is recommended to use :ref:`cmake_path(SET) <cmake_path-SET>`
+instead, as it automatically converts the path to the required form where
+required.  The :ref:`cmake_path(APPEND) <APPEND>` subcommand may
+be another suitable alternative where a path needs to be constructed by
+joining fragments.  The following example compares the three methods for
+constructing the same path:
+
+.. code-block:: cmake
+
+  set(path1 "${CMAKE_CURRENT_SOURCE_DIR}/data")
+
+  cmake_path(SET path2 "${CMAKE_CURRENT_SOURCE_DIR}/data")
+
+  cmake_path(APPEND path3 "${CMAKE_CURRENT_SOURCE_DIR}" "data")
+
+`Modification`_ and `Generation`_ sub-commands can either store the result
+in-place, or in a separate variable named after an ``OUTPUT_VARIABLE``
+keyword.  All other sub-commands store the result in a mandatory ``<out-var>``
+variable.
+
+.. _Normalization:
+
+Normalization
+^^^^^^^^^^^^^
+
+Some sub-commands support *normalizing* a path.  The algorithm used to
+normalize a path is as follows:
+
+1. If the path is empty, stop (the normalized form of an empty path is
+   also an empty path).
+2. Replace each ``directory-separator``, which may consist of multiple
+   separators, with a single ``/`` (``/a///b  --> /a/b``).
+3. Remove each solitary period (``.``) and any immediately following
+   ``directory-separator`` (``/a/./b/. --> /a/b``).
+4. Remove each ``item-name`` (other than ``..``) that is immediately
+   followed by a ``directory-separator`` and a ``..``, along with any
+   immediately following ``directory-separator`` (``/a/b/../c --> a/c``).
+5. If there is a ``root-directory``, remove any ``..`` and any
+   ``directory-separators`` immediately following them.  The parent of the
+   root directory is treated as still the root directory (``/../a --> /a``).
+6. If the last ``item-name`` is ``..``, remove any trailing
+   ``directory-separator`` (``../ --> ..``).
+7. If the path is empty by this stage, add a ``dot`` (normal form of ``./``
+   is ``.``).
+
+
+Decomposition
+^^^^^^^^^^^^^
+
+.. _GET:
+.. _GET_ROOT_NAME:
+.. _GET_ROOT_DIRECTORY:
+.. _GET_ROOT_PATH:
+.. _GET_FILENAME:
+.. _GET_EXTENSION:
+.. _GET_STEM:
+.. _GET_RELATIVE_PART:
+.. _GET_PARENT_PATH:
+
+The following forms of the ``GET`` subcommand each retrieve a different
+component or group of components from a path.  See
+`Path Structure And Terminology`_ for the meaning of each path component.
+
+::
+
+  cmake_path(GET <path-var> ROOT_NAME <out-var>)
+  cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
+  cmake_path(GET <path-var> ROOT_PATH <out-var>)
+  cmake_path(GET <path-var> FILENAME <out-var>)
+  cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
+  cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
+  cmake_path(GET <path-var> RELATIVE_PART <out-var>)
+  cmake_path(GET <path-var> PARENT_PATH <out-var>)
+
+If a requested component is not present in the path, an empty string will be
+stored in ``<out-var>``.  For example, only Windows systems have the concept
+of a ``root-name``, so when the host machine is non-Windows, the ``ROOT_NAME``
+subcommand will always return an empty string.
+
+For ``PARENT_PATH``, if the `HAS_RELATIVE_PART`_ subcommand returns false,
+the result is a copy of ``<path-var>``.  Note that this implies that a root
+directory is considered to have a parent, with that parent being itself.
+Where `HAS_RELATIVE_PART`_ returns true, the result will essentially be
+``<path-var>`` with one less element.
+
+Root examples
+"""""""""""""
+
+.. code-block:: cmake
+
+  set(path "c:/a")
+
+  cmake_path(GET path ROOT_NAME rootName)
+  cmake_path(GET path ROOT_DIRECTORY rootDir)
+  cmake_path(GET path ROOT_PATH rootPath)
+
+  message("Root name is \"${rootName}\"")
+  message("Root directory is \"${rootDir}\"")
+  message("Root path is \"${rootPath}\"")
+
+::
+
+  Root name is "c:"
+  Root directory is "/"
+  Root path is "c:/"
+
+Filename examples
+"""""""""""""""""
+
+.. code-block:: cmake
+
+  set(path "/a/b")
+  cmake_path(GET path FILENAME filename)
+  message("First filename is \"${filename}\"")
+
+  # Trailing slash means filename is empty
+  set(path "/a/b/")
+  cmake_path(GET path FILENAME filename)
+  message("Second filename is \"${filename}\"")
+
+::
+
+  First filename is "b"
+  Second filename is ""
+
+Extension and stem examples
+"""""""""""""""""""""""""""
+
+.. code-block:: cmake
+
+  set(path "name.ext1.ext2")
+
+  cmake_path(GET path EXTENSION fullExt)
+  cmake_path(GET path STEM fullStem)
+  message("Full extension is \"${fullExt}\"")
+  message("Full stem is \"${fullStem}\"")
+
+  # Effect of LAST_ONLY
+  cmake_path(GET path EXTENSION LAST_ONLY lastExt)
+  cmake_path(GET path STEM LAST_ONLY lastStem)
+  message("Last extension is \"${lastExt}\"")
+  message("Last stem is \"${lastStem}\"")
+
+  # Special cases
+  set(dotPath "/a/.")
+  set(dotDotPath "/a/..")
+  set(someMorePath "/a/.some.more")
+  cmake_path(GET dotPath EXTENSION dotExt)
+  cmake_path(GET dotPath STEM dotStem)
+  cmake_path(GET dotDotPath EXTENSION dotDotExt)
+  cmake_path(GET dotDotPath STEM dotDotStem)
+  cmake_path(GET dotMorePath EXTENSION someMoreExt)
+  cmake_path(GET dotMorePath STEM someMoreStem)
+  message("Dot extension is \"${dotExt}\"")
+  message("Dot stem is \"${dotStem}\"")
+  message("Dot-dot extension is \"${dotDotExt}\"")
+  message("Dot-dot stem is \"${dotDotStem}\"")
+  message(".some.more extension is \"${someMoreExt}\"")
+  message(".some.more stem is \"${someMoreStem}\"")
+
+::
+
+  Full extension is ".ext1.ext2"
+  Full stem is "name"
+  Last extension is ".ext2"
+  Last stem is "name.ext1"
+  Dot extension is ""
+  Dot stem is "."
+  Dot-dot extension is ""
+  Dot-dot stem is ".."
+  .some.more extension is ".more"
+  .some.more stem is ".some"
+
+Relative part examples
+""""""""""""""""""""""
+
+.. code-block:: cmake
+
+  set(path "c:/a/b")
+  cmake_path(GET path RELATIVE_PART result)
+  message("Relative part is \"${result}\"")
+
+  set(path "c/d")
+  cmake_path(GET path RELATIVE_PART result)
+  message("Relative part is \"${result}\"")
+
+  set(path "/")
+  cmake_path(GET path RELATIVE_PART result)
+  message("Relative part is \"${result}\"")
+
+::
+
+  Relative part is "a/b"
+  Relative part is "c/d"
+  Relative part is ""
+
+Path traversal examples
+"""""""""""""""""""""""
+
+.. code-block:: cmake
+
+  set(path "c:/a/b")
+  cmake_path(GET path PARENT_PATH result)
+  message("Parent path is \"${result}\"")
+
+  set(path "c:/")
+  cmake_path(GET path PARENT_PATH result)
+  message("Parent path is \"${result}\"")
+
+::
+
+  Parent path is "c:/a"
+  Parent path is "c:/"
+
+
+Query
+^^^^^
+
+Each of the ``GET`` subcommands has a corresponding ``HAS_...``
+subcommand which can be used to discover whether a particular path
+component is present.  See `Path Structure And Terminology`_ for the
+meaning of each path component.
+
+.. _HAS_ROOT_NAME:
+.. _HAS_ROOT_DIRECTORY:
+.. _HAS_ROOT_PATH:
+.. _HAS_FILENAME:
+.. _HAS_EXTENSION:
+.. _HAS_STEM:
+.. _HAS_RELATIVE_PART:
+.. _HAS_PARENT_PATH:
+
+::
+
+  cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
+  cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
+  cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
+  cmake_path(HAS_FILENAME <path-var> <out-var>)
+  cmake_path(HAS_EXTENSION <path-var> <out-var>)
+  cmake_path(HAS_STEM <path-var> <out-var>)
+  cmake_path(HAS_RELATIVE_PART <path-var> <out-var>)
+  cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
+
+Each of the above follows the predictable pattern of setting ``<out-var>``
+to true if the path has the associated component, or false otherwise.
+Note the following special cases:
+
+* For ``HAS_ROOT_PATH``, a true result will only be returned if at least one
+  of ``root-name`` or ``root-directory`` is non-empty.
+
+* For ``HAS_PARENT_PATH``, the root directory is also considered to have a
+  parent, which will be itself.  The result is true except if the path
+  consists of just a :ref:`filename <FILENAME_DEF>`.
+
+.. _IS_ABSOLUTE:
+
+::
+
+  cmake_path(IS_ABSOLUTE <path-var> <out-var>)
+
+Sets ``<out-var>`` to true if ``<path-var>`` is absolute.  An absolute path
+is a path that unambiguously identifies the location of a file without
+reference to an additional starting location.  On Windows, this means the
+path must have both a ``root-name`` and a ``root-directory-separator`` to be
+considered absolute.  On other platforms, just a ``root-directory-separator``
+is sufficient.  Note that this means on Windows, ``IS_ABSOLUTE`` can be
+false while ``HAS_ROOT_DIRECTORY`` can be true.
+
+.. _IS_RELATIVE:
+
+::
+
+  cmake_path(IS_RELATIVE <path-var> <out-var>)
+
+This will store the opposite of ``IS_ABSOLUTE`` in ``<out-var>``.
+
+.. _IS_PREFIX:
+
+::
+
+  cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
+
+Checks if ``<path-var>`` is the prefix of ``<input>``.
+
+When the ``NORMALIZE`` option is specified, ``<path-var>`` and ``<input>``
+are :ref:`normalized <Normalization>` before the check.
+
+.. code-block:: cmake
+
+  set(path "/a/b/c/d")
+  cmake_path(IS_PREFIX path "/a/b" result)    # result = true
+  cmake_path(IS_PREFIX path "/x/y/z" result)  # result = false
+
+  set(path "/a/b")
+  cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE result)   # result = true
+
+.. _COMPARE:
+
+::
+
+  cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
+  cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
+
+Compares the lexical representations of two paths provided as string literals.
+No normalization is performed on either path.  Equality is determined
+according to the following pseudo-code logic:
+
+::
+
+  if(NOT <input1>.root_name() STREQUAL <input2>.root_name())
+    return FALSE
+
+  if(<input1>.has_root_directory() XOR <input2>.has_root_directory())
+    return FALSE
+
+  Return FALSE if a relative portion of <input1> is not lexicographically
+  equal to the relative portion of <input2>. This comparison is performed path
+  component-wise. If all of the components compare equal, then return TRUE.
+
+.. note::
+  Unlike most other ``cmake_path()`` subcommands, the ``COMPARE`` subcommand
+  takes literal strings as input, not the names of variables.
+
+
+Modification
+^^^^^^^^^^^^
+
+.. _cmake_path-SET:
+
+::
+
+  cmake_path(SET <path-var> [NORMALIZE] <input>)
+
+Assign the ``<input>`` path to ``<path-var>``.  If ``<input>`` is a native
+path, it is converted into a cmake-style path with forward-slashes
+(``/``). On Windows, the long filename marker is taken into account.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+For example:
+
+.. code-block:: cmake
+
+  set(native_path "c:\\a\\b/..\\c")
+  cmake_path(SET path "${native_path}")
+  message("CMake path is \"${path}\"")
+
+  cmake_path(SET path NORMALIZE "${native_path}")
+  message("Normalized CMake path is \"${path}\"")
+
+Output::
+
+  CMake path is "c:/a/b/../c"
+  Normalized CMake path is "c:/a/c"
+
+.. _APPEND:
+
+::
+
+  cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+
+Append all the ``<input>`` arguments to the ``<path-var>`` using ``/`` as
+the ``directory-separator``.  Depending on the ``<input>``, the previous
+contents of ``<path-var>`` may be discarded.  For each ``<input>`` argument,
+the following algorithm (pseudo-code) applies:
+
+::
+
+  # <path> is the contents of <path-var>
+
+  if(<input>.is_absolute() OR
+     (<input>.has_root_name() AND
+      NOT <input>.root_name() STREQUAL <path>.root_name()))
+    replace <path> with <input>
+    return()
+  endif()
+
+  if(<input>.has_root_directory())
+    remove any root-directory and the entire relative path from <path>
+  elseif(<path>.has_filename() OR
+         (NOT <path-var>.has_root_directory() OR <path>.is_absolute()))
+    append directory-separator to <path>
+  endif()
+
+  append <input> omitting any root-name to <path>
+
+.. _APPEND_STRING:
+
+::
+
+  cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
+
+Append all the ``<input>`` arguments to the ``<path-var>`` without adding any
+``directory-separator``.
+
+.. _REMOVE_FILENAME:
+
+::
+
+  cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
+
+Removes the :ref:`filename <FILENAME_DEF>` component (as returned by
+:ref:`GET ... FILENAME <GET_FILENAME>`) from ``<path-var>``.  After removal,
+any trailing ``directory-separator`` is left alone, if present.
+
+If ``OUTPUT_VARIABLE`` is not given, then after this function returns,
+`HAS_FILENAME`_ returns false for ``<path-var>``.
+
+For example:
+
+.. code-block:: cmake
+
+  set(path "/a/b")
+  cmake_path(REMOVE_FILENAME path)
+  message("First path is \"${path}\"")
+
+  # filename is now already empty, the following removes nothing
+  cmake_path(REMOVE_FILENAME path)
+  message("Second path is \"${result}\"")
+
+Output::
+
+  First path is "/a/"
+  Second path is "/a/"
+
+.. _REPLACE_FILENAME:
+
+::
+
+  cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
+
+Replaces the :ref:`filename <FILENAME_DEF>` component from ``<path-var>``
+with ``<input>``.  If ``<path-var>`` has no filename component (i.e.
+`HAS_FILENAME`_ returns false), the path is unchanged.  The operation is
+equivalent to the following:
+
+.. code-block:: cmake
+
+  cmake_path(HAS_FILENAME path has_filename)
+  if(has_filename)
+    cmake_path(REMOVE_FILENAME path)
+    cmake_path(APPEND path input);
+  endif()
+
+.. _REMOVE_EXTENSION:
+
+::
+
+  cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
+                                         [OUTPUT_VARIABLE <out-var>])
+
+Removes the :ref:`extension <EXTENSION_DEF>`, if any, from ``<path-var>``.
+
+.. _REPLACE_EXTENSION:
+
+::
+
+  cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
+                               [OUTPUT_VARIABLE <out-var>])
+
+Replaces the :ref:`extension <EXTENSION_DEF>` with ``<input>``.  Its effect
+is equivalent to the following:
+
+.. code-block:: cmake
+
+  cmake_path(REMOVE_EXTENSION path)
+  if(NOT "input" MATCHES "^\\.")
+    cmake_path(APPEND_STRING path ".")
+  endif()
+  cmake_path(APPEND_STRING path "input")
+
+
+Generation
+^^^^^^^^^^
+
+.. _NORMAL_PATH:
+
+::
+
+  cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
+
+Normalize ``<path-var>`` according the steps described in :ref:`Normalization`.
+
+.. _cmake_path-RELATIVE_PATH:
+.. _RELATIVE_PATH:
+
+::
+
+  cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
+                                      [OUTPUT_VARIABLE <out-var>])
+
+Modifies ``<path-var>`` to make it relative to the ``BASE_DIRECTORY`` argument.
+If ``BASE_DIRECTORY`` is not specified, the default base directory will be
+:variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
+For reference, the algorithm used to compute the relative path is the same
+as that used by C++
+`std::filesystem::path::lexically_relative
+<https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal>`_.
+
+.. _ABSOLUTE_PATH:
+
+::
+
+  cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
+                                      [OUTPUT_VARIABLE <out-var>])
+
+If ``<path-var>`` is a relative path (`IS_RELATIVE`_ is true), it is evaluated
+relative to the given base directory specified by ``BASE_DIRECTORY`` option.
+If ``BASE_DIRECTORY`` is not specified, the default base directory will be
+:variable:`CMAKE_CURRENT_SOURCE_DIR`.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` after the path computation.
+
+Because ``cmake_path()`` does not access the filesystem, symbolic links are
+not resolved.  To compute a real path with symbolic links resolved, use the
+:command:`file(REAL_PATH)` command instead.
+
+Native Conversion
+^^^^^^^^^^^^^^^^^
+
+For commands in this section, *native* refers to the host platform, not the
+target platform when cross-compiling.
+
+.. _cmake_path-NATIVE_PATH:
+.. _NATIVE_PATH:
+
+::
+
+  cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
+
+Converts a cmake-style ``<path-var>`` into a native path with
+platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+.. _CONVERT:
+.. _cmake_path-TO_CMAKE_PATH_LIST:
+.. _TO_CMAKE_PATH_LIST:
+
+::
+
+  cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
+
+Converts a native ``<input>`` path into a cmake-style path with forward
+slashes (``/``).  On Windows hosts, the long filename marker is taken into
+account.  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 (on non-Windows platforms, this essentially
+means ``:`` separators are replaced with ``;``).  The result of the
+conversion is stored in the ``<out-var>`` variable.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+.. note::
+  Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
+  takes a literal string as input, not the name of a variable.
+
+.. _cmake_path-TO_NATIVE_PATH_LIST:
+.. _TO_NATIVE_PATH_LIST:
+
+::
+
+  cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])
+
+Converts a cmake-style ``<input>`` path into a native path with
+platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
+The input can be a single path or a cmake-style list.  A list will be
+converted into a native search path (``;``-separated on Windows,
+``:``-separated on other platforms).  The result of the conversion is
+stored in the ``<out-var>`` variable.
+
+When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
+<Normalization>` before the conversion.
+
+.. note::
+  Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
+  takes a literal string as input, not the name of a variable.
+
+For example:
+
+.. code-block:: cmake
+
+  set(paths "/a/b/c" "/x/y/z")
+  cmake_path(CONVERT "${paths}" TO_NATIVE_PATH_LIST native_paths)
+  message("Native path list is \"${native_paths}\"")
+
+Output on Windows::
+
+  Native path list is "\a\b\c;\x\y\z"
+
+Output on all other platforms::
+
+  Native path list is "/a/b/c:/x/y/z"
+
+Hashing
+^^^^^^^
+
+.. _HASH:
+
+::
+
+    cmake_path(HASH <path-var> <out-var>)
+
+Compute a hash value of ``<path-var>`` such that for two paths ``p1`` and
+``p2`` that compare equal (:ref:`COMPARE ... EQUAL <COMPARE>`), the hash
+value of ``p1`` is equal to the hash value of ``p2``.  The path is always
+:ref:`normalized <Normalization>` before the hash is computed.
index 4bc7807..94060d9 100644 (file)
@@ -28,6 +28,9 @@ encourage projects to set policies based on CMake versions:
 
   cmake_policy(VERSION <min>[...<max>])
 
+.. versionadded:: 3.12
+  The optional ``<max>`` version.
+
 ``<min>`` and the optional ``<max>`` are each CMake versions of the form
 ``major.minor[.patch[.tweak]]``, and the ``...`` is literal.  The ``<min>``
 version must be at least ``2.4`` and at most the running version of CMake.
index c59995a..63ea84d 100644 (file)
@@ -6,8 +6,9 @@ Copy a file to another location and modify its contents.
 .. code-block:: cmake
 
   configure_file(<input> <output>
+                 [FILE_PERMISSIONS <permissions>...]
                  [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
-                 [NO_SOURCE_PERMISSIONS]
+                 [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]
                  [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
 
 Copies an ``<input>`` file to an ``<output>`` file and substitutes
@@ -37,22 +38,24 @@ a false constant by the :command:`if` command.  The "..." content on the
 line after the variable name, if any, is processed as above.
 Input file lines of the form ``#cmakedefine01 VAR`` will be replaced with
 either ``#define VAR 1`` or ``#define VAR 0`` similarly.
-The result lines (with the exception of the ``#undef`` comments) can be
-indented using spaces and/or tabs between the ``#`` character
-and the ``cmakedefine`` or ``cmakedefine01`` words. This whitespace
-indentation will be preserved in the output lines:
 
-.. code-block:: c
+.. versionadded:: 3.10
+  The result lines (with the exception of the ``#undef`` comments) can be
+  indented using spaces and/or tabs between the ``#`` character
+  and the ``cmakedefine`` or ``cmakedefine01`` words. This whitespace
+  indentation will be preserved in the output lines:
 
-  #  cmakedefine VAR
-  #  cmakedefine01 VAR
+  .. code-block:: c
 
-will be replaced, if ``VAR`` is defined, with
+    #  cmakedefine VAR
+    #  cmakedefine01 VAR
 
-.. code-block:: c
+  will be replaced, if ``VAR`` is defined, with
 
-  #  define VAR
-  #  define VAR 1
+  .. code-block:: c
+
+    #  define VAR
+    #  define VAR 1
 
 If the input file is modified the build system will re-run CMake to
 re-configure the file and generate the build system again.
@@ -72,6 +75,9 @@ The arguments are:
   If the path names an existing directory the output file is placed
   in that directory with the same file name as the input file.
 
+``FILE_PERMISSIONS <permissions>...``
+  Use user provided permissions for the output file.
+
 ``COPYONLY``
   Copy the file without replacing any variable references or other
   content.  This option may not be used with ``NEWLINE_STYLE``.
@@ -84,10 +90,17 @@ The arguments are:
   This is useful for configuring scripts that use ``${VAR}`` syntax.
 
 ``NO_SOURCE_PERMISSIONS``
+  .. versionadded:: 3.19
+
   Does not transfer the file permissions of the original file to the copy.
   The copied file permissions default to the standard 644 value
   (-rw-r--r--).
 
+``USE_SOURCE_PERMISSIONS``
+  .. versionadded:: 3.20
+
+  Transfer the file permissions of the original file to the output file.
+
 ``NEWLINE_STYLE <style>``
   Specify the newline style for the output file.  Specify
   ``UNIX`` or ``LF`` for ``\n`` newlines, or specify
index 66e1844..4d6dc5a 100644 (file)
@@ -50,7 +50,10 @@ The options are:
   for an example.
 
 ``PROJECT_NAME <project-name>``
-  Ignored.  This was once used but is no longer needed.
+  Ignored since CMake 3.0.
+
+  .. versionchanged:: 3.14
+    This value is no longer required.
 
 ``TARGET <target-name>``
   Specify the name of a target to build.  If not specified the
@@ -68,10 +71,14 @@ The options are:
   Store the return value of the native build tool in the given variable.
 
 ``CAPTURE_CMAKE_ERROR <result-var>``
+  .. versionadded:: 3.7
+
   Store in the ``<result-var>`` variable -1 if there are any errors running
   the command and prevent ctest from returning non-zero if an error occurs.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   Suppress any CTest-specific non-error output that would have been
   printed to the console otherwise.  The summary of warnings / errors,
   as well as the output from the native build tool is unaffected by
index 2dea07b..95712aa 100644 (file)
@@ -37,10 +37,14 @@ The options are:
   configuration tool.
 
 ``CAPTURE_CMAKE_ERROR <result-var>``
+  .. versionadded:: 3.7
+
   Store in the ``<result-var>`` variable -1 if there are any errors running
   the command and prevent ctest from returning non-zero if an error occurs.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   Suppress any CTest-specific non-error messages that would have
   otherwise been printed to the console.  Output from the underlying
   configure command is not affected.
index d50f634..a6c643b 100644 (file)
@@ -37,10 +37,14 @@ The options are:
   ran without error and non-zero otherwise.
 
 ``CAPTURE_CMAKE_ERROR <result-var>``
+  .. versionadded:: 3.7
+
   Store in the ``<result-var>`` variable -1 if there are any errors running
   the command and prevent ctest from returning non-zero if an error occurs.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   Suppress any CTest-specific non-error output that would have been
   printed to the console otherwise.  The summary indicating how many
   lines of code were covered is unaffected by this option.
index 288b65a..f655c2e 100644 (file)
@@ -35,4 +35,6 @@ Most options are the same as those for the :command:`ctest_test` command.
 The options unique to this command are:
 
 ``DEFECT_COUNT <defect-count-var>``
+  .. versionadded:: 3.8
+
   Store in the ``<defect-count-var>`` the number of defects found.
index f0704ac..c0f3c6d 100644 (file)
@@ -29,8 +29,11 @@ The parameters are as follows:
 ``GROUP <group>``
   If ``GROUP`` is used, the submissions will go to the specified group on the
   CDash server. If no ``GROUP`` is specified, the name of the model is used by
-  default. This replaces the deprecated option ``TRACK``. Despite the name
-  change its behavior is unchanged.
+  default.
+
+  .. versionchanged:: 3.16
+    This replaces the deprecated option ``TRACK``. Despite the name
+    change its behavior is unchanged.
 
 ``APPEND``
   If ``APPEND`` is used, the existing ``TAG`` is used rather than creating a new
@@ -56,6 +59,8 @@ The parameters are as follows:
   new model and group will be used.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   If ``QUIET`` is used, CTest will suppress any non-error messages that it
   otherwise would have printed to the console.
 
index 983fc20..e6d277f 100644 (file)
@@ -42,14 +42,20 @@ The options are:
   Each individual file must exist at the time of the call.
 
 ``SUBMIT_URL <url>``
+  .. versionadded:: 3.14
+
   The ``http`` or ``https`` URL of the dashboard server to send the submission
   to.  If not given, the :variable:`CTEST_SUBMIT_URL` variable is used.
 
 ``BUILD_ID <result-var>``
+  .. versionadded:: 3.15
+
   Store in the ``<result-var>`` variable the ID assigned to this build by
   CDash.
 
 ``HTTPHEADER <HTTP-header>``
+  .. versionadded:: 3.9
+
   Specify HTTP header to be included in the request to CDash during submission.
   For example, CDash can be configured to only accept submissions from
   authenticated clients. In this case, you should provide a bearer token in your
@@ -73,20 +79,27 @@ The options are:
   non-zero on failure.
 
 ``CAPTURE_CMAKE_ERROR <result-var>``
+  .. versionadded:: 3.13
+
   Store in the ``<result-var>`` variable -1 if there are any errors running
   the command and prevent ctest from returning non-zero if an error occurs.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   Suppress all non-error messages that would have otherwise been
   printed to the console.
 
 Submit to CDash Upload API
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.2
+
 ::
 
   ctest_submit(CDASH_UPLOAD <file> [CDASH_UPLOAD_TYPE <type>]
                [SUBMIT_URL <url>]
+               [BUILD_ID <result-var>]
                [HTTPHEADER <header>]
                [RETRY_COUNT <count>]
                [RETRY_DELAY <delay>]
@@ -99,6 +112,19 @@ with a content hash of the file. If CDash does not already have the file,
 then it is uploaded. Along with the file, a CDash type string is specified
 to tell CDash which handler to use to process the data.
 
-This signature accepts the ``SUBMIT_URL``, ``BUILD_ID``, ``HTTPHEADER``,
-``RETRY_COUNT``, ``RETRY_DELAY``, ``RETURN_VALUE`` and ``QUIET`` options
-as described above.
+This signature interprets options in the same way as the first one.
+
+.. versionadded:: 3.8
+  Added the ``RETRY_COUNT``, ``RETRY_DELAY``, ``QUIET`` options.
+
+.. versionadded:: 3.9
+  Added the ``HTTPHEADER`` option.
+
+.. versionadded:: 3.13
+  Added the ``RETURN_VALUE`` option.
+
+.. versionadded:: 3.14
+  Added the ``SUBMIT_URL`` option.
+
+.. versionadded:: 3.15
+  Added the ``BUILD_ID`` option.
index 3589296..b4493a0 100644 (file)
@@ -68,6 +68,8 @@ The options are:
   Tests not matching this expression are excluded.
 
 ``EXCLUDE_FIXTURE <regex>``
+  .. versionadded:: 3.7
+
   If a test in the set of tests to be executed requires a particular fixture,
   that fixture's setup and cleanup tests would normally be added to the test
   set automatically. This option prevents adding setup or cleanup tests for
@@ -76,9 +78,13 @@ The options are:
   setup tests that fail.
 
 ``EXCLUDE_FIXTURE_SETUP <regex>``
+  .. versionadded:: 3.7
+
   Same as ``EXCLUDE_FIXTURE`` except only matching setup tests are excluded.
 
 ``EXCLUDE_FIXTURE_CLEANUP <regex>``
+  .. versionadded:: 3.7
+
   Same as ``EXCLUDE_FIXTURE`` except only matching cleanup tests are excluded.
 
 ``PARALLEL_LEVEL <level>``
@@ -86,11 +92,15 @@ The options are:
   be run in parallel.
 
 ``RESOURCE_SPEC_FILE <file>``
+  .. versionadded:: 3.16
+
   Specify a
   :ref:`resource specification file <ctest-resource-specification-file>`. See
   :ref:`ctest-resource-allocation` for more information.
 
 ``TEST_LOAD <threshold>``
+  .. versionadded:: 3.4
+
   While running tests in parallel, try not to start tests when they
   may cause the CPU load to pass above a given threshold.  If not
   specified the :variable:`CTEST_TEST_LOAD` variable will be checked,
@@ -98,6 +108,8 @@ The options are:
   See also the ``TestLoad`` setting in the :ref:`CTest Test Step`.
 
 ``REPEAT <mode>:<n>``
+  .. versionadded:: 3.17
+
   Run tests repeatedly based on the given ``<mode>`` up to ``<n>`` times.
   The modes are:
 
@@ -121,6 +133,8 @@ The options are:
   implicit test dependencies.
 
 ``STOP_ON_FAILURE``
+  .. versionadded:: 3.18
+
   Stop the execution of the tests once one has failed.
 
 ``STOP_TIME <time-of-day>``
@@ -131,10 +145,14 @@ The options are:
   Store non-zero if anything went wrong.
 
 ``CAPTURE_CMAKE_ERROR <result-var>``
+  .. versionadded:: 3.7
+
   Store in the ``<result-var>`` variable -1 if there are any errors running
   the command and prevent ctest from returning non-zero if an error occurs.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   Suppress any CTest-specific non-error messages that would have otherwise
   been printed to the console.  Output from the underlying test command is not
   affected.  Summary info detailing the percentage of passing tests is also
index 96a11c9..63f991b 100644 (file)
@@ -24,10 +24,14 @@ The options are:
   updated or ``-1`` on error.
 
 ``CAPTURE_CMAKE_ERROR <result-var>``
+  .. versionadded:: 3.13
+
   Store in the ``<result-var>`` variable -1 if there are any errors running
   the command and prevent ctest from returning non-zero if an error occurs.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   Tell CTest to suppress most non-error messages that it would
   have otherwise printed to the console.  CTest will still report
   the new revision of the repository and any conflicting files
index 39d9de1..ffddd0a 100644 (file)
@@ -14,9 +14,13 @@ The options are:
   dashboard server.
 
 ``QUIET``
+  .. versionadded:: 3.3
+
   Suppress any CTest-specific non-error output that would have been
   printed to the console otherwise.
 
 ``CAPTURE_CMAKE_ERROR <result-var>``
+  .. versionadded:: 3.7
+
   Store in the ``<result-var>`` variable -1 if there are any errors running
   the command and prevent ctest from returning non-zero if an error occurs.
index e8640ea..ce765de 100644 (file)
@@ -12,6 +12,15 @@ variables that are created by the project command.  Example languages
 are ``CXX``, ``C``, ``CUDA``, ``OBJC``, ``OBJCXX``, ``Fortran``,
 ``ISPC``, and ``ASM``.
 
+.. versionadded:: 3.8
+  Added ``CUDA`` support.
+
+.. versionadded:: 3.16
+  Added ``OBJC`` and ``OBJCXX`` support.
+
+.. versionadded:: 3.18
+  Added ``ISPC`` support.
+
 If enabling ``ASM``, enable it last so that CMake can check whether
 compilers for other languages like ``C`` work for assembly too.
 
index 268c307..82fcd46 100644 (file)
@@ -62,6 +62,8 @@ Options:
  describing an error condition.
 
 ``RESULTS_VARIABLE <variable>``
+ .. versionadded:: 3.10
+
  The variable will be set to contain the result of all processes as a
  :ref:`semicolon-separated list <CMake Language Lists>`, in order of the
  given ``COMMAND`` arguments.  Each entry will be an integer return code
@@ -75,19 +77,26 @@ Options:
 ``INPUT_FILE, OUTPUT_FILE``, ``ERROR_FILE``
  The file named will be attached to the standard input of the first
  process, standard output of the last process, or standard error of
- all processes, respectively.  If the same file is named for both
- output and error then it will be used for both.
+ all processes, respectively.
+
+ .. versionadded:: 3.3
+  If the same file is named for both output and error then it will be used
+  for both.
 
 ``OUTPUT_QUIET``, ``ERROR_QUIET``
  The standard output or standard error results will be quietly ignored.
 
 ``COMMAND_ECHO <where>``
+ .. versionadded:: 3.15
+
  The command being run will be echo'ed to ``<where>`` with ``<where>``
  being set to one of ``STDERR``, ``STDOUT`` or ``NONE``.
  See the :variable:`CMAKE_EXECUTE_PROCESS_COMMAND_ECHO` variable for a way
  to control the default behavior when this option is not present.
 
 ``ENCODING <name>``
+ .. versionadded:: 3.8
+
  On Windows, the encoding that is used to decode output from the process.
  Ignored on other platforms.
  Valid encoding names are:
@@ -104,11 +113,15 @@ Options:
  ``OEM``
    Use the original equipment manufacturer (OEM) code page.
  ``UTF8`` or ``UTF-8``
-   Use the UTF-8 codepage. Prior to CMake 3.11.0, only ``UTF8`` was accepted
-   for this encoding. In CMake 3.11.0, ``UTF-8`` was added for consistency with
-   the `UTF-8 RFC <https://www.ietf.org/rfc/rfc3629>`_ naming convention.
+   Use the UTF-8 codepage.
+
+   .. versionadded:: 3.11
+     Accept ``UTF-8`` spelling for consistency with the
+     `UTF-8 RFC <https://www.ietf.org/rfc/rfc3629>`_ naming convention.
 
 ``ECHO_OUTPUT_VARIABLE``, ``ECHO_ERROR_VARIABLE``
+  .. versionadded:: 3.18
+
   The standard output or standard error will not be exclusively redirected to
   the configured variables.
 
@@ -118,6 +131,8 @@ Options:
   This is analogous to the ``tee`` Unix command.
 
 ``COMMAND_ERROR_IS_FATAL <ANY|LAST>``
+  .. versionadded:: 3.19
+
   The option following ``COMMAND_ERROR_IS_FATAL`` determines the behavior when
   an error is encountered:
 
index 2ca7056..e8a1fa7 100644 (file)
@@ -64,16 +64,23 @@ build tree. In some cases, for example for packaging and for system
 wide installations, it is not desirable to write the user package
 registry.
 
-By default the ``export(PACKAGE)`` command does nothing (see policy
-:policy:`CMP0090`) because populating the user package registry has effects
-outside the source and build trees.  Set the
-:variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable to add build directories to
-the CMake user package registry.
+.. versionchanged:: 3.1
+  If the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable
+  is enabled, the ``export(PACKAGE)`` command will do nothing.
+
+.. versionchanged:: 3.15
+  By default the ``export(PACKAGE)`` command does nothing (see policy
+  :policy:`CMP0090`) because populating the user package registry has effects
+  outside the source and build trees.  Set the
+  :variable:`CMAKE_EXPORT_PACKAGE_REGISTRY` variable to add build directories
+  to the CMake user package registry.
 
 .. code-block:: cmake
 
   export(TARGETS [target1 [target2 [...]]]  [ANDROID_MK <filename>])
 
+.. versionadded:: 3.7
+
 This signature exports cmake built targets to the android ndk build system
 by creating an Android.mk file that references the prebuilt targets. The
 Android NDK supports the use of prebuilt libraries, both static and shared.
index e963be0..3db605d 100644 (file)
@@ -3,6 +3,21 @@ file
 
 File manipulation command.
 
+This command is dedicated to file and path manipulation requiring access to the
+filesystem.
+
+For other path manipulation, handling only syntactic aspects, have a look at
+:command:`cmake_path` command.
+
+.. note::
+
+  The sub-commands `RELATIVE_PATH`_, `TO_CMAKE_PATH`_ and `TO_NATIVE_PATH`_ has
+  been superseded, respectively, by sub-commands
+  :ref:`RELATIVE_PATH <cmake_path-RELATIVE_PATH>`,
+  :ref:`CONVERT ... TO_CMAKE_PATH_LIST <cmake_path-TO_CMAKE_PATH_LIST>` and
+  :ref:`CONVERT ... TO_NATIVE_PATH_LIST <cmake_path-TO_NATIVE_PATH_LIST>` of
+  :command:`cmake_path` command.
+
 Synopsis
 ^^^^^^^^
 
@@ -103,10 +118,15 @@ Parse a list of ASCII strings from ``<filename>`` and store it in
  Consider only strings that match the given regular expression.
 
 ``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.
+ ``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.
 
 For example, the code
 
@@ -160,6 +180,8 @@ the ``<format>`` and ``UTC`` options.
     [POST_EXCLUDE_REGEXES [<regexes>...]]
     )
 
+.. versionadded:: 3.16
+
 Recursively get the list of libraries depended on by the given files.
 
 Please note that this sub-command is not intended to be used in project mode.
@@ -408,6 +430,9 @@ dependency resolution:
   If this variable is not specified, it is determined by the value of
   ``CMAKE_OBJDUMP`` if set, else by system introspection.
 
+  .. versionadded:: 3.18
+    Use ``CMAKE_OBJDUMP`` if set.
+
 Writing
 ^^^^^^^
 
@@ -436,6 +461,8 @@ to update the file only when its content changes.
   file(TOUCH [<files>...])
   file(TOUCH_NOCREATE [<files>...])
 
+.. versionadded:: 3.12
+
 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.
@@ -452,7 +479,10 @@ modified.
 
   file(GENERATE OUTPUT output-file
        <INPUT input-file|CONTENT content>
-       [CONDITION expression] [TARGET target])
+       [CONDITION expression] [TARGET target]
+       [FILE_PERMISSIONS <permissions>...]
+       [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]
+       [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
 
 Generate an output file for each build configuration supported by the current
 :manual:`CMake Generator <cmake-generators(7)>`.  Evaluate
@@ -469,8 +499,10 @@ from the input content to produce the output content.  The options are:
 
 ``INPUT <input-file>``
   Use the content from a given file as input.
-  A relative path is treated with respect to the value of
-  :variable:`CMAKE_CURRENT_SOURCE_DIR`.  See policy :policy:`CMP0070`.
+
+  .. versionchanged:: 3.10
+    A relative path is treated with respect to the value of
+    :variable:`CMAKE_CURRENT_SOURCE_DIR`.  See policy :policy:`CMP0070`.
 
 ``OUTPUT <output-file>``
   Specify the output file name to generate.  Use generator expressions
@@ -478,15 +510,37 @@ from the input content to produce the output content.  The options are:
   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.
-  A relative path (after evaluating generator expressions) is treated
-  with respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`.
-  See policy :policy:`CMP0070`.
+
+  .. 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`.
 
 ``TARGET <target>``
+  .. versionadded:: 3.19
+
   Specify which target to use when evaluating generator expressions that
   require a target for evaluation (e.g. ``$<COMPILE_FEATURES:...>``,
   ``$<TARGET_PROPERTY:prop>``).
 
+``FILE_PERMISSIONS <permissions>...``
+  Use user provided permissions for the generated file.
+
+``NO_SOURCE_PERMISSIONS``
+  The generated file permissions default to the standard 644 value
+  (-rw-r--r--).
+
+``USE_SOURCE_PERMISSIONS``
+  Transfer the file permissions of the original file to the generated file.
+  This option expects INPUT option.
+
+``NEWLINE_STYLE <style>``
+  .. versionadded:: 3.20
+
+  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.
+
 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
@@ -506,6 +560,8 @@ of a project's ``CMakeLists.txt`` files.
        [ESCAPE_QUOTES] [@ONLY]
        [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
 
+.. versionadded:: 3.18
+
 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.
@@ -554,20 +610,25 @@ 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.  The results will be ordered lexicographically.
+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.
 
-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.
+.. versionadded:: 3.3
+  By default ``GLOB`` lists directories - directories are omitted in result if
+  ``LIST_DIRECTORIES`` is set to false.
 
-By default ``GLOB`` lists directories - directories are omitted in 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
@@ -590,10 +651,11 @@ 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``.
 
-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.
+.. 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::
 
@@ -619,7 +681,12 @@ Move a file or directory within a filesystem from ``<oldname>`` to
 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.  Empty input paths are ignored with a warning.
+to the current source directory.
+
+.. versionchanged:: 3.15
+  Empty input paths are ignored with a warning.  Previous versions of CMake
+  interpreted empty string as a relative path with respect to the current
+  directory and removed its contents.
 
 .. _MAKE_DIRECTORY:
 
@@ -652,17 +719,18 @@ 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``).
 
-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:
+.. 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:
 
 * ``/opt/foo/lib/libfoo.so.1.2.3``
 * ``/opt/foo/lib/libfoo.so.1.2 -> libfoo.so.1.2.3``
@@ -696,6 +764,8 @@ use this signature (with some undocumented options for internal use).
 
   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.
@@ -706,6 +776,8 @@ pointing to a file and is readable.
 
   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.
@@ -730,6 +802,8 @@ absolute path is obtained:
   file(CREATE_LINK <original> <linkname>
        [RESULT <result>] [COPY_ON_ERROR] [SYMBOLIC])
 
+.. 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``
@@ -754,10 +828,12 @@ which would make them unable to support a hard link.
       [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``.
+``WORLD_WRITE``, ``WORLD_EXECUTE``, ``SETUID``, ``SETGID``.
 
 Valid combination of keywords are:
 
@@ -790,6 +866,8 @@ Valid combination of keywords are:
        [FILE_PERMISSIONS <permissions>...]
        [DIRECTORY_PERMISSIONS <permissions>...])
 
+.. versionadded:: 3.19
+
 Same as `CHMOD`_, but change the permissions of files and directories present in
 the ``<directories>...`` recursively.
 
@@ -802,6 +880,8 @@ Path Conversion
 
   file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>])
 
+.. versionadded:: 3.19
+
 Compute the absolute path to an existing file or directory with symlinks
 resolved.
 
@@ -849,10 +929,12 @@ Transfer
   file(UPLOAD   <file> <url> [<options>...])
 
 The ``DOWNLOAD`` subcommand downloads the given ``<url>`` to a local ``<file>``.
-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 ``UPLOAD``
-mode uploads a local ``<file>`` to a given ``<url>``.
+The ``UPLOAD`` mode uploads a local ``<file>`` to a given ``<url>``.
+
+.. 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.
 
 Options to both ``DOWNLOAD`` and ``UPLOAD`` are:
 
@@ -877,12 +959,18 @@ Options to both ``DOWNLOAD`` and ``UPLOAD`` are:
   Terminate the operation after a given total time has elapsed.
 
 ``USERPWD <username>:<password>``
+  .. versionadded:: 3.7
+
   Set username and password for operation.
 
 ``HTTPHEADER <HTTP-header>``
+  .. versionadded:: 3.7
+
   HTTP header for operation. Suboption can be repeated several times.
 
 ``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 ``CMAKE_NETRC`` variable
   will be used instead.
@@ -899,6 +987,8 @@ Options to both ``DOWNLOAD`` and ``UPLOAD`` are:
     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 ``CMAKE_NETRC_FILE`` variable will
@@ -911,9 +1001,15 @@ If neither ``NETRC`` option is given CMake will check variables
   Specify whether to verify the server certificate for ``https://`` URLs.
   The default is to *not* verify.
 
+  .. versionadded:: 3.18
+    Added support to ``file(UPLOAD)``.
+
 ``TLS_CAINFO <file>``
   Specify a custom Certificate Authority file for ``https://`` URLs.
 
+  .. versionadded:: 3.18
+    Added support to ``file(UPLOAD)``.
+
 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. If neither ``TLS`` option is given CMake will check
@@ -944,6 +1040,8 @@ Locking
        [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
@@ -979,6 +1077,8 @@ Archiving
     [MTIME <mtime>]
     [VERBOSE])
 
+.. 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.
@@ -993,9 +1093,10 @@ 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``.
 
-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.
+.. 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.
 
 .. note::
   With ``FORMAT`` set to ``raw`` only one file will be compressed with the
@@ -1016,6 +1117,8 @@ the ``MTIME`` option.
     [LIST_ONLY]
     [VERBOSE])
 
+.. versionadded:: 3.18
+
 Extracts or lists the content of the specified ``<archive>``.
 
 The directory where the content of the archive will be extracted to can
index 1be2e09..3dfd62f 100644 (file)
@@ -351,15 +351,16 @@ The set of installation prefixes is constructed using the following
 steps.  If ``NO_DEFAULT_PATH`` is specified all ``NO_*`` options are
 enabled.
 
-1. Search paths specified in the :variable:`<PackageName>_ROOT` CMake
-   variable and the :envvar:`<PackageName>_ROOT` environment variable,
-   where ``<PackageName>`` is the package to be found.
-   The package root variables are maintained as a stack so if
-   called from within a find module, root paths from the parent's find
-   module will also be searched after paths for the current package.
-   This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed or by setting
-   the :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` to ``FALSE``.
-   See policy :policy:`CMP0074`.
+1. .. versionadded:: 3.12
+    Search paths specified in the :variable:`<PackageName>_ROOT` CMake
+    variable and the :envvar:`<PackageName>_ROOT` environment variable,
+    where ``<PackageName>`` is the package to be found.
+    The package root variables are maintained as a stack so if
+    called from within a find module, root paths from the parent's find
+    module will also be searched after paths for the current package.
+    This can be skipped if ``NO_PACKAGE_ROOT_PATH`` is passed or by setting
+    the :variable:`CMAKE_FIND_USE_PACKAGE_ROOT_PATH` to ``FALSE``.
+    See policy :policy:`CMP0074`.
 
 2. Search paths specified in cmake-specific cache variables.  These
    are intended to be used on the command line with a ``-DVAR=value``.
@@ -430,6 +431,10 @@ enabled.
 9. Search paths specified by the ``PATHS`` option.  These are typically
    hard-coded guesses.
 
+.. versionadded:: 3.16
+   Added the ``CMAKE_FIND_USE_<CATEGORY>_PATH`` variables to globally disable
+   various search locations.
+
 .. |FIND_XXX| replace:: find_package
 .. |FIND_ARGS_XXX| replace:: <PackageName>
 .. |CMAKE_FIND_ROOT_PATH_MODE_XXX| replace::
index a01a104..8de6deb 100644 (file)
@@ -88,6 +88,8 @@ yields
 
   foreach(<loop_var>... IN ZIP_LISTS <lists>)
 
+.. versionadded:: 3.17
+
 In this variant, ``<lists>`` is a whitespace or semicolon
 separated list of list-valued variables. The ``foreach``
 command iterates over each list simultaneously setting the
index 7a9b907..3d25aa4 100644 (file)
@@ -50,8 +50,9 @@ and so on. However, it is strongly recommended to stay with the
 case chosen in the function definition. Typically functions use
 all-lowercase names.
 
-The :command:`cmake_language(CALL ...)` command can also be used to
-invoke the function.
+.. versionadded:: 3.18
+  The :command:`cmake_language(CALL ...)` command can also be used to
+  invoke the function.
 
 Arguments
 ^^^^^^^^^
index 39015cc..0ccbfb0 100644 (file)
@@ -11,12 +11,14 @@ Stores a property of directory scope in the named ``<variable>``.
 
 The ``DIRECTORY`` argument specifies another directory from which
 to retrieve the property value instead of the current directory.
-It may reference either a source directory, or since CMake 3.19,
-a binary directory.  Relative paths are treated as relative to the
+Relative paths are treated as relative to the
 current source directory.  CMake must already know about the directory,
 either by having added it through a call to :command:`add_subdirectory`
 or being the top level directory.
 
+.. versionadded:: 3.19
+  ``<dir>`` may reference a binary directory.
+
 If the property is not defined for the nominated directory scope,
 an empty string is returned.  In the case of ``INHERITED`` properties,
 if the property is not found for the nominated directory scope,
index ea2dedb..be9d00a 100644 (file)
@@ -3,6 +3,11 @@ get_filename_component
 
 Get a specific component of a full filename.
 
+.. versionchanged:: 3.19
+  This command 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.
+
 .. code-block:: cmake
 
   get_filename_component(<var> <FileName> <mode> [CACHE])
@@ -19,6 +24,9 @@ Sets ``<var>`` to a component of ``<FileName>``, where ``<mode>`` is one of:
  NAME_WLE  = File name with neither the directory nor the last extension
  PATH      = Legacy alias for DIRECTORY (use for CMake <= 2.8.11)
 
+.. versionadded:: 3.14
+  Added the ``LAST_EXT`` and ``NAME_WLE`` modes.
+
 Paths are returned with forward slashes and have no trailing slashes.
 If the optional ``CACHE`` argument is specified, the result variable is
 added to the cache.
@@ -27,6 +35,8 @@ added to the cache.
 
   get_filename_component(<var> <FileName> <mode> [BASE_DIR <dir>] [CACHE])
 
+.. versionadded:: 3.4
+
 Sets ``<var>`` to the absolute path of ``<FileName>``, where ``<mode>`` is one
 of:
 
@@ -53,9 +63,3 @@ left as a full path.  If ``PROGRAM_ARGS`` is present with ``PROGRAM``, then
 any command-line arguments present in the ``<FileName>`` string are split
 from the program name and stored in ``<arg_var>``.  This is used to
 separate a program name from its arguments in a command line string.
-
-.. note::
-
-  The ``REALPATH`` and ``PROGRAM`` subcommands had been superseded,
-  respectively, by :ref:`file(REAL_PATH) <REAL_PATH>` and
-  :command:`separate_arguments(PROGRAM)` commands.
index 870c934..f77d8af 100644 (file)
@@ -30,35 +30,43 @@ It must be one of the following:
 ``DIRECTORY``
   Scope defaults to the current directory but another
   directory (already processed by CMake) may be named by the
-  full or relative path ``<dir>``.  The ``<dir>`` may reference either a
-  source directory, or since CMake 3.19, a binary directory.
+  full or relative path ``<dir>``.
   Relative paths are treated as relative to the current source directory.
   See also the :command:`get_directory_property` command.
 
+  .. versionadded:: 3.19
+    ``<dir>`` may reference a binary directory.
+
 ``TARGET``
   Scope must name one existing target.
   See also the :command:`get_target_property` command.
 
 ``SOURCE``
   Scope must name one source file.  By default, the source file's property
-  will be read from the current source directory's scope, but this can be
-  overridden with one of the following sub-options:
+  will be read from the current source directory's scope.
+
+  .. versionadded:: 3.18
+    Directory scope can be overridden with one of the following sub-options:
+
+    ``DIRECTORY <dir>``
+      The source file property will be read from the ``<dir>`` directory's
+      scope.  CMake must already know about
+      the directory, either by having added it through a call
+      to :command:`add_subdirectory` or ``<dir>`` being the top level directory.
+      Relative paths are treated as relative to the current source directory.
 
-  ``DIRECTORY <dir>``
-    The source file property will be read from the ``<dir>`` directory's
-    scope.  The ``<dir>`` may reference either a source directory, or
-    since CMake 3.19, a binary directory.  CMake must already know about
-    the directory, either by having added it through a call
-    to :command:`add_subdirectory` or ``<dir>`` being the top level directory.
-    Relative paths are treated as relative to the current source directory.
+      .. versionadded:: 3.19
+        ``<dir>`` may reference a binary directory.
 
-  ``TARGET_DIRECTORY <target>``
-    The source file property will be read from the directory scope in which
-    ``<target>`` was created (``<target>`` must therefore already exist).
+    ``TARGET_DIRECTORY <target>``
+      The source file property will be read from the directory scope in which
+      ``<target>`` was created (``<target>`` must therefore already exist).
 
   See also the :command:`get_source_file_property` command.
 
 ``INSTALL``
+  .. versionadded:: 3.1
+
   Scope must name one installed file path.
 
 ``TEST``
@@ -86,3 +94,8 @@ If ``BRIEF_DOCS`` or ``FULL_DOCS`` is given then the variable is set to a
 string containing documentation for the requested property.  If
 documentation is requested for a property that has not been defined
 ``NOTFOUND`` is returned.
+
+.. note::
+
+  The :prop_sf:`GENERATED` source file property may be globally visible.
+  See its documentation for details.
index 76ed776..ae41565 100644 (file)
@@ -19,22 +19,29 @@ command and if still unable to find the property, ``variable`` will be set to
 an empty string.
 
 By default, the source file's property will be read from the current source
-directory's scope, but this can be overridden with one of the following
-sub-options:
+directory's scope.
 
-``DIRECTORY <dir>``
-  The source file property will be read from the ``<dir>`` directory's
-  scope.  CMake must already know about that source directory, either by
-  having added it through a call to :command:`add_subdirectory` or ``<dir>``
-  being the top level source directory.  Relative paths are treated as
-  relative to the current source directory.
+.. versionadded:: 3.18
+  Directory scope can be overridden with one of the following sub-options:
 
-``TARGET_DIRECTORY <target>``
-  The source file property will be read from the directory scope in which
-  ``<target>`` was created (``<target>`` must therefore already exist).
+  ``DIRECTORY <dir>``
+    The source file property will be read from the ``<dir>`` directory's
+    scope.  CMake must already know about that source directory, either by
+    having added it through a call to :command:`add_subdirectory` or ``<dir>``
+    being the top level source directory.  Relative paths are treated as
+    relative to the current source directory.
+
+  ``TARGET_DIRECTORY <target>``
+    The source file property will be read from the directory scope in which
+    ``<target>`` was created (``<target>`` must therefore already exist).
 
 Use :command:`set_source_files_properties` to set property values.  Source
 file properties usually control how the file is built. One property that is
 always there is :prop_sf:`LOCATION`.
 
 See also the more general :command:`get_property` command.
+
+.. note::
+
+  The :prop_sf:`GENERATED` source file property may be globally visible.
+  See its documentation for details.
index be992df..f327ca9 100644 (file)
@@ -39,15 +39,16 @@ the ``if``, ``elseif`` and :command:`while` clauses.
 
 Compound conditions are evaluated in the following order of precedence:
 Innermost parentheses are evaluated first. Next come unary tests such
-as ``EXISTS``, ``COMMAND``, and ``DEFINED``.  Then binary tests such as
-``EQUAL``, ``LESS``, ``LESS_EQUAL``, ``GREATER``, ``GREATER_EQUAL``,
-``STREQUAL``, ``STRLESS``, ``STRLESS_EQUAL``, ``STRGREATER``,
-``STRGREATER_EQUAL``, ``VERSION_EQUAL``, ``VERSION_LESS``,
-``VERSION_LESS_EQUAL``, ``VERSION_GREATER``, ``VERSION_GREATER_EQUAL``,
-and ``MATCHES``.  Then the boolean operators in the order ``NOT``,  ``AND``,
-and finally ``OR``.
+as `EXISTS`_, `COMMAND`_, and `DEFINED`_.  Then binary tests such as
+`EQUAL`_, `LESS`_, `LESS_EQUAL`_, `GREATER`_, `GREATER_EQUAL`_,
+`STREQUAL`_, `STRLESS`_, `STRLESS_EQUAL`_, `STRGREATER`_,
+`STRGREATER_EQUAL`_, `VERSION_EQUAL`_, `VERSION_LESS`_,
+`VERSION_LESS_EQUAL`_, `VERSION_GREATER`_, `VERSION_GREATER_EQUAL`_,
+and `MATCHES`_.  Then the boolean operators in the order `NOT`_,  `AND`_,
+and finally `OR`_.
 
-Possible conditions are:
+Basic Expressions
+"""""""""""""""""
 
 ``if(<constant>)``
  True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``,
@@ -62,15 +63,35 @@ Possible conditions are:
  True if given a variable that is defined to a value that is not a false
  constant.  False otherwise.  (Note macro arguments are not variables.)
 
+Logic Operators
+"""""""""""""""
+
+.. _NOT:
+
 ``if(NOT <condition>)``
  True if the condition is not true.
 
+.. _AND:
+
 ``if(<cond1> AND <cond2>)``
  True if both conditions would be considered true individually.
 
+.. _OR:
+
 ``if(<cond1> OR <cond2>)``
  True if either condition would be considered true individually.
 
+``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.
+
+Existence Checks
+""""""""""""""""
+
+.. _COMMAND:
+
 ``if(COMMAND command-name)``
  True if the given name is a command, macro or function that can be
  invoked.
@@ -85,14 +106,35 @@ Possible conditions are:
  (in any directory).
 
 ``if(TEST test-name)``
- True if the given name is an existing test name created by the
- :command:`add_test` command.
+ .. versionadded:: 3.3
+  True if the given name is an existing test name created by the
+  :command:`add_test` command.
+
+.. _DEFINED:
+
+``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 that macro arguments are not variables.
+
+ .. versionadded:: 3.14
+  Added support for ``CACHE{<name>}`` variables.
+
+``if(<variable|string> IN_LIST <variable>)``
+ .. versionadded:: 3.3
+  True if the given element is contained in the named list variable.
+
+File Operations
+"""""""""""""""
+
+.. _EXISTS:
 
 ``if(EXISTS path-to-file-or-directory)``
  True if the named file or directory exists.  Behavior is well-defined
- only for full paths. 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.
+ 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.
 
 ``if(file1 IS_NEWER_THAN file2)``
  True if ``file1`` is newer than ``file2`` or if one of the two files doesn't
@@ -113,50 +155,86 @@ Possible conditions are:
 ``if(IS_ABSOLUTE path)``
  True if the given path is an absolute path.
 
+Comparisons
+"""""""""""
+
+.. _MATCHES:
+
 ``if(<variable|string> MATCHES regex)``
  True if the given string or variable's value matches the given regular
  condition.  See :ref:`Regex Specification` for regex format.
- ``()`` groups are captured in :variable:`CMAKE_MATCH_<n>` variables.
+
+ .. versionadded:: 3.9
+  ``()`` groups are captured in :variable:`CMAKE_MATCH_<n>` variables.
+
+.. _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.
 
+.. _GREATER:
+
 ``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.
 
+.. _EQUAL:
+
 ``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.
 
+.. _LESS_EQUAL:
+
 ``if(<variable|string> LESS_EQUAL <variable|string>)``
- True if the given string or variable's value is a valid number and less
- than or equal to that on the right.
+ .. 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:
 
 ``if(<variable|string> GREATER_EQUAL <variable|string>)``
- True if the given string or variable's value is a valid number and greater
- than or equal to that on the right.
+ .. 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:
 
 ``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.
 
+.. _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.
 
+.. _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.
 
+.. _STRLESS_EQUAL:
+
 ``if(<variable|string> STRLESS_EQUAL <variable|string>)``
- True if the given string or variable's value is lexicographically less
- than or equal to the string or variable on the right.
+ .. 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:
 
 ``if(<variable|string> STRGREATER_EQUAL <variable|string>)``
- True if the given string or variable's value is lexicographically greater
- than or equal to the string or variable on the right.
+ .. 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:
 
 ``if(<variable|string> VERSION_LESS <variable|string>)``
  Component-wise integer version number comparison (version format is
@@ -164,43 +242,39 @@ Possible conditions are:
  Any non-integer version component or non-integer trailing part of a version
  component effectively truncates the string at that point.
 
+.. _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.
 
-``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.
+.. _VERSION_EQUAL:
 
-``if(<variable|string> VERSION_LESS_EQUAL <variable|string>)``
+``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.
 
-``if(<variable|string> VERSION_GREATER_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.
+.. _VERSION_LESS_EQUAL:
 
-``if(<variable|string> IN_LIST <variable>)``
- True if the given element is contained in the named list variable.
+``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.
 
-``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 that macro arguments are not variables.
+.. _VERSION_GREATER_EQUAL:
 
-``if((condition) AND (condition OR (condition)))``
- The conditions inside the parenthesis are evaluated first and then
- the remaining condition is evaluated as in the previous examples.
- Where there are nested parenthesis the innermost are evaluated as part
- of evaluating the condition that contains them.
+``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
+  component effectively truncates the string at that point.
 
 Variable Expansion
 ^^^^^^^^^^^^^^^^^^
@@ -268,11 +342,12 @@ above-documented condition syntax accepts ``<variable|string>``:
   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.
 
-To prevent ambiguity, potential variable or keyword names can be
-specified in a :ref:`Quoted Argument` or a :ref:`Bracket Argument`.
-A quoted or bracketed variable or keyword will be interpreted as a
-string and not dereferenced or interpreted.
-See policy :policy:`CMP0054`.
+.. versionchanged:: 3.1
+  To prevent ambiguity, potential variable or keyword names can be
+  specified in a :ref:`Quoted Argument` or a :ref:`Bracket Argument`.
+  A quoted or bracketed variable or keyword will be interpreted as a
+  string and not dereferenced or interpreted.
+  See policy :policy:`CMP0054`.
 
 There is no automatic evaluation for environment or cache
 :ref:`Variable References`.  Their values must be referenced as
index 540a13a..4354654 100644 (file)
@@ -21,6 +21,7 @@ specify the type of project, id (``GUID``) of the project and the name of
 the target platform.  This is useful for projects requiring values
 other than the default (e.g.  WIX projects).
 
-If the imported project has different configuration names than the
-current project, set the :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>`
-target property to specify the mapping.
+.. versionadded:: 3.9
+  If the imported project has different configuration names than the
+  current project, set the :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>`
+  target property to specify the mapping.
index c11eaf4..35207f4 100644 (file)
@@ -20,10 +20,13 @@ Introduction
 
 This command generates installation rules for a project.  Install rules
 specified by calls to the ``install()`` command within a source directory
-are executed in order during installation.  Install rules in subdirectories
-added by calls to the :command:`add_subdirectory` command are interleaved
-with those in the parent directory to run in the order declared (see
-policy :policy:`CMP0082`).
+are executed in order during installation.
+
+.. versionchanged:: 3.14
+  Install rules in subdirectories
+  added by calls to the :command:`add_subdirectory` command are interleaved
+  with those in the parent directory to run in the order declared (see
+  policy :policy:`CMP0082`).
 
 There are multiple signatures for this command.  Some of them define
 installation options for files and targets.  Options common to
@@ -85,6 +88,8 @@ signatures that specify them.  The common options are:
   :variable:`CMAKE_INSTALL_DEFAULT_COMPONENT_NAME` variable.
 
 ``EXCLUDE_FROM_ALL``
+  .. versionadded:: 3.6
+
   Specify that the file is excluded from a full installation and only
   installed as part of a component-specific installation
 
@@ -97,16 +102,18 @@ signatures that specify them.  The common options are:
   Specify that it is not an error if the file to be installed does
   not exist.
 
-Command signatures that install files may print messages during
-installation.  Use the :variable:`CMAKE_INSTALL_MESSAGE` variable
-to control which messages are printed.
+.. versionadded:: 3.1
+  Command signatures that install files may print messages during
+  installation.  Use the :variable:`CMAKE_INSTALL_MESSAGE` variable
+  to control which messages are printed.
 
-Many of the ``install()`` variants implicitly create the directories
-containing the installed files. If
-:variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS` is set, these
-directories will be created with the permissions specified. Otherwise,
-they will be created according to the uname rules on Unix-like platforms.
-Windows platforms are unaffected.
+.. versionadded:: 3.11
+  Many of the ``install()`` variants implicitly create the directories
+  containing the installed files. If
+  :variable:`CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS` is set, these
+  directories will be created with the permissions specified. Otherwise,
+  they will be created according to the uname rules on Unix-like platforms.
+  Windows platforms are unaffected.
 
 Installing Targets
 ^^^^^^^^^^^^^^^^^^
@@ -162,6 +169,8 @@ that may be installed:
     accompanying import libraries are of kind ``ARCHIVE``).
 
 ``OBJECTS``
+  .. versionadded:: 3.9
+
   Object files associated with *object libraries*.
 
 ``FRAMEWORK``
@@ -246,6 +255,8 @@ In addition to the common options listed above, each target can accept
 the following additional arguments:
 
 ``NAMELINK_COMPONENT``
+  .. versionadded:: 3.12
+
   On some platforms a versioned shared library has a symbolic link such
   as::
 
@@ -357,17 +368,19 @@ targets that link to the object libraries in their implementation.
 Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property
 set to ``TRUE`` has undefined behavior.
 
-`install(TARGETS)`_ can install targets that were created in
-other directories.  When using such cross-directory install rules, running
-``make install`` (or similar) from a subdirectory will not guarantee that
-targets from other directories are up-to-date.  You can use
-:command:`target_link_libraries` or :command:`add_dependencies`
-to ensure that such out-of-directory targets are built before the
-subdirectory-specific install rules are run.
+.. versionadded:: 3.3
+  An install destination given as a ``DESTINATION`` argument may
+  use "generator expressions" with the syntax ``$<...>``.  See the
+  :manual:`cmake-generator-expressions(7)` manual for available expressions.
 
-An install destination given as a ``DESTINATION`` argument may
-use "generator expressions" with the syntax ``$<...>``.  See the
-:manual:`cmake-generator-expressions(7)` manual for available expressions.
+.. versionadded:: 3.13
+  `install(TARGETS)`_ can install targets that were created in
+  other directories.  When using such cross-directory install rules, running
+  ``make install`` (or similar) from a subdirectory will not guarantee that
+  targets from other directories are up-to-date.  You can use
+  :command:`target_link_libraries` or :command:`add_dependencies`
+  to ensure that such out-of-directory targets are built before the
+  subdirectory-specific install rules are run.
 
 Installing Files
 ^^^^^^^^^^^^^^^^
@@ -455,9 +468,15 @@ this advice while installing headers to a project-specific subdirectory:
           DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/myproj
   )
 
-An install destination given as a ``DESTINATION`` argument may
-use "generator expressions" with the syntax ``$<...>``.  See the
-:manual:`cmake-generator-expressions(7)` manual for available expressions.
+.. versionadded:: 3.4
+  An install destination given as a ``DESTINATION`` argument may
+  use "generator expressions" with the syntax ``$<...>``.  See the
+  :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+.. versionadded:: 3.20
+  An install rename given as a ``RENAME`` argument may
+  use "generator expressions" with the syntax ``$<...>``.  See the
+  :manual:`cmake-generator-expressions(7)` manual for available expressions.
 
 Installing Directories
 ^^^^^^^^^^^^^^^^^^^^^^
@@ -495,7 +514,8 @@ permissions specified in the ``FILES`` form of the command, and the
 directories will be given the default permissions specified in the
 ``PROGRAMS`` form of the command.
 
-The ``MESSAGE_NEVER`` option disables file installation status output.
+.. versionadded:: 3.1
+  The ``MESSAGE_NEVER`` option disables file installation status output.
 
 Installation of directories may be controlled with fine granularity
 using the ``PATTERN`` or ``REGEX`` options.  These "match" options specify a
@@ -579,10 +599,14 @@ path that begins with the appropriate :module:`GNUInstallDirs` variable.
 This allows package maintainers to control the install destination by setting
 the appropriate cache variables.
 
-The list of ``dirs...`` given to ``DIRECTORY`` and an install destination
-given as a ``DESTINATION`` argument may use "generator expressions"
-with the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
-manual for available expressions.
+.. versionadded:: 3.4
+  An install destination given as a ``DESTINATION`` argument may
+  use "generator expressions" with the syntax ``$<...>``.  See the
+  :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+.. versionadded:: 3.5
+  The list of ``dirs...`` given to ``DIRECTORY`` may use
+  "generator expressions" too.
 
 Custom Installation Logic
 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -610,10 +634,11 @@ example, the code
 
 will print a message during installation.
 
-``<file>`` or ``<code>`` may use "generator expressions" with the syntax
-``$<...>`` (in the case of ``<file>``, this refers to their use in the file
-name, not the file's contents).  See the
-:manual:`cmake-generator-expressions(7)` manual for available expressions.
+.. versionadded:: 3.14
+  ``<file>`` or ``<code>`` may use "generator expressions" with the syntax
+  ``$<...>`` (in the case of ``<file>``, this refers to their use in the file
+  name, not the file's contents).  See the
+  :manual:`cmake-generator-expressions(7)` manual for available expressions.
 
 Installing Exports
 ^^^^^^^^^^^^^^^^^^
@@ -673,13 +698,14 @@ RPM, typically handle this by listing the ``Runtime`` component as a dependency
 of the ``Development`` component in the package metadata, ensuring that the
 library is always installed if the headers and CMake export file are present.
 
-In addition to cmake language files, the ``EXPORT_ANDROID_MK`` mode maybe
-used to specify an export to the android ndk build system.  This mode
-accepts the same options as the normal export mode.  The Android
-NDK supports the use of prebuilt libraries, both static and shared. This
-allows cmake to build the libraries of a project and make them available
-to an ndk build system complete with transitive dependencies, include flags
-and defines required to use the libraries.
+.. versionadded:: 3.7
+  In addition to cmake language files, the ``EXPORT_ANDROID_MK`` mode maybe
+  used to specify an export to the android ndk build system.  This mode
+  accepts the same options as the normal export mode.  The Android
+  NDK supports the use of prebuilt libraries, both static and shared. This
+  allows cmake to build the libraries of a project and make them available
+  to an ndk build system complete with transitive dependencies, include flags
+  and defines required to use the libraries.
 
 The ``EXPORT`` form is useful to help outside projects use targets built
 and installed by the current project.  For example, the code
index 9cb8faa..6732402 100644 (file)
@@ -11,21 +11,25 @@ Adds the paths in which the linker should search for libraries.
 Relative paths given to this command are interpreted as relative to
 the current source directory, see :policy:`CMP0015`.
 
-The directories are added to the :prop_dir:`LINK_DIRECTORIES` directory
-property for the current ``CMakeLists.txt`` file, converting relative
-paths to absolute as needed.
 The command will apply only to targets created after it is called.
 
-By default the directories specified are appended onto the current list of
-directories.  This default behavior can be changed by setting
-:variable:`CMAKE_LINK_DIRECTORIES_BEFORE` to ``ON``.  By using
-``AFTER`` or ``BEFORE`` explicitly, you can select between appending and
-prepending, independent of the default.
-
-Arguments to ``link_directories`` may use "generator expressions" with
-the syntax "$<...>".  See the :manual:`cmake-generator-expressions(7)`
-manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
-manual for more on defining buildsystem properties.
+.. versionadded:: 3.13
+  The directories are added to the :prop_dir:`LINK_DIRECTORIES` directory
+  property for the current ``CMakeLists.txt`` file, converting relative
+  paths to absolute as needed.  See the :manual:`cmake-buildsystem(7)`
+  manual for more on defining buildsystem properties.
+
+.. versionadded:: 3.13
+  By default the directories specified are appended onto the current list of
+  directories.  This default behavior can be changed by setting
+  :variable:`CMAKE_LINK_DIRECTORIES_BEFORE` to ``ON``.  By using
+  ``AFTER`` or ``BEFORE`` explicitly, you can select between appending and
+  prepending, independent of the default.
+
+.. versionadded:: 3.13
+  Arguments to ``link_directories`` may use "generator expressions" with
+  the syntax "$<...>".  See the :manual:`cmake-generator-expressions(7)`
+  manual for available expressions.
 
 .. note::
 
index 4d339a0..7accc5a 100644 (file)
@@ -88,6 +88,8 @@ Returns the list of elements specified by indices from the list.
 
   list(JOIN <list> <glue> <output variable>)
 
+.. 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.
@@ -98,6 +100,8 @@ from :command:`string` command.
 
   list(SUBLIST <list> <begin> <length> <output variable>)
 
+.. 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
@@ -132,6 +136,8 @@ Appends elements to the list.
 
   list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)
 
+.. versionadded:: 3.6
+
 Includes or removes items from the list that match the mode's pattern.
 In ``REGEX`` mode, items will be matched against the given regular expression.
 
@@ -152,6 +158,8 @@ Inserts elements to the list to the specified location.
 
   list(POP_BACK <list> [<out-var>...])
 
+.. versionadded:: 3.15
+
 If no variable name is given, removes exactly one element. Otherwise,
 assign the last element's value to the given variable and removes it,
 up to the last variable name given.
@@ -162,6 +170,8 @@ up to the last variable name given.
 
   list(POP_FRONT <list> [<out-var>...])
 
+.. versionadded:: 3.15
+
 If no variable name is given, removes exactly one element. Otherwise,
 assign the first element's value to the given variable and removes it,
 up to the last variable name given.
@@ -172,6 +182,8 @@ up to the last variable name given.
 
   list(PREPEND <list> [<element> ...])
 
+.. versionadded:: 3.15
+
 Insert elements to the 0th position in the list.
 
 .. _REMOVE_ITEM:
@@ -206,6 +218,8 @@ but if duplicates are encountered, only the first instance is preserved.
   list(TRANSFORM <list> <ACTION> [<SELECTOR>]
                         [OUTPUT_VARIABLE <output variable>])
 
+.. 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.
@@ -302,6 +316,13 @@ Reverses the contents of the list in-place.
   list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])
 
 Sorts the list in-place alphabetically.
+
+.. versionadded:: 3.13
+  Added the ``COMPARE``, ``CASE``, and ``ORDER`` options.
+
+.. versionadded:: 3.18
+  Added the ``COMPARE NATURAL`` option.
+
 Use the ``COMPARE`` keyword to select the comparison method for sorting.
 The ``<compare>`` option should be one of:
 
index 797a90d..5fe4c00 100644 (file)
@@ -48,8 +48,9 @@ and so on. However, it is strongly recommended to stay with the
 case chosen in the macro definition.  Typically macros use
 all-lowercase names.
 
-The :command:`cmake_language(CALL ...)` command can also be used to
-invoke the macro.
+.. versionadded:: 3.18
+  The :command:`cmake_language(CALL ...)` command can also be used to
+  invoke the macro.
 
 Arguments
 ^^^^^^^^^
index e52e623..201363f 100644 (file)
@@ -23,8 +23,6 @@ new values will be marked as advanced, but if a
 variable already has an advanced/non-advanced state,
 it will not be changed.
 
-.. note::
-
-  Policy :policy:`CMP0102` affects the behavior of the ``mark_as_advanced``
-  call. When set to ``NEW``, variables passed to this command which are not
-  already in the cache are ignored. See policy :policy:`CMP0102`.
+.. versionchanged:: 3.17
+  Variables passed to this command which are not already in the cache
+  are ignored. See policy :policy:`CMP0102`.
index ddb1ec6..8386aab 100644 (file)
@@ -17,17 +17,18 @@ Supported operators are ``+``, ``-``, ``*``, ``/``, ``%``, ``|``, ``&``,
 ``^``, ``~``, ``<<``, ``>>``, and ``(...)``; they have the same meaning
 as in C code.
 
-Hexadecimal numbers are recognized when prefixed with ``0x``, as in C code.
-
-The result is formatted according to the option ``OUTPUT_FORMAT``,
-where ``<format>`` is one of
-
-``HEXADECIMAL``
-  Hexadecimal notation as in C code, i. e. starting with "0x".
-``DECIMAL``
-  Decimal notation. Which is also used if no ``OUTPUT_FORMAT`` option
-  is specified.
-
+.. versionadded:: 3.13
+  Hexadecimal numbers are recognized when prefixed with ``0x``, as in C code.
+
+.. versionadded:: 3.13
+  The result is formatted according to the option ``OUTPUT_FORMAT``,
+  where ``<format>`` is one of
+
+  ``HEXADECIMAL``
+    Hexadecimal notation as in C code, i. e. starting with "0x".
+  ``DECIMAL``
+    Decimal notation. Which is also used if no ``OUTPUT_FORMAT`` option
+    is specified.
 
 For example
 
index 6bc0e4c..e44803e 100644 (file)
@@ -71,6 +71,9 @@ influences the way the message is handled:
   using this log level would normally only be temporary and would expect to be
   removed before releasing the project, packaging up the files, etc.
 
+.. versionadded:: 3.15
+  Added the ``NOTICE``, ``VERBOSE``, ``DEBUG``, and ``TRACE`` levels.
+
 The CMake command-line tool displays ``STATUS`` to ``TRACE`` messages on stdout
 with the message preceded by two hyphens and a space.  All other message types
 are sent to stderr and are not prefixed with hyphens.  The
@@ -79,25 +82,29 @@ The :manual:`curses interface <ccmake(1)>` shows ``STATUS`` to ``TRACE``
 messages one at a time on a status line and other messages in an
 interactive pop-up box.  The ``--log-level`` command-line option to each of
 these tools can be used to control which messages will be shown.
-To make a log level persist between CMake runs, the
-:variable:`CMAKE_MESSAGE_LOG_LEVEL` variable can be set instead.
-Note that the command line option takes precedence over the cache variable.
-
-Messages of log levels ``NOTICE`` and below will have each line preceded
-by the content of the :variable:`CMAKE_MESSAGE_INDENT` variable (converted to
-a single string by concatenating its list items).  For ``STATUS`` to ``TRACE``
-messages, this indenting content will be inserted after the hyphens.
-
-Messages of log levels ``NOTICE`` and below can also have each line preceded
-with context of the form ``[some.context.example]``.  The content between the
-square brackets is obtained by converting the :variable:`CMAKE_MESSAGE_CONTEXT`
-list variable to a dot-separated string.  The message context will always
-appear before any indenting content but after any automatically added leading
-hyphens. By default, message context is not shown, it has to be explicitly
-enabled by giving the :manual:`cmake <cmake(1)>` ``--log-context``
-command-line option or by setting the :variable:`CMAKE_MESSAGE_CONTEXT_SHOW`
-variable to true.  See the :variable:`CMAKE_MESSAGE_CONTEXT` documentation for
-usage examples.
+
+.. versionadded:: 3.17
+  To make a log level persist between CMake runs, the
+  :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable can be set instead.
+  Note that the command line option takes precedence over the cache variable.
+
+.. versionadded:: 3.16
+  Messages of log levels ``NOTICE`` and below will have each line preceded
+  by the content of the :variable:`CMAKE_MESSAGE_INDENT` variable (converted to
+  a single string by concatenating its list items).  For ``STATUS`` to ``TRACE``
+  messages, this indenting content will be inserted after the hyphens.
+
+.. versionadded:: 3.17
+  Messages of log levels ``NOTICE`` and below can also have each line preceded
+  with context of the form ``[some.context.example]``.  The content between the
+  square brackets is obtained by converting the :variable:`CMAKE_MESSAGE_CONTEXT`
+  list variable to a dot-separated string.  The message context will always
+  appear before any indenting content but after any automatically added leading
+  hyphens. By default, message context is not shown, it has to be explicitly
+  enabled by giving the :manual:`cmake <cmake(1)>` ``--log-context``
+  command-line option or by setting the :variable:`CMAKE_MESSAGE_CONTEXT_SHOW`
+  variable to true.  See the :variable:`CMAKE_MESSAGE_CONTEXT` documentation for
+  usage examples.
 
 CMake Warning and Error message text displays using a simple markup
 language.  Non-indented text is formatted in line-wrapped paragraphs
@@ -107,6 +114,8 @@ delimited by newlines.  Indented text is considered pre-formatted.
 Reporting checks
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.17
+
 A common pattern in CMake output is a message indicating the start of some
 sort of check, followed by another message reporting the result of that check.
 For example:
index c325050..6c931b6 100644 (file)
@@ -55,10 +55,14 @@ The options are:
   * :variable:`PROJECT_VERSION_TWEAK`,
     :variable:`<PROJECT-NAME>_VERSION_TWEAK`.
 
-  When the ``project()`` command is called from the top-level ``CMakeLists.txt``,
-  then the version is also stored in the variable :variable:`CMAKE_PROJECT_VERSION`.
+  .. versionadded:: 3.12
+    When the ``project()`` command is called from the top-level
+    ``CMakeLists.txt``, then the version is also stored in the variable
+    :variable:`CMAKE_PROJECT_VERSION`.
 
 ``DESCRIPTION <project-description-string>``
+  .. versionadded:: 3.9
+
   Optional.
   Sets the variables
 
@@ -71,7 +75,12 @@ The options are:
   When the ``project()`` command is called from the top-level ``CMakeLists.txt``,
   then the description is also stored in the variable :variable:`CMAKE_PROJECT_DESCRIPTION`.
 
+  .. versionadded:: 3.12
+    Added the ``<PROJECT-NAME>_DESCRIPTION`` variable.
+
 ``HOMEPAGE_URL <url-string>``
+  .. versionadded:: 3.12
+
   Optional.
   Sets the variables
 
@@ -93,6 +102,15 @@ The options are:
   Specify language ``NONE``, or use the ``LANGUAGES`` keyword and list no languages,
   to skip enabling any languages.
 
+  .. versionadded:: 3.8
+    Added ``CUDA`` support.
+
+  .. versionadded:: 3.16
+    Added ``OBJC`` and ``OBJCXX`` support.
+
+  .. versionadded:: 3.18
+    Added ``ISPC`` support.
+
   If enabling ``ASM``, list it last so that CMake can check whether
   compilers for other languages like ``C`` work for assembly too.
 
@@ -115,6 +133,13 @@ they point to will be included as the last step of the ``project()`` command.
 If both are set, then :variable:`CMAKE_PROJECT_INCLUDE` will be included before
 :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`.
 
+.. versionadded:: 3.15
+  Added the ``CMAKE_PROJECT_INCLUDE`` and ``CMAKE_PROJECT_INCLUDE_BEFORE``
+  variables.
+
+.. versionadded:: 3.17
+  Added the ``CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`` variable.
+
 Usage
 ^^^^^
 
index 69fb726..f66af35 100644 (file)
@@ -32,10 +32,14 @@ be one of the following keywords:
   MSDN article `Parsing C Command-Line Arguments`_ for details.
 
 ``NATIVE_COMMAND``
+  .. versionadded:: 3.9
+
   Proceeds as in ``WINDOWS_COMMAND`` mode if the host system is Windows.
   Otherwise proceeds as in ``UNIX_COMMAND`` mode.
 
 ``PROGRAM``
+  .. versionadded:: 3.19
+
   The first item in ``<args>`` is assumed to be an executable and will be
   searched in the system search path or left as a full path. If not found,
   ``<variable>`` will be empty. Otherwise, ``<variable>`` is a list of 2
index b5c1613..bf437b4 100644 (file)
@@ -28,11 +28,12 @@ It must be one of the following:
 ``DIRECTORY``
   Scope defaults to the current directory but other directories
   (already processed by CMake) may be named by full or relative path.
-  Each path may reference either a source directory, or since CMake 3.19,
-  a binary directory.
   Relative paths are treated as relative to the current source directory.
   See also the :command:`set_directory_properties` command.
 
+  .. versionadded:: 3.19
+    ``<dir>`` may reference a binary directory.
+
 ``TARGET``
   Scope may name zero or more existing targets.
   See also the :command:`set_target_properties` command.
@@ -40,25 +41,31 @@ It must be one of the following:
 ``SOURCE``
   Scope may name zero or more source files.  By default, source file properties
   are only visible to targets added in the same directory (``CMakeLists.txt``).
-  Visibility can be set in other directory scopes using one or both of the
-  following sub-options:
-
-  ``DIRECTORY <dirs>...``
-    The source file property will be set in each of the ``<dirs>``
-    directories' scopes.  Each path may reference either a source directory,
-    or since CMake 3.19, a binary directory.  CMake must already know about
-    each of these directories, either by having added them through a call to
-    :command:`add_subdirectory` or it being the top level source directory.
-    Relative paths are treated as relative to the current source directory.
-
-  ``TARGET_DIRECTORY <targets>...``
-    The source file property will be set in each of the directory scopes
-    where any of the specified ``<targets>`` were created (the ``<targets>``
-    must therefore already exist).
+
+  .. versionadded:: 3.18
+    Visibility can be set in other directory scopes using one or both of the
+    following sub-options:
+
+    ``DIRECTORY <dirs>...``
+      The source file property will be set in each of the ``<dirs>``
+      directories' scopes.  CMake must already know about
+      each of these directories, either by having added them through a call to
+      :command:`add_subdirectory` or it being the top level source directory.
+      Relative paths are treated as relative to the current source directory.
+
+      .. versionadded:: 3.19
+        ``<dirs>`` may reference a binary directory.
+
+    ``TARGET_DIRECTORY <targets>...``
+      The source file property will be set in each of the directory scopes
+      where any of the specified ``<targets>`` were created (the ``<targets>``
+      must therefore already exist).
 
   See also the :command:`set_source_files_properties` command.
 
 ``INSTALL``
+  .. versionadded:: 3.1
+
   Scope may name zero or more installed file paths.
   These are made available to CPack to influence deployment.
 
@@ -98,3 +105,8 @@ directly set in the nominated scope, the command will behave as though
 
 See the :manual:`cmake-properties(7)` manual for a list of properties
 in each scope.
+
+.. note::
+
+  The :prop_sf:`GENERATED` source file property may be globally visible.
+  See its documentation for details.
index 9558b40..61c69a2 100644 (file)
@@ -14,9 +14,10 @@ Source files can have properties that affect how they are built.
 Sets properties associated with source files using a key/value paired
 list.
 
-By default, source file properties are only visible to targets added in the
-same directory (``CMakeLists.txt``).  Visibility can be set in other directory
-scopes using one or both of the following options:
+.. versionadded:: 3.18
+  By default, source file properties are only visible to targets added in the
+  same directory (``CMakeLists.txt``).  Visibility can be set in other directory
+  scopes using one or both of the following options:
 
 ``DIRECTORY <dirs>...``
   The source file properties will be set in each of the ``<dirs>``
@@ -35,3 +36,8 @@ See also the :command:`set_property(SOURCE)` command.
 
 See :ref:`Source File Properties` for the list of properties known
 to CMake.
+
+.. note::
+
+  The :prop_sf:`GENERATED` source file property may be globally visible.
+  See its documentation for details.
index 1bcaead..09b5a9f 100644 (file)
@@ -6,3 +6,7 @@ Set the given variable to the name of the computer.
 .. code-block:: cmake
 
   site_name(variable)
+
+On UNIX-like platforms, if the variable ``HOSTNAME`` is set, its value
+will be executed as a command expected to print out the host name,
+much like the ``hostname`` command-line tool.
index 5ae9e51..5db1ec8 100644 (file)
@@ -14,12 +14,16 @@ This is intended to set up file tabs in Visual Studio.
 The options are:
 
 ``TREE``
+ .. versionadded:: 3.8
+
  CMake will automatically detect, from ``<src>`` files paths, source groups
  it needs to create, to keep structure of source groups analogically to the
  actual files and directories structure in the project. Paths of ``<src>``
  files will be cut to be relative to ``<root>``.
 
 ``PREFIX``
+ .. versionadded:: 3.8
+
  Source group and files located directly in ``<root>`` path, will be placed
  in ``<prefix>`` source groups.
 
@@ -47,6 +51,9 @@ appropriately:
   source_group(outer\\inner ...)
   source_group(TREE <root> PREFIX sources\\inc ...)
 
+.. versionadded:: 3.18
+  Allow using forward slashes (``/``) to specify subgroups.
+
 For backwards compatibility, the short-hand signature
 
 .. code-block:: cmake
index 51f8d82..8ad0089 100644 (file)
@@ -170,10 +170,12 @@ The following characters have special meaning in regular expressions:
   Matches a pattern on either side of the ``|``
 ``()``
   Saves a matched subexpression, which can be referenced
-  in the ``REGEX REPLACE`` operation. Additionally it is saved
-  by all regular expression-related commands, including
-  e.g. :command:`if(MATCHES)`, in the variables
-  :variable:`CMAKE_MATCH_<n>` for ``<n>`` 0..9.
+  in the ``REGEX REPLACE`` operation.
+
+  .. versionadded:: 3.9
+    All regular expression-related commands, including e.g.
+    :command:`if(MATCHES)`, save subgroup matches in the variables
+    :variable:`CMAKE_MATCH_<n>` for ``<n>`` 0..9.
 
 ``*``, ``+`` and ``?`` have higher precedence than concatenation.  ``|``
 has lower precedence than concatenation.  This means that the regular
@@ -205,6 +207,8 @@ Manipulation
 
   string(APPEND <string_variable> [<input>...])
 
+.. versionadded:: 3.4
+
 Append all the ``<input>`` arguments to the string.
 
 .. _PREPEND:
@@ -213,6 +217,8 @@ Append all the ``<input>`` arguments to the string.
 
   string(PREPEND <string_variable> [<input>...])
 
+.. versionadded:: 3.10
+
 Prepend all the ``<input>`` arguments to the string.
 
 .. _CONCAT:
@@ -230,6 +236,8 @@ the result in the named ``<output_variable>``.
 
   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>``.
 
@@ -271,16 +279,15 @@ result stored in ``<output_variable>`` will *not* be the number of 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.  If ``<string>`` is shorter than ``<length>`` then the
-end of the string is used instead.
+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.
 
-.. note::
-  CMake 3.1 and below reported an error if ``<length>`` pointed past
-  the end of ``<string>``.
-
 .. _STRIP:
 
 .. code-block:: cmake
@@ -296,6 +303,8 @@ leading and trailing spaces removed.
 
   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>``.
 
@@ -305,6 +314,8 @@ from the input ``<string>`` and store the result in the ``<output_variable>``.
 
   string(REPEAT <string> <count> <output_variable>)
 
+.. versionadded:: 3.15
+
 Produce the output string as the input ``<string>`` repeated ``<count>`` times.
 
 Comparison
@@ -323,6 +334,9 @@ Comparison
 
 Compare the strings and store true or false in the ``<output_variable>``.
 
+.. versionadded:: 3.7
+  Added the ``LESS_EQUAL`` and ``GREATER_EQUAL`` options.
+
 .. _`Supported Hash Algorithms`:
 
 Hashing
@@ -358,6 +372,9 @@ The supported ``<HASH>`` algorithm names are:
 ``SHA3_512``
   Keccak SHA-3.
 
+.. versionadded:: 3.8
+  Added the ``SHA3_*`` hash algorithms.
+
 Generation
 ^^^^^^^^^^
 
@@ -375,6 +392,8 @@ Convert all numbers into corresponding ASCII characters.
 
   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.
@@ -451,6 +470,18 @@ specifiers:
    %y        The last two digits of the current year (00-99)
    %Y        The current year.
 
+.. versionadded:: 3.6
+  ``%s`` format specifier (UNIX time).
+
+.. versionadded:: 3.7
+  ``%a`` and ``%b`` format specifiers (abbreviated month and weekday names).
+
+.. versionadded:: 3.8
+  ``%%`` specifier (literal ``%``).
+
+.. versionadded:: 3.7
+  ``%A`` and ``%B`` format specifiers (full month and weekday names).
+
 Unknown format specifiers will be ignored and copied to the output
 as-is.
 
@@ -461,8 +492,7 @@ If no explicit ``<format_string>`` is given, it will default to:
    %Y-%m-%dT%H:%M:%S    for local time.
    %Y-%m-%dT%H:%M:%SZ   for UTC.
 
-.. note::
-
+.. 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.
@@ -474,6 +504,8 @@ If no explicit ``<format_string>`` is given, it will default to:
   string(UUID <output_variable> NAMESPACE <namespace> NAME <name>
          TYPE <MD5|SHA1> [UPPER])
 
+.. 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>``.
@@ -489,6 +521,8 @@ with the optional ``UPPER`` flag.
 JSON
 ^^^^
 
+.. versionadded:: 3.19
+
 Functionality for querying a JSON string.
 
 .. note::
index 9e9c690..3fb113a 100644 (file)
@@ -19,10 +19,12 @@ specify the scope of the following arguments.  ``PRIVATE`` and ``PUBLIC``
 items will populate the :prop_tgt:`COMPILE_DEFINITIONS` property of
 ``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
 :prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` property of ``<target>``.
-(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
 The following arguments specify compile definitions.  Repeated calls for the
 same ``<target>`` append items in the order called.
 
+.. versionadded:: 3.11
+  Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
 Arguments to ``target_compile_definitions`` may use "generator expressions"
 with the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
@@ -37,3 +39,12 @@ For example, the following are all equivalent:
   target_compile_definitions(foo PUBLIC -DFOO)  # -D removed
   target_compile_definitions(foo PUBLIC "" FOO) # "" ignored
   target_compile_definitions(foo PUBLIC -D FOO) # -D becomes "", then ignored
+
+Definitions may optionally have values:
+
+.. code-block:: cmake
+
+  target_compile_definitions(foo PUBLIC FOO=1)
+
+Note that many compilers treat ``-DFOO`` as equivalent to ``-DFOO=1``, but
+other tools may not recognize this in all circumstances (e.g. IntelliSense).
index b50be34..58502bf 100644 (file)
@@ -21,9 +21,11 @@ specify the scope of the features.  ``PRIVATE`` and ``PUBLIC`` items will
 populate the :prop_tgt:`COMPILE_FEATURES` property of ``<target>``.
 ``PUBLIC`` and ``INTERFACE`` items will populate the
 :prop_tgt:`INTERFACE_COMPILE_FEATURES` property of ``<target>``.
-(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
 Repeated calls for the same ``<target>`` append items.
 
+.. versionadded:: 3.11
+  Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
 The named ``<target>`` must have been created by a command such as
 :command:`add_executable` or :command:`add_library` and must not be an
 :ref:`ALIAS target <Alias Targets>`.
index 3c733c5..e45b209 100644 (file)
@@ -26,10 +26,12 @@ specify the scope of the following arguments.  ``PRIVATE`` and ``PUBLIC``
 items will populate the :prop_tgt:`COMPILE_OPTIONS` property of
 ``<target>``.  ``PUBLIC`` and ``INTERFACE`` items will populate the
 :prop_tgt:`INTERFACE_COMPILE_OPTIONS` property of ``<target>``.
-(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
 The following arguments specify compile options.  Repeated calls for the same
 ``<target>`` append items in the order called.
 
+.. versionadded:: 3.11
+  Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
 Arguments to ``target_compile_options`` may use "generator expressions"
 with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
index 660e15c..3e53b2e 100644 (file)
@@ -5,7 +5,7 @@ Add include directories to a target.
 
 .. code-block:: cmake
 
-  target_include_directories(<target> [SYSTEM] [BEFORE]
+  target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
     <INTERFACE|PUBLIC|PRIVATE> [items1...]
     [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
 
@@ -14,17 +14,19 @@ The named ``<target>`` must have been created by a command such
 as :command:`add_executable` or :command:`add_library` and must not be an
 :ref:`ALIAS target <Alias Targets>`.
 
-If ``BEFORE`` is specified, the content will be prepended to the property
-instead of being appended.
+By using ``AFTER`` or ``BEFORE`` explicitly, you can select between appending
+and prepending, independent of the default.
 
 The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to specify
 the scope of the following arguments.  ``PRIVATE`` and ``PUBLIC`` items will
 populate the :prop_tgt:`INCLUDE_DIRECTORIES` property of ``<target>``.
 ``PUBLIC`` and ``INTERFACE`` items will populate the
 :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` property of ``<target>``.
-(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
 The following arguments specify include directories.
 
+.. versionadded:: 3.11
+  Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
+
 Specified include directories may be absolute paths or relative paths.
 Repeated calls for the same <target> append items in the order called.  If
 ``SYSTEM`` is specified, the compiler will be told the
index c2e7e8a..872e264 100644 (file)
@@ -27,6 +27,10 @@ set to ``NEW`` then the target must have been created in the current
 directory.  Repeated calls for the same ``<target>`` append items in
 the order called.
 
+.. versionadded:: 3.13
+  The ``<target>`` doesn't have to be defined in the same directory as the
+  ``target_link_libraries`` call.
+
 Each ``<item>`` may be:
 
 * **A library target name**: The generated link line will have the
@@ -62,10 +66,11 @@ Each ``<item>`` may be:
   :ref:`usage requirement <Target Usage Requirements>`.  This has the same
   effect as passing the framework directory as an include directory.
 
-  On :ref:`Visual Studio Generators` for VS 2010 and above, library files
-  ending in ``.targets`` will be treated as MSBuild targets files and
-  imported into generated project files.  This is not supported by other
-  generators.
+  .. versionadded:: 3.8
+    On :ref:`Visual Studio Generators` for VS 2010 and above, library files
+    ending in ``.targets`` will be treated as MSBuild targets files and
+    imported into generated project files.  This is not supported by other
+    generators.
 
   The full path to the library file will be quoted/escaped for
   the shell automatically.
@@ -89,6 +94,11 @@ Each ``<item>`` may be:
   flags explicitly. The flags will then be placed at the toolchain-defined
   flag position in the link command.
 
+  .. versionadded:: 3.13
+    :prop_tgt:`LINK_OPTIONS` target property and :command:`target_link_options`
+    command.  For earlier versions of CMake, use :prop_tgt:`LINK_FLAGS`
+    property instead.
+
   The link flag is treated as a command-line string fragment and
   will be used with no extra quoting or escaping.
 
@@ -216,6 +226,8 @@ is not ``NEW``, they are also appended to the
 Linking Object Libraries
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.12
+
 :ref:`Object Libraries` may be used as the ``<target>`` (first) argument
 of ``target_link_libraries`` to specify dependencies of their sources
 on other libraries.  For example, the code
index e59e0e1..87dff39 100644 (file)
@@ -36,10 +36,12 @@ specify the scope of the following arguments.  ``PRIVATE`` and ``PUBLIC``
 items will populate the :prop_tgt:`LINK_OPTIONS` property of
 ``<target>``.  ``PUBLIC`` and ``INTERFACE`` items will populate the
 :prop_tgt:`INTERFACE_LINK_OPTIONS` property of ``<target>``.
-(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
 The following arguments specify link options.  Repeated calls for the same
 ``<target>`` append items in the order called.
 
+.. note::
+  :ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.
+
 Arguments to ``target_link_options`` may use "generator expressions"
 with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
index 7005180..9f7dabb 100644 (file)
@@ -34,7 +34,7 @@ Repeated calls for the same ``<target>`` will append items in the order called.
 
 Projects should generally avoid using ``PUBLIC`` or ``INTERFACE`` for targets
 that will be :ref:`exported <install(EXPORT)>`, or they should at least use
-the ``$<BUILD_INTERFACE:...>`` generator expression to prevent precompile
+the :genex:`$<BUILD_INTERFACE:...>` generator expression to prevent precompile
 headers from appearing in an installed exported target.  Consumers of a target
 should typically be in control of what precompile headers they use, not have
 precompile headers forced on them by the targets being consumed (since
@@ -74,7 +74,7 @@ Arguments to ``target_precompile_headers()`` may use "generator expressions"
 with the syntax ``$<...>``.
 See the :manual:`cmake-generator-expressions(7)` manual for available
 expressions.
-The ``$<COMPILE_LANGUAGE:...>`` generator expression is particularly
+The :genex:`$<COMPILE_LANGUAGE:...>` generator expression is particularly
 useful for specifying a language-specific header to precompile for
 only one language (e.g. ``CXX`` and not ``C``).  In this case, header
 file names that are not explicitly in double quotes or angle brackets
index 653b8d7..520614a 100644 (file)
@@ -12,27 +12,37 @@ Add sources to a target.
     [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
 
 Specifies sources to use when building a target and/or its dependents.
-Relative source file paths are interpreted as being relative to the current
-source directory (i.e. :variable:`CMAKE_CURRENT_SOURCE_DIR`).  The
-named ``<target>`` must have been created by a command such as
-:command:`add_executable` or :command:`add_library` and must not be an
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` or
+:command:`add_custom_target` and must not be an
 :ref:`ALIAS target <Alias Targets>`.
 
+.. versionchanged:: 3.13
+  Relative source file paths are interpreted as being relative to the current
+  source directory (i.e. :variable:`CMAKE_CURRENT_SOURCE_DIR`).
+  See policy :policy:`CMP0076`.
+
+.. versionadded:: 3.20
+  ``<target>`` can be a custom target.
+
 The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
 specify the scope of the items following them.  ``PRIVATE`` and ``PUBLIC``
 items will populate the :prop_tgt:`SOURCES` property of
 ``<target>``, which are used when building the target itself.
 ``PUBLIC`` and ``INTERFACE`` items will populate the
 :prop_tgt:`INTERFACE_SOURCES` property of ``<target>``, which are used
-when building dependents.  (:ref:`IMPORTED targets <Imported Targets>`
-only support ``INTERFACE`` items because they are not build targets.)
+when building dependents.
 The following arguments specify sources.  Repeated calls for the same
-``<target>`` append items in the order called.
+``<target>`` append items in the order called. The targets created by
+:command:`add_custom_target` can only have ``PRIVATE`` scope.
+
+.. versionadded:: 3.3
+  Allow exporting targets with :prop_tgt:`INTERFACE_SOURCES`.
+
+.. versionadded:: 3.11
+  Allow setting ``INTERFACE`` items on :ref:`IMPORTED targets <Imported Targets>`.
 
 Arguments to ``target_sources`` may use "generator expressions"
 with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for more on defining buildsystem properties.
-
-See also the :policy:`CMP0076` policy for older behavior related to the
-handling of relative source file paths.
index 323077a..06da910 100644 (file)
@@ -19,6 +19,10 @@ Try Compiling Whole Projects
 Try building a project.  The success or failure of the ``try_compile``,
 i.e. ``TRUE`` or ``FALSE`` respectively, is returned in ``<resultVar>``.
 
+.. versionadded:: 3.14
+  The name of the ``<resultVar>`` is defined by the user.  Previously, it had
+  a fixed name ``RESULT_VAR``.
+
 In this form, ``<srcdir>`` should contain a complete CMake project with a
 ``CMakeLists.txt`` file and all sources.  The ``<bindir>`` and ``<srcdir>``
 will not be deleted after this command is run.  Specify ``<targetName>`` to
@@ -47,6 +51,10 @@ Try building an executable or static library from one or more source files
 variable).  The success or failure of the ``try_compile``, i.e. ``TRUE`` or
 ``FALSE`` respectively, is returned in ``<resultVar>``.
 
+.. versionadded:: 3.14
+  The name of the ``<resultVar>`` is defined by the user.  Previously, it had
+  a fixed name ``RESULT_VAR``.
+
 In this form, one or more source files must be provided.  If
 :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` is unset or is set to ``EXECUTABLE``,
 the sources must include a definition for ``main`` and CMake will create a
@@ -94,6 +102,8 @@ The options are:
   given to the ``CMAKE_FLAGS`` option will be ignored.
 
 ``LINK_OPTIONS <options>...``
+  .. versionadded:: 3.14
+
   Specify link step options to pass to :command:`target_link_options` or to
   set the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property in the generated
   project, depending on the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable.
@@ -102,17 +112,23 @@ The options are:
   Store the output from the build process in the given variable.
 
 ``<LANG>_STANDARD <std>``
+  .. versionadded:: 3.8
+
   Specify the :prop_tgt:`C_STANDARD`, :prop_tgt:`CXX_STANDARD`,
   :prop_tgt:`OBJC_STANDARD`, :prop_tgt:`OBJCXX_STANDARD`,
   or :prop_tgt:`CUDA_STANDARD` target property of the generated project.
 
 ``<LANG>_STANDARD_REQUIRED <bool>``
+  .. versionadded:: 3.8
+
   Specify the :prop_tgt:`C_STANDARD_REQUIRED`,
   :prop_tgt:`CXX_STANDARD_REQUIRED`, :prop_tgt:`OBJC_STANDARD_REQUIRED`,
   :prop_tgt:`OBJCXX_STANDARD_REQUIRED`,or :prop_tgt:`CUDA_STANDARD_REQUIRED`
   target property of the generated project.
 
 ``<LANG>_EXTENSIONS <bool>``
+  .. versionadded:: 3.8
+
   Specify the :prop_tgt:`C_EXTENSIONS`, :prop_tgt:`CXX_EXTENSIONS`,
   :prop_tgt:`OBJC_EXTENSIONS`, :prop_tgt:`OBJCXX_EXTENSIONS`,
   or :prop_tgt:`CUDA_EXTENSIONS` target property of the generated project.
@@ -131,24 +147,26 @@ the try_compile call of interest, and then re-run cmake again with
 Other Behavior Settings
 ^^^^^^^^^^^^^^^^^^^^^^^
 
-If set, the following variables are passed in to the generated
-try_compile CMakeLists.txt to initialize compile target properties with
-default values:
+.. versionadded:: 3.4
+  If set, the following variables are passed in to the generated
+  try_compile CMakeLists.txt to initialize compile target properties with
+  default values:
 
-* :variable:`CMAKE_CUDA_RUNTIME_LIBRARY`
-* :variable:`CMAKE_ENABLE_EXPORTS`
-* :variable:`CMAKE_LINK_SEARCH_START_STATIC`
-* :variable:`CMAKE_LINK_SEARCH_END_STATIC`
-* :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
-* :variable:`CMAKE_POSITION_INDEPENDENT_CODE`
+  * :variable:`CMAKE_CUDA_RUNTIME_LIBRARY`
+  * :variable:`CMAKE_ENABLE_EXPORTS`
+  * :variable:`CMAKE_LINK_SEARCH_START_STATIC`
+  * :variable:`CMAKE_LINK_SEARCH_END_STATIC`
+  * :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
+  * :variable:`CMAKE_POSITION_INDEPENDENT_CODE`
 
-If :policy:`CMP0056` is set to ``NEW``, then
-:variable:`CMAKE_EXE_LINKER_FLAGS` is passed in as well.
+  If :policy:`CMP0056` is set to ``NEW``, then
+  :variable:`CMAKE_EXE_LINKER_FLAGS` is passed in as well.
 
-If :policy:`CMP0083` is set to ``NEW``, then in order to obtain correct
-behavior at link time, the ``check_pie_supported()`` command from the
-:module:`CheckPIESupported` module must be called before using the
-:command:`try_compile` command.
+.. versionchanged:: 3.14
+  If :policy:`CMP0083` is set to ``NEW``, then in order to obtain correct
+  behavior at link time, the ``check_pie_supported()`` command from the
+  :module:`CheckPIESupported` module must be called before using the
+  :command:`try_compile` command.
 
 The current settings of :policy:`CMP0065` and :policy:`CMP0083` are propagated
 through to the generated test project.
@@ -156,37 +174,41 @@ through to the generated test project.
 Set the :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` variable to choose
 a build configuration.
 
-Set the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to specify
-the type of target used for the source file signature.
-
-Set the :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable to specify
-variables that must be propagated into the test project.  This variable is
-meant for use only in toolchain files and is only honored by the
-``try_compile()`` command for the source files form, not when given a whole
-project.
-
-If :policy:`CMP0067` is set to ``NEW``, or any of the ``<LANG>_STANDARD``,
-``<LANG>_STANDARD_REQUIRED``, or ``<LANG>_EXTENSIONS`` options are used,
-then the language standard variables are honored:
-
-* :variable:`CMAKE_C_STANDARD`
-* :variable:`CMAKE_C_STANDARD_REQUIRED`
-* :variable:`CMAKE_C_EXTENSIONS`
-* :variable:`CMAKE_CXX_STANDARD`
-* :variable:`CMAKE_CXX_STANDARD_REQUIRED`
-* :variable:`CMAKE_CXX_EXTENSIONS`
-* :variable:`CMAKE_OBJC_STANDARD`
-* :variable:`CMAKE_OBJC_STANDARD_REQUIRED`
-* :variable:`CMAKE_OBJC_EXTENSIONS`
-* :variable:`CMAKE_OBJCXX_STANDARD`
-* :variable:`CMAKE_OBJCXX_STANDARD_REQUIRED`
-* :variable:`CMAKE_OBJCXX_EXTENSIONS`
-* :variable:`CMAKE_CUDA_STANDARD`
-* :variable:`CMAKE_CUDA_STANDARD_REQUIRED`
-* :variable:`CMAKE_CUDA_EXTENSIONS`
-
-Their values are used to set the corresponding target properties in
-the generated project (unless overridden by an explicit option).
-
-For the :generator:`Green Hills MULTI` generator the GHS toolset and target
-system customization cache variables are also propagated into the test project.
+.. versionadded:: 3.6
+  Set the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to specify
+  the type of target used for the source file signature.
+
+.. versionadded:: 3.6
+  Set the :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable to specify
+  variables that must be propagated into the test project.  This variable is
+  meant for use only in toolchain files and is only honored by the
+  ``try_compile()`` command for the source files form, not when given a whole
+  project.
+
+.. versionchanged:: 3.8
+  If :policy:`CMP0067` is set to ``NEW``, or any of the ``<LANG>_STANDARD``,
+  ``<LANG>_STANDARD_REQUIRED``, or ``<LANG>_EXTENSIONS`` options are used,
+  then the language standard variables are honored:
+
+  * :variable:`CMAKE_C_STANDARD`
+  * :variable:`CMAKE_C_STANDARD_REQUIRED`
+  * :variable:`CMAKE_C_EXTENSIONS`
+  * :variable:`CMAKE_CXX_STANDARD`
+  * :variable:`CMAKE_CXX_STANDARD_REQUIRED`
+  * :variable:`CMAKE_CXX_EXTENSIONS`
+  * :variable:`CMAKE_OBJC_STANDARD`
+  * :variable:`CMAKE_OBJC_STANDARD_REQUIRED`
+  * :variable:`CMAKE_OBJC_EXTENSIONS`
+  * :variable:`CMAKE_OBJCXX_STANDARD`
+  * :variable:`CMAKE_OBJCXX_STANDARD_REQUIRED`
+  * :variable:`CMAKE_OBJCXX_EXTENSIONS`
+  * :variable:`CMAKE_CUDA_STANDARD`
+  * :variable:`CMAKE_CUDA_STANDARD_REQUIRED`
+  * :variable:`CMAKE_CUDA_EXTENSIONS`
+
+  Their values are used to set the corresponding target properties in
+  the generated project (unless overridden by an explicit option).
+
+.. versionchanged:: 3.14
+  For the :generator:`Green Hills MULTI` generator the GHS toolset and target
+  system customization cache variables are also propagated into the test project.
index d401ebe..404de98 100644 (file)
@@ -20,6 +20,7 @@ Try Compiling and Running Source Files
           [COMPILE_OUTPUT_VARIABLE <var>]
           [RUN_OUTPUT_VARIABLE <var>]
           [OUTPUT_VARIABLE <var>]
+          [WORKING_DIRECTORY <var>]
           [ARGS <args>...])
 
 Try compiling a ``<srcfile>``.  Returns ``TRUE`` or ``FALSE`` for success
@@ -29,6 +30,11 @@ executable was built, but failed to run, then ``<runResultVar>`` will be
 set to ``FAILED_TO_RUN``.  See the :command:`try_compile` command for
 information on how the test project is constructed to build the source file.
 
+.. versionadded:: 3.14
+  The names of the result variables ``<runResultVar>`` and
+  ``<compileResultVar>`` are defined by the user.  Previously, they had
+  fixed names ``RUN_RESULT_VAR`` and ``COMPILE_RESULT_VAR``.
+
 The options are:
 
 ``CMAKE_FLAGS <flags>...``
@@ -46,6 +52,8 @@ The options are:
   Report the compile step build output in a given variable.
 
 ``LINK_LIBRARIES <libs>...``
+  .. versionadded:: 3.2
+
   Specify libraries to be linked in the generated project.
   The list of libraries may refer to system libraries and to
   :ref:`Imported Targets <Imported Targets>` from the calling project.
@@ -54,6 +62,8 @@ The options are:
   given to the ``CMAKE_FLAGS`` option will be ignored.
 
 ``LINK_OPTIONS <options>...``
+  .. versionadded:: 3.14
+
   Specify link step options to pass to :command:`target_link_options` in the
   generated project.
 
@@ -65,6 +75,12 @@ The options are:
 ``RUN_OUTPUT_VARIABLE <var>``
   Report the output from running the executable in a given variable.
 
+``WORKING_DIRECTORY <var>``
+  .. versionadded:: 3.20
+
+  Run the executable in the given directory. If no ``WORKING_DIRECTORY`` is
+  specified, the executable will run in ``<bindir>``.
+
 Other Behavior Settings
 ^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -74,6 +90,10 @@ a build configuration.
 Behavior when Cross Compiling
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.3
+  Use ``CMAKE_CROSSCOMPILING_EMULATOR`` when running cross-compiled
+  binaries.
+
 When cross compiling, the executable compiled in the first step
 usually cannot be run on the build host.  The ``try_run`` command checks
 the :variable:`CMAKE_CROSSCOMPILING` variable to detect whether CMake is in
index 3656aa2..b941812 100644 (file)
@@ -12,6 +12,12 @@ any of the following formats:
   - TZST (.tar.zst)
   - ZIP (.zip)
 
+.. versionadded:: 3.1
+  ``7Z`` and ``TXZ`` formats support.
+
+.. versionadded:: 3.16
+  ``TZST`` format support.
+
 When this generator is called from ``CPackSourceConfig.cmake`` (or through
 the ``package_source`` target), then the generated archive will contain all
 files in the project directory, except those specified in
@@ -46,6 +52,9 @@ Variables specific to CPack Archive generator
   The default is ``<CPACK_PACKAGE_FILE_NAME>[-<component>]``, with spaces
   replaced by '-'.
 
+  .. versionadded:: 3.9
+    Per-component ``CPACK_ARCHIVE_<component>_FILE_NAME`` variables.
+
 .. variable:: CPACK_ARCHIVE_COMPONENT_INSTALL
 
   Enable component packaging. If enabled (ON), then the archive generator
@@ -63,12 +72,16 @@ CPack generators which are essentially archives at their core. These include:
 
 .. variable:: CPACK_ARCHIVE_THREADS
 
+  .. versionadded:: 3.18
+
   The number of threads to use when performing the compression. If set to
   ``0``, the number of available cores on the machine will be used instead.
   The default is ``1`` which limits compression to a single thread. Note that
   not all compression modes support threading in all environments. Currently,
   only the XZ compression may support it.
 
+  See also the :variable:`CPACK_THREADS` variable.
+
 .. note::
 
     Official CMake binaries available on ``cmake.org`` ship with a ``liblzma``
index b16dbda..5e335c0 100644 (file)
@@ -36,6 +36,8 @@ Bundle-specific parameters (``CPACK_BUNDLE_xxx``).
 
 .. variable:: CPACK_BUNDLE_APPLE_CERT_APP
 
+ .. versionadded:: 3.2
+
  The name of your Apple supplied code signing certificate for the application.
  The name usually takes the form ``Developer ID Application: [Name]`` or
  ``3rd Party Mac Developer Application: [Name]``. If this variable is not set
@@ -43,23 +45,31 @@ Bundle-specific parameters (``CPACK_BUNDLE_xxx``).
 
 .. variable:: CPACK_BUNDLE_APPLE_ENTITLEMENTS
 
+ .. versionadded:: 3.2
+
  The name of the Property List (``.plist``) file that contains your Apple
  entitlements for sandboxing your application. This file is required
  for submission to the macOS App Store.
 
 .. variable:: CPACK_BUNDLE_APPLE_CODESIGN_FILES
 
+ .. versionadded:: 3.2
+
  A list of additional files that you wish to be signed. You do not need to
  list the main application folder, or the main executable. You should
  list any frameworks and plugins that are included in your app bundle.
 
 .. variable:: CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER
 
+ .. versionadded:: 3.3
+
  Additional parameter that will passed to ``codesign``.
  Default value: ``--deep -f``
 
 .. variable:: CPACK_COMMAND_CODESIGN
 
+ .. versionadded:: 3.2
+
  Path to the ``codesign(1)`` command used to sign applications with an
  Apple cert. This variable can be used to override the automatically
  detected command (or specify its location if the auto-detection fails
index c65653e..c537a79 100644 (file)
@@ -6,7 +6,9 @@ Cygwin CPack generator (Cygwin).
 Variables affecting the CPack Cygwin generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-  - :variable:`CPACK_ARCHIVE_THREADS`
+- .. versionadded:: 3.18
+    :variable:`CPACK_ARCHIVE_THREADS`
+
 
 Variables specific to CPack Cygwin generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index bf50c55..03c4ea8 100644 (file)
@@ -54,11 +54,16 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_NAME` suffixed with -<COMPONENT>
      for component-based installations.
 
+ .. versionadded:: 3.5
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_NAME`` variables.
+
  See https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source
 
 .. variable:: CPACK_DEBIAN_FILE_NAME
               CPACK_DEBIAN_<COMPONENT>_FILE_NAME
 
+ .. versionadded:: 3.6
+
  Package file name.
 
  * Mandatory : YES
@@ -72,6 +77,9 @@ List of CPack DEB generator specific variables:
  Alternatively provided package file name must end
  with either ``.deb`` or ``.ipk`` suffix.
 
+ .. versionadded:: 3.10
+  ``.ipk`` suffix used by OPKG packaging system.
+
  .. note::
 
    Preferred setting of this variable is ``DEB-DEFAULT`` but for backward
@@ -86,6 +94,8 @@ List of CPack DEB generator specific variables:
 
 .. variable:: CPACK_DEBIAN_PACKAGE_EPOCH
 
+ .. versionadded:: 3.10
+
  The Debian package epoch
 
  * Mandatory : No
@@ -116,6 +126,8 @@ List of CPack DEB generator specific variables:
 
 .. variable:: CPACK_DEBIAN_PACKAGE_RELEASE
 
+ .. versionadded:: 3.6
+
  The Debian package release - Debian revision number.
 
  * Mandatory : No
@@ -136,6 +148,9 @@ List of CPack DEB generator specific variables:
  * Default   : Output of ``dpkg --print-architecture`` (or ``i386``
    if ``dpkg`` is not found)
 
+ .. versionadded:: 3.6
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_ARCHITECTURE`` variables.
+
 .. variable:: CPACK_DEBIAN_PACKAGE_DEPENDS
               CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS
 
@@ -148,6 +163,10 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_DEPENDS` for component-based
      installations.
 
+
+ .. versionadded:: 3.3
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS`` variables.
+
  .. note::
 
    If :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS` or
@@ -165,7 +184,9 @@ List of CPack DEB generator specific variables:
 
 .. variable:: CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS
 
- Sets inter component dependencies if listed with
+ .. versionadded:: 3.6
+
+ Sets inter-component dependencies if listed with
  :variable:`CPACK_COMPONENT_<compName>_DEPENDS` variables.
 
  * Mandatory : NO
@@ -196,6 +217,15 @@ List of CPack DEB generator specific variables:
  used if set. Otherwise, :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` will be added as the first
  line of description as defined in `Debian Policy Manual`_.
 
+ .. versionadded:: 3.3
+  Per-component ``CPACK_COMPONENT_<compName>_DESCRIPTION`` variables.
+
+ .. versionadded:: 3.16
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_DESCRIPTION`` variables.
+
+ .. versionadded:: 3.16
+  The ``CPACK_PACKAGE_DESCRIPTION_FILE`` variable.
+
 .. _Debian Policy Manual: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description
 
 .. variable:: CPACK_DEBIAN_PACKAGE_SECTION
@@ -206,10 +236,17 @@ List of CPack DEB generator specific variables:
  * Mandatory : YES
  * Default   : "devel"
 
+ .. versionadded:: 3.5
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION`` variables.
+
  See https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
 
 .. variable:: CPACK_DEBIAN_ARCHIVE_TYPE
 
+ .. versionadded:: 3.7
+
+ .. deprecated:: 3.14
+
  The archive format used for creating the Debian package.
 
  * Mandatory : YES
@@ -228,6 +265,8 @@ List of CPack DEB generator specific variables:
 
 .. variable:: CPACK_DEBIAN_COMPRESSION_TYPE
 
+ .. versionadded:: 3.1
+
  The compression used for creating the Debian package.
 
  * Mandatory : YES
@@ -249,6 +288,9 @@ List of CPack DEB generator specific variables:
  * Mandatory : YES
  * Default   : "optional"
 
+ .. versionadded:: 3.5
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY`` varables.
+
  See https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities
 
 .. variable:: CPACK_DEBIAN_PACKAGE_HOMEPAGE
@@ -260,6 +302,9 @@ List of CPack DEB generator specific variables:
  * Mandatory : NO
  * Default   : :variable:`CMAKE_PROJECT_HOMEPAGE_URL`
 
+ .. versionadded:: 3.12
+  The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+
  .. note::
 
    The content of this field is a simple URL without any surrounding
@@ -284,6 +329,36 @@ List of CPack DEB generator specific variables:
    may fail to find your own shared libs.
    See https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling
 
+ .. note::
+
+   You can also set :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS`
+   to an appropriate value if you use this feature, in order to please
+   ``dpkg-shlibdeps``. However, you should only do this for private
+   shared libraries that could not get resolved otherwise.
+
+ .. versionadded:: 3.3
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS`` variables.
+
+ .. versionadded:: 3.6
+  Correct handling of ``$ORIGIN`` in :variable:`CMAKE_INSTALL_RPATH`.
+
+.. variable:: CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS
+
+ .. versionadded:: 3.20
+
+ May be set to a list of directories that will be given to ``dpkg-shlibdeps``
+ via its ``-l`` option. These will be searched by ``dpkg-shlibdeps`` in order
+ to find private shared library dependencies.
+
+ * Mandatory : NO
+ * Default   :
+
+ .. note::
+
+   You should prefer to set :variable:`CMAKE_INSTALL_RPATH` to an appropriate
+   value if you use ``dpkg-shlibdeps``. The current option is really only
+   needed for private shared library dependencies.
+
 .. variable:: CPACK_DEBIAN_PACKAGE_DEBUG
 
  May be set when invoking cpack in order to trace debug information
@@ -308,6 +383,9 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_PREDEPENDS` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_PREDEPENDS`` variables.
+
  See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
 
 .. variable:: CPACK_DEBIAN_PACKAGE_ENHANCES
@@ -325,6 +403,9 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_ENHANCES` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_ENHANCES`` variables.
+
  See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
 
 .. variable:: CPACK_DEBIAN_PACKAGE_BREAKS
@@ -345,6 +426,9 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_BREAKS` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_BREAKS`` variables.
+
  See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-breaks
 
 .. variable:: CPACK_DEBIAN_PACKAGE_CONFLICTS
@@ -362,6 +446,9 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_CONFLICTS` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONFLICTS`` variables.
+
  See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-conflicts
 
  .. note::
@@ -386,6 +473,9 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_PROVIDES` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_PROVIDES`` variables.
+
  See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-virtual
 
 .. variable:: CPACK_DEBIAN_PACKAGE_REPLACES
@@ -402,6 +492,9 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_REPLACES` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_REPLACES`` variables.
+
  See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
 
 .. variable:: CPACK_DEBIAN_PACKAGE_RECOMMENDS
@@ -418,6 +511,9 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_RECOMMENDS` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_RECOMMENDS`` variables.
+
  See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
 
 .. variable:: CPACK_DEBIAN_PACKAGE_SUGGESTS
@@ -433,10 +529,15 @@ List of CPack DEB generator specific variables:
    - :variable:`CPACK_DEBIAN_PACKAGE_SUGGESTS` for component-based
      installations.
 
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SUGGESTS`` variables.
+
  See http://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
 
 .. variable:: CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS
 
+ .. versionadded:: 3.6
+
  * Mandatory : NO
  * Default   : OFF
 
@@ -451,6 +552,8 @@ List of CPack DEB generator specific variables:
 
 .. variable:: CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY
 
+ .. versionadded:: 3.6
+
  Compatibility policy for auto-generated shlibs control file.
 
  * Mandatory : NO
@@ -476,17 +579,14 @@ List of CPack DEB generator specific variables:
   set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
       "${CMAKE_CURRENT_SOURCE_DIR}/prerm;${CMAKE_CURRENT_SOURCE_DIR}/postrm")
 
- .. note::
-
-   The original permissions of the files will be used in the final
-   package unless the variable
-   :variable:`CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION` is set.
-   In particular, the scripts should have the proper executable
-   flag prior to the generation of the package.
+ .. versionadded:: 3.4
+  Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONTROL_EXTRA`` variables.
 
 .. variable:: CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION
               CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONTROL_STRICT_PERMISSION
 
+ .. versionadded:: 3.4
+
  This variable indicates if the Debian policy on control files should be
  strictly followed.
 
@@ -497,15 +597,22 @@ List of CPack DEB generator specific variables:
 
   set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
 
+ This overrides the permissions on the original files, following the rules
+ set by Debian policy
+ https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
+
  .. note::
 
-   This overrides the permissions on the original files, following the rules
-   set by Debian policy
-   https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
+  The original permissions of the files will be used in the final
+  package unless this variable is set to ``TRUE``.
+  In particular, the scripts should have the proper executable
+  flag prior to the generation of the package.
 
 .. variable:: CPACK_DEBIAN_PACKAGE_SOURCE
               CPACK_DEBIAN_<COMPONENT>_PACKAGE_SOURCE
 
+ .. versionadded:: 3.5
+
  Sets the ``Source`` field of the binary Debian package.
  When the binary package name is not the same as the source package name
  (in particular when several components/binaries are generated from one
@@ -529,6 +636,8 @@ List of CPack DEB generator specific variables:
 Packaging of debug information
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.13
+
 Dbgsym packages contain debug symbols for debugging packaged binaries.
 
 Dbgsym packaging has its own set of variables:
@@ -549,6 +658,8 @@ Dbgsym packaging has its own set of variables:
 Building Debian packages on Windows
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.10
+
 To communicate UNIX file permissions from the install stage
 to the CPack DEB generator the "cmake_mode_t" NTFS
 alternate data stream (ADT) is used.
@@ -559,6 +670,8 @@ permissions can be preserved.
 Reproducible packages
 ^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.13
+
 The environment variable ``SOURCE_DATE_EPOCH`` may be set to a UNIX
 timestamp, defined as the number of seconds, excluding leap seconds,
 since 01 Jan 1970 00:00:00 UTC.  If set, the CPack DEB generator will
index cede0f2..4c662a6 100644 (file)
@@ -30,6 +30,8 @@ on macOS:
 
 .. variable:: CPACK_DMG_DS_STORE_SETUP_SCRIPT
 
+ .. versionadded:: 3.5
+
  Path to a custom AppleScript file.  This AppleScript is used to generate
  a ``.DS_Store`` file which specifies the Finder window position/geometry and
  layout (such as hidden toolbars, placement of the icons etc.).
@@ -47,11 +49,15 @@ on macOS:
 
 .. variable:: CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK
 
+ .. versionadded:: 3.6
+
  Default behaviour is to include a symlink to ``/Applications`` in the DMG.
  Set this option to ``ON`` to avoid adding the symlink.
 
 .. variable:: CPACK_DMG_SLA_DIR
 
+  .. versionadded:: 3.5
+
   Directory where license and menu files for different languages are stored.
   Setting this causes CPack to look for a ``<language>.menu.txt`` and
   ``<language>.license.txt`` or ``<language>.license.rtf`` file for every
@@ -61,8 +67,13 @@ on macOS:
   ``<language>.license.txt`` and ``<language>.license.rtf`` exist, the ``.txt``
   file will be used.
 
+  .. versionadded:: 3.17
+    RTF support.
+
 .. variable:: CPACK_DMG_SLA_LANGUAGES
 
+  .. versionadded:: 3.5
+
   Languages for which a license agreement is provided when mounting the
   generated DMG. A menu file consists of 9 lines of text. The first line is
   is the name of the language itself, uppercase, in English (e.g. German).
@@ -85,6 +96,8 @@ on macOS:
 
 .. variable:: CPACK_DMG_<component>_FILE_NAME
 
+ .. versionadded:: 3.17
+
  File name when packaging ``<component>`` as its own DMG
  (``CPACK_COMPONENTS_GROUPING`` set to IGNORE).
 
index e54b356..4c083f0 100644 (file)
@@ -1,6 +1,8 @@
 CPack External Generator
 ------------------------
 
+.. versionadded:: 3.13
+
 CPack provides many generators to create packages for a variety of platforms
 and packaging systems. The intention is for CMake/CPack to be a complete
 end-to-end solution for building and packaging a software project. However, it
@@ -284,6 +286,8 @@ Variables specific to CPack External generator
 
 .. variable:: CPACK_EXTERNAL_BUILT_PACKAGES
 
+  .. versionadded:: 3.19
+
   The ``CPACK_EXTERNAL_PACKAGE_SCRIPT`` script may set this list variable to the
   full paths of generated package files.  CPack will copy these files from the
   staging directory back to the top build directory and possibly produce
index 47a7784..2c93569 100644 (file)
@@ -1,12 +1,15 @@
 CPack FreeBSD Generator
 -----------------------
 
+.. versionadded:: 3.10
+
 The built in (binary) CPack FreeBSD (pkg) generator (Unix only)
 
 Variables affecting the CPack FreeBSD (pkg) generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-  - :variable:`CPACK_ARCHIVE_THREADS`
+- .. versionadded:: 3.18
+    :variable:`CPACK_ARCHIVE_THREADS`
 
 Variables specific to CPack FreeBSD (pkg) generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,6 +89,9 @@ the RPM information (e.g. package license).
      :variable:`CPACK_DEBIAN_PACKAGE_HOMEPAGE` (this may be set already
      for Debian packaging, so we may as well re-use it).
 
+  .. versionadded:: 3.12
+    The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+
 .. variable:: CPACK_FREEBSD_PACKAGE_LICENSE
 
   The license, or licenses, which apply to this software package. This must
index 5fbbfa2..6817eac 100644 (file)
@@ -1,6 +1,8 @@
 CPack IFW Generator
 -------------------
 
+.. versionadded:: 3.1
+
 Configure and run the Qt Installer Framework to generate a Qt installer.
 
 .. only:: html
@@ -35,6 +37,8 @@ Debug
 
 .. variable:: CPACK_IFW_VERBOSE
 
+ .. versionadded:: 3.3
+
  Set to ``ON`` to enable addition debug output.
  By default is ``OFF``.
 
@@ -71,41 +75,59 @@ Package
 
 .. variable:: CPACK_IFW_PACKAGE_WATERMARK
 
+ .. versionadded:: 3.8
+
  Filename for a watermark is used as QWizard::WatermarkPixmap.
 
 .. variable:: CPACK_IFW_PACKAGE_BANNER
 
+ .. versionadded:: 3.8
+
  Filename for a banner is used as QWizard::BannerPixmap.
 
 .. variable:: CPACK_IFW_PACKAGE_BACKGROUND
 
+ .. versionadded:: 3.8
+
  Filename for an image used as QWizard::BackgroundPixmap (only used by MacStyle).
 
 .. variable:: CPACK_IFW_PACKAGE_WIZARD_STYLE
 
- Wizard style to be used ("Modern", "Mac", "Aero" or "Classic").
-
-.. variable:: CPACK_IFW_PACKAGE_STYLE_SHEET
+ .. versionadded:: 3.8
 
Filename for a stylesheet.
Wizard style to be used ("Modern", "Mac", "Aero" or "Classic").
 
 .. variable:: CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH
 
+ .. versionadded:: 3.8
+
  Default width of the wizard in pixels. Setting a banner image will override this.
 
 .. variable:: CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT
 
+ .. versionadded:: 3.8
+
  Default height of the wizard in pixels. Setting a watermark image will override this.
 
+.. variable:: CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST
+
+ .. versionadded:: 3.20
+
+ Set to ``OFF`` if the widget listing installer pages on the left side of the wizard should not be shown.
+
+ It is ``ON`` by default, but will only have an effect if using QtIFW 4.0 or later.
+
 .. variable:: CPACK_IFW_PACKAGE_TITLE_COLOR
 
+ .. versionadded:: 3.8
+
  Color of the titles and subtitles (takes an HTML color code, such as "#88FF33").
 
-.. variable:: CPACK_IFW_PACKAGE_START_MENU_DIRECTORY
+.. variable:: CPACK_IFW_PACKAGE_STYLE_SHEET
 
- Name of the default program group for the product in the Windows Start menu.
+ .. versionadded:: 3.15
 
By default used :variable:`CPACK_IFW_PACKAGE_NAME`.
Filename for a stylesheet.
 
 .. variable:: CPACK_IFW_TARGET_DIRECTORY
 
@@ -123,6 +145,14 @@ Package
 
  You can use predefined variables.
 
+.. variable:: CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR
+
+ .. versionadded:: 3.11
+
+ Set to ``OFF`` if the target directory should not be deleted when uninstalling.
+
+ Is ``ON`` by default
+
 .. variable:: CPACK_IFW_PACKAGE_GROUP
 
  The group, which will be used to configure the root package
@@ -132,43 +162,57 @@ Package
  The root package name, which will be used if configuration group is not
  specified
 
+.. variable:: CPACK_IFW_PACKAGE_START_MENU_DIRECTORY
+
+ .. versionadded:: 3.3
+
+ Name of the default program group for the product in the Windows Start menu.
+
+ By default used :variable:`CPACK_IFW_PACKAGE_NAME`.
+
 .. variable:: CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME
 
+ .. versionadded:: 3.3
+
  Filename of the generated maintenance tool.
  The platform-specific executable file extension is appended.
 
  By default used QtIFW defaults (``maintenancetool``).
 
-.. variable:: CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR
-
- Set to ``OFF`` if the target directory should not be deleted when uninstalling.
-
- Is ``ON`` by default
-
 .. variable:: CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_INI_FILE
 
+ .. versionadded:: 3.3
+
  Filename for the configuration of the generated maintenance tool.
 
  By default used QtIFW defaults (``maintenancetool.ini``).
 
 .. variable:: CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS
 
+ .. versionadded:: 3.3
+
  Set to ``ON`` if the installation path can contain non-ASCII characters.
 
  Is ``ON`` for QtIFW less 2.0 tools.
 
 .. variable:: CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH
 
+ .. versionadded:: 3.3
+
  Set to ``OFF`` if the installation path cannot contain space characters.
 
  Is ``ON`` for QtIFW less 2.0 tools.
 
 .. variable:: CPACK_IFW_PACKAGE_CONTROL_SCRIPT
 
+ .. versionadded:: 3.3
+
  Filename for a custom installer control script.
 
 .. variable:: CPACK_IFW_PACKAGE_RESOURCES
 
+ .. versionadded:: 3.7
+
  List of additional resources ('.qrc' files) to include in the installer
  binary.
 
@@ -177,6 +221,8 @@ Package
 
 .. variable:: CPACK_IFW_PACKAGE_FILE_EXTENSION
 
+ .. versionadded:: 3.10
+
  The target binary extension.
 
  On Linux, the name of the target binary is automatically extended with
@@ -216,6 +262,8 @@ Components
 
 .. variable:: CPACK_IFW_REPOSITORIES_DIRECTORIES
 
+ .. versionadded:: 3.10
+
  Additional prepared repository dirs that will be used to resolve and
  repack dependent components. This feature available only
  since QtIFW 3.1.
@@ -225,6 +273,8 @@ QtIFW Tools
 
 .. variable:: CPACK_IFW_FRAMEWORK_VERSION
 
+ .. versionadded:: 3.3
+
  The version of used QtIFW tools.
 
 The following variables provide the locations of the QtIFW
@@ -233,6 +283,8 @@ These variables are cached, and may be configured if needed.
 
 .. variable:: CPACK_IFW_ARCHIVEGEN_EXECUTABLE
 
+ .. versionadded:: 3.19
+
  The path to ``archivegen``.
 
 .. variable:: CPACK_IFW_BINARYCREATOR_EXECUTABLE
@@ -260,6 +312,8 @@ the path may be specified in either a CMake or an environment variable:
 
 .. variable:: CPACK_IFW_ROOT
 
+ .. versionadded:: 3.9
+
  An CMake variable which specifies the location of the QtIFW tool suite.
 
  The variable will be cached in the ``CPackConfig.cmake`` file and used at
@@ -306,6 +360,8 @@ these files accessible from a download URL.
 Internationalization
 """"""""""""""""""""
 
+.. versionadded:: 3.9
+
 Some variables and command arguments support internationalization via
 CMake script. This is an optional feature.
 
index 0dd876e..eaef8ae 100644 (file)
@@ -3,7 +3,8 @@ CPack NSIS Generator
 
 CPack Nullsoft Scriptable Install System (NSIS) generator specific options.
 
-The NSIS generator requires NSIS 3.0 or newer.
+.. versionchanged:: 3.17
+ The NSIS generator requires NSIS 3.0 or newer.
 
 Variables specific to CPack NSIS generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,10 +34,14 @@ on Windows Nullsoft Scriptable Install System.
 
 .. variable:: CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP
 
+ .. versionadded:: 3.5
+
  The filename of a bitmap to use as the NSIS ``MUI_WELCOMEFINISHPAGE_BITMAP``.
 
 .. variable:: CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP
 
+ .. versionadded:: 3.5
+
  The filename of a bitmap to use as the NSIS ``MUI_UNWELCOMEFINISHPAGE_BITMAP``.
 
 .. variable:: CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS
@@ -99,6 +104,8 @@ on Windows Nullsoft Scriptable Install System.
 
 .. variable:: CPACK_NSIS_<compName>_INSTALL_DIRECTORY
 
+ .. versionadded:: 3.7
+
  Custom install directory for the specified component ``<compName>`` instead
  of ``$INSTDIR``.
 
@@ -133,29 +140,56 @@ on Windows Nullsoft Scriptable Install System.
 
 .. variable:: CPACK_NSIS_UNINSTALL_NAME
 
+ .. versionadded:: 3.17
+
  Specify the name of the program to uninstall the version.
  Default is ``Uninstall``.
 
 .. variable:: CPACK_NSIS_WELCOME_TITLE
 
+  .. versionadded:: 3.17
+
   The title to display on the top of the page for the welcome page.
 
 .. variable:: CPACK_NSIS_WELCOME_TITLE_3LINES
 
+ .. versionadded:: 3.17
+
  Display the title in the welcome page on 3 lines instead of 2.
 
 .. variable:: CPACK_NSIS_FINISH_TITLE
 
+ .. versionadded:: 3.17
+
  The title to display on the top of the page for the finish page.
 
 .. variable:: CPACK_NSIS_FINISH_TITLE_3LINES
 
+ .. versionadded:: 3.17
+
  Display the title in the finish page on 3 lines instead of 2.
 
 .. variable:: CPACK_NSIS_MUI_HEADERIMAGE
 
+ .. versionadded:: 3.17
+
  The image to display on the header of installers pages.
 
 .. variable:: CPACK_NSIS_MANIFEST_DPI_AWARE
 
+ .. versionadded:: 3.18
+
  If set, declares that the installer is DPI-aware.
+
+.. variable:: CPACK_NSIS_BRANDING_TEXT
+
+ .. versionadded:: 3.20
+
+ If set, updates the text at the bottom of the install window.
+ To set the string to blank, use a space (" ").
+
+.. variable:: CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION
+
+ .. versionadded:: 3.20
+
+ If set, trim down the size of the control to the size of the branding text string.
index f8aa626..c980dd6 100644 (file)
@@ -1,9 +1,11 @@
 CPack NuGet Generator
 ---------------------
 
+.. versionadded:: 3.12
+
 When build a NuGet package there is no direct way to control an output
 filename due a lack of the corresponding CLI option of NuGet, so there
-is no ``CPACK_NUGET_PACKAGE_FILENAME`` variable. To form the output filename
+is no ``CPACK_NUGET_PACKAGE_FILE_NAME`` variable. To form the output filename
 NuGet uses the package name and the version according to its built-in rules.
 
 Also, be aware that including a top level directory
@@ -35,7 +37,8 @@ List of CPack NuGet generator specific variables:
 .. variable:: CPACK_NUGET_PACKAGE_NAME
               CPACK_NUGET_<compName>_PACKAGE_NAME
 
- The NUGET package name.
+ The NUGET package name. ``CPACK_NUGET_PACKAGE_NAME`` is used as the
+ package ``id`` on nuget.org_
 
  * Mandatory : YES
  * Default   : :variable:`CPACK_PACKAGE_NAME`
@@ -95,7 +98,7 @@ List of CPack NuGet generator specific variables:
 .. variable:: CPACK_NUGET_PACKAGE_HOMEPAGE_URL
               CPACK_NUGET_<compName>_PACKAGE_HOMEPAGE_URL
 
- A URL for the package's home page, often shown in UI displays as well
+ An URL for the package's home page, often shown in UI displays as well
  as nuget.org_.
 
  * Mandatory : NO
@@ -104,8 +107,45 @@ List of CPack NuGet generator specific variables:
 .. variable:: CPACK_NUGET_PACKAGE_LICENSEURL
               CPACK_NUGET_<compName>_PACKAGE_LICENSEURL
 
- A URL for the package's license, often shown in UI displays as well
- as nuget.org_.
+ .. deprecated:: 3.20
+  Use a local license file
+  (:variable:`CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME`)
+  or a `(SPDX) license identifier`_
+  (:variable:`CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION`) instead.
+
+ An URL for the package's license, often shown in UI displays as well
+ as on nuget.org_.
+
+ * Mandatory : NO
+ * Default   : -
+
+.. variable:: CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION
+              CPACK_NUGET_<compName>_PACKAGE_LICENSE_EXPRESSION
+
+ .. versionadded:: 3.20
+
+ A Software Package Data Exchange `(SPDX) license identifier`_ such as
+ ``MIT``, ``BSD-3-Clause``, or ``LGPL-3.0-or-later``. In the case of a
+ choice of licenses or more complex restrictions, compound license
+ expressions may be formed using boolean operators, for example
+ ``MIT OR BSD-3-Clause``.  See the `SPDX specification`_ for guidance
+ on forming complex license expressions.
+
+ If ``CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME`` is specified,
+ ``CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION`` is ignored.
+
+ * Mandatory : NO
+ * Default   : -
+
+.. variable:: CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME
+              CPACK_NUGET_<compName>_PACKAGE_LICENSE_FILE_NAME
+
+ The package's license file in :file:`.txt` or :file:`.md` format.
+
+ If ``CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME`` is specified,
+ ``CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION`` is ignored.
+
+ .. versionadded:: 3.20
 
  * Mandatory : NO
  * Default   : -
@@ -113,7 +153,21 @@ List of CPack NuGet generator specific variables:
 .. variable:: CPACK_NUGET_PACKAGE_ICONURL
               CPACK_NUGET_<compName>_PACKAGE_ICONURL
 
- A URL for a 64x64 image with transparency background to use as the
+ .. deprecated:: 3.20
+  Use a local icon file (:variable:`CPACK_NUGET_PACKAGE_ICON`) instead.
+
+ An URL for a 64x64 image with transparency background to use as the
+ icon for the package in UI display.
+
+ * Mandatory : NO
+ * Default   : -
+
+.. variable:: CPACK_NUGET_PACKAGE_ICON
+              CPACK_NUGET_<compName>_PACKAGE_ICON
+
+ .. versionadded:: 3.20
+
+ The filename of a 64x64 image with transparency background to use as the
  icon for the package in UI display.
 
  * Mandatory : NO
@@ -146,6 +200,16 @@ List of CPack NuGet generator specific variables:
  * Mandatory : NO
  * Default   : -
 
+.. variable:: CPACK_NUGET_PACKAGE_LANGUAGE
+              CPACK_NUGET_<compName>_PACKAGE_LANGUAGE
+
+ .. versionadded:: 3.20
+
+ Locale specifier for the package, for example ``en_CA``.
+
+ * Mandatory : NO
+ * Default   : -
+
 .. variable:: CPACK_NUGET_PACKAGE_TAGS
               CPACK_NUGET_<compName>_PACKAGE_TAGS
 
@@ -185,5 +249,7 @@ List of CPack NuGet generator specific variables:
 
 .. _nuget.org: http://nuget.org
 .. _version specification: https://docs.microsoft.com/en-us/nuget/reference/package-versioning#version-ranges-and-wildcards
+.. _(SPDX) license identifier: https://spdx.org/licenses/
+.. _SPDX specification: https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/
 
 .. NuGet spec docs https://docs.microsoft.com/en-us/nuget/reference/nuspec
index 357eb73..256446d 100644 (file)
@@ -27,6 +27,14 @@ macOS using PackageMaker:
  don't mind missing extra features available in the installer shipping with
  later versions of macOS.
 
+Background Image
+""""""""""""""""
+
+.. versionadded:: 3.17
+
+This group of variables controls the background image of the generated
+installer.
+
 .. variable:: CPACK_PACKAGEMAKER_BACKGROUND
 
  Adds a background to Distribution XML if specified. The value contains the
index fd99e5a..cf3041f 100644 (file)
@@ -1,6 +1,8 @@
 CPack productbuild Generator
 ----------------------------
 
+.. versionadded:: 3.7
+
 productbuild CPack generator (macOS).
 
 Variables specific to CPack productbuild generator
@@ -18,11 +20,15 @@ macOS using ProductBuild:
 
 .. variable:: CPACK_PRODUCTBUILD_IDENTITY_NAME
 
+ .. versionadded:: 3.8
+
  Adds a digital signature to the resulting package.
 
 
 .. variable:: CPACK_PRODUCTBUILD_KEYCHAIN_PATH
 
+ .. versionadded:: 3.8
+
  Specify a specific keychain to search for the signing identity.
 
 
@@ -35,11 +41,15 @@ macOS using ProductBuild:
 
 .. variable:: CPACK_PKGBUILD_IDENTITY_NAME
 
+ .. versionadded:: 3.8
+
  Adds a digital signature to the resulting package.
 
 
 .. variable:: CPACK_PKGBUILD_KEYCHAIN_PATH
 
+ .. versionadded:: 3.8
+
  Specify a specific keychain to search for the signing identity.
 
 
@@ -60,12 +70,22 @@ macOS using ProductBuild:
 
 .. variable:: CPACK_PRODUCTBUILD_RESOURCES_DIR
 
+ .. versionadded:: 3.9
+
  If specified the productbuild generator copies files from this directory
  (including subdirectories) to the ``Resources`` directory. This is done
  before the :variable:`CPACK_RESOURCE_FILE_WELCOME`,
  :variable:`CPACK_RESOURCE_FILE_README`, and
  :variable:`CPACK_RESOURCE_FILE_LICENSE` files are copied.
 
+Background Image
+""""""""""""""""
+
+.. versionadded:: 3.17
+
+This group of variables controls the background image of the generated
+installer.
+
 .. variable:: CPACK_PRODUCTBUILD_BACKGROUND
 
  Adds a background to Distribution XML if specified. The value contains the
index ccb7ebd..5260a1d 100644 (file)
@@ -20,7 +20,7 @@ a component GROUP name. Usually those variables correspond to RPM spec file
 entities. One may find information about spec files here
 http://www.rpm.org/wiki/Docs
 
-.. note::
+.. versionchanged:: 3.6
 
  `<COMPONENT>` part of variables is preferred to be in upper case (e.g. if
  component is named ``foo`` then use ``CPACK_RPM_FOO_XXXX`` variable name format)
@@ -59,6 +59,9 @@ List of CPack RPM generator specific variables:
  * Mandatory : YES
  * Default   : :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`
 
+ .. versionadded:: 3.2
+  Per-component ``CPACK_RPM_<component>_PACKAGE_SUMMARY`` variables.
+
 .. variable:: CPACK_RPM_PACKAGE_NAME
               CPACK_RPM_<component>_PACKAGE_NAME
 
@@ -67,9 +70,14 @@ List of CPack RPM generator specific variables:
  * Mandatory : YES
  * Default   : :variable:`CPACK_PACKAGE_NAME`
 
+ .. versionadded:: 3.5
+  Per-component ``CPACK_RPM_<component>_PACKAGE_NAME`` variables.
+
 .. variable:: CPACK_RPM_FILE_NAME
               CPACK_RPM_<component>_FILE_NAME
 
+ .. versionadded:: 3.6
+
  Package file name.
 
  * Mandatory : YES
@@ -93,6 +101,8 @@ List of CPack RPM generator specific variables:
 
 .. variable:: CPACK_RPM_MAIN_COMPONENT
 
+ .. versionadded:: 3.8
+
  Main component that is packaged without component suffix.
 
  * Mandatory : NO
@@ -104,6 +114,8 @@ List of CPack RPM generator specific variables:
 
 .. variable:: CPACK_RPM_PACKAGE_EPOCH
 
+ .. versionadded:: 3.10
+
  The RPM package epoch
 
  * Mandatory : No
@@ -129,6 +141,9 @@ List of CPack RPM generator specific variables:
 
  This may be set to ``noarch`` if you know you are building a ``noarch`` package.
 
+ .. versionadded:: 3.3
+  Per-component ``CPACK_RPM_<component>_PACKAGE_ARCHITECTURE`` variables.
+
 .. variable:: CPACK_RPM_PACKAGE_RELEASE
 
  The RPM package release.
@@ -150,6 +165,8 @@ List of CPack RPM generator specific variables:
 
 .. variable:: CPACK_RPM_PACKAGE_RELEASE_DIST
 
+ .. versionadded:: 3.6
+
  The dist tag that is added  RPM ``Release:`` field.
 
  * Mandatory : NO
@@ -174,6 +191,9 @@ List of CPack RPM generator specific variables:
  * Mandatory : YES
  * Default   : "unknown"
 
+ .. versionadded:: 3.5
+  Per-component ``CPACK_RPM_<component>_PACKAGE_GROUP`` variables.
+
 .. variable:: CPACK_RPM_PACKAGE_VENDOR
 
  The RPM package vendor.
@@ -189,6 +209,9 @@ List of CPack RPM generator specific variables:
  * Mandatory : NO
  * Default   : :variable:`CMAKE_PROJECT_HOMEPAGE_URL`
 
+ .. versionadded:: 3.12
+  The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+
 .. variable:: CPACK_RPM_PACKAGE_DESCRIPTION
               CPACK_RPM_<component>_PACKAGE_DESCRIPTION
 
@@ -199,6 +222,9 @@ List of CPack RPM generator specific variables:
    based installers only) if set, :variable:`CPACK_PACKAGE_DESCRIPTION_FILE`
    if set or "no package description available"
 
+ .. versionadded:: 3.2
+  Per-component ``CPACK_RPM_<component>_PACKAGE_DESCRIPTION`` variables.
+
 .. variable:: CPACK_RPM_COMPRESSION_TYPE
 
  RPM compression type.
@@ -302,6 +328,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_PACKAGE_REQUIRES_PRE
               CPACK_RPM_<component>_PACKAGE_REQUIRES_PRE
 
+ .. versionadded:: 3.2
+
  RPM spec requires(pre) field.
 
  * Mandatory : NO
@@ -315,6 +343,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_PACKAGE_REQUIRES_POST
               CPACK_RPM_<component>_PACKAGE_REQUIRES_POST
 
+ .. versionadded:: 3.2
+
  RPM spec requires(post) field.
 
  * Mandatory : NO
@@ -328,6 +358,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_PACKAGE_REQUIRES_POSTUN
               CPACK_RPM_<component>_PACKAGE_REQUIRES_POSTUN
 
+ .. versionadded:: 3.2
+
  RPM spec requires(postun) field.
 
  * Mandatory : NO
@@ -342,6 +374,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_PACKAGE_REQUIRES_PREUN
               CPACK_RPM_<component>_PACKAGE_REQUIRES_PREUN
 
+ .. versionadded:: 3.2
+
  RPM spec requires(preun) field.
 
  * Mandatory : NO
@@ -492,6 +526,9 @@ List of CPack RPM generator specific variables:
 
   rpm -qp --scripts  package.rpm
 
+ .. versionadded:: 3.18
+  The ``CPACK_RPM_PRE_TRANS_SCRIPT_FILE`` variable.
+
 .. variable:: CPACK_RPM_POST_INSTALL_SCRIPT_FILE
               CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE
               CPACK_RPM_POST_TRANS_SCRIPT_FILE
@@ -513,6 +550,9 @@ List of CPack RPM generator specific variables:
 
   rpm -qp --scripts  package.rpm
 
+ .. versionadded:: 3.18
+  The ``CPACK_RPM_POST_TRANS_SCRIPT_FILE`` variable.
+
 .. variable:: CPACK_RPM_USER_FILELIST
               CPACK_RPM_<COMPONENT>_USER_FILELIST
 
@@ -521,13 +561,16 @@ List of CPack RPM generator specific variables:
 
  May be used to explicitly specify ``%(<directive>)`` file line
  in the spec file. Like ``%config(noreplace)`` or any other directive
- that be found in the ``%files`` section. You can have multiple directives
- per line, as in ``%attr(600,root,root) %config(noreplace)``. Since
+ that be found in the ``%files`` section. Since
  the CPack RPM generator is generating the list of files (and directories) the
  user specified files of the ``CPACK_RPM_<COMPONENT>_USER_FILELIST`` list will
  be removed from the generated list. If referring to directories do
  not add a trailing slash.
 
+ .. versionadded:: 3.8
+  You can have multiple directives per line, as in
+  ``%attr(600,root,root) %config(noreplace)``.
+
 .. variable:: CPACK_RPM_CHANGELOG_FILE
 
  RPM changelog file.
@@ -555,6 +598,9 @@ List of CPack RPM generator specific variables:
  the default path. If you want to add some path to the default list then you
  can use :variable:`CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION` variable.
 
+ .. versionadded:: 3.10
+  Added ``/usr/share/aclocal`` to the default list of excludes.
+
 .. variable:: CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
 
  additional list of path to be excluded.
@@ -568,6 +614,8 @@ List of CPack RPM generator specific variables:
 
 .. variable:: CPACK_RPM_RELOCATION_PATHS
 
+ .. versionadded:: 3.2
+
  Packages relocation paths list.
 
  * Mandatory : NO
@@ -591,6 +639,8 @@ List of CPack RPM generator specific variables:
 
 .. variable:: CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
 
+ .. versionadded:: 3.2
+
  Per component relocation path install prefix.
 
  * Mandatory : NO
@@ -602,6 +652,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_NO_INSTALL_PREFIX_RELOCATION
               CPACK_RPM_NO_<COMPONENT>_INSTALL_PREFIX_RELOCATION
 
+ .. versionadded:: 3.3
+
  Removal of default install prefix from relocation paths list.
 
  * Mandatory : NO
@@ -613,6 +665,8 @@ List of CPack RPM generator specific variables:
 
 .. variable:: CPACK_RPM_ADDITIONAL_MAN_DIRS
 
+ .. versionadded:: 3.3
+
  * Mandatory : NO
  * Default   : -
 
@@ -641,6 +695,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_DEFAULT_USER
               CPACK_RPM_<compName>_DEFAULT_USER
 
+ .. versionadded:: 3.6
+
  default user ownership of RPM content
 
  * Mandatory : NO
@@ -652,6 +708,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_DEFAULT_GROUP
               CPACK_RPM_<compName>_DEFAULT_GROUP
 
+ .. versionadded:: 3.6
+
  default group ownership of RPM content
 
  * Mandatory : NO
@@ -663,6 +721,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_DEFAULT_FILE_PERMISSIONS
               CPACK_RPM_<compName>_DEFAULT_FILE_PERMISSIONS
 
+ .. versionadded:: 3.6
+
  default permissions used for packaged files
 
  * Mandatory : NO
@@ -686,6 +746,8 @@ List of CPack RPM generator specific variables:
 .. variable:: CPACK_RPM_DEFAULT_DIR_PERMISSIONS
               CPACK_RPM_<compName>_DEFAULT_DIR_PERMISSIONS
 
+ .. versionadded:: 3.6
+
  default permissions used for packaged directories
 
  * Mandatory : NO
@@ -697,6 +759,8 @@ List of CPack RPM generator specific variables:
 
 .. variable:: CPACK_RPM_INSTALL_WITH_EXEC
 
+ .. versionadded:: 3.11
+
  force execute permissions on programs and shared libraries
 
  * Mandatory : NO
@@ -714,6 +778,8 @@ List of CPack RPM generator specific variables:
 Packaging of Symbolic Links
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.3
+
 The CPack RPM generator supports packaging of symbolic links::
 
   execute_process(COMMAND ${CMAKE_COMMAND}
@@ -731,8 +797,10 @@ those locations will be treated as if they were a part of the package
 while determining if symlink should be either created or present in a
 post install script - depending on relocation paths.
 
-Symbolic links that point to locations outside packaging path produce a
-warning and are treated as non relocatable permanent symbolic links.
+.. versionchanged:: 3.6
+ Symbolic links that point to locations outside packaging path produce a
+ warning and are treated as non relocatable permanent symbolic links.
+ Previous versions of CMake produced an error in this case.
 
 Currently there are a few limitations though:
 
@@ -750,6 +818,8 @@ Currently there are a few limitations though:
 Packaging of debug information
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.7
+
 Debuginfo packages contain debug symbols and sources for debugging packaged
 binaries.
 
@@ -832,6 +902,8 @@ Debuginfo RPM packaging has its own set of variables:
 
 .. variable:: CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE
 
+ .. versionadded:: 3.8
+
  Create a single debuginfo package even if components packaging is set.
 
  * Mandatory : NO
@@ -853,6 +925,8 @@ Debuginfo RPM packaging has its own set of variables:
 .. variable:: CPACK_RPM_DEBUGINFO_FILE_NAME
               CPACK_RPM_<component>_DEBUGINFO_FILE_NAME
 
+ .. versionadded:: 3.9
+
  Debuginfo package file name.
 
  * Mandatory : NO
@@ -877,6 +951,8 @@ Debuginfo RPM packaging has its own set of variables:
 Packaging of sources (SRPM)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.7
+
 SRPM packaging is enabled by setting :variable:`CPACK_RPM_PACKAGE_SOURCES`
 variable while usually using :variable:`CPACK_INSTALLED_DIRECTORIES` variable
 to provide directory containing CMakeLists.txt and source files.
index 5b880ba..79f835e 100644 (file)
@@ -3,6 +3,9 @@ CPack WIX Generator
 
 CPack WIX generator specific options
 
+.. versionadded:: 3.7
+  Support :variable:`CPACK_COMPONENT_<compName>_DISABLED` variable.
+
 Variables specific to CPack WIX generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -95,9 +98,10 @@ Windows using WiX.
 
  If this variable is not set, it will be initialized with CPACK_PACKAGE_NAME
 
- If this variable is set to ``.``, then application shortcuts will be
- created directly in the start menu and the uninstaller shortcut will be
- omitted.
+ .. versionadded:: 3.16
+  If this variable is set to ``.``, then application shortcuts will be
+  created directly in the start menu and the uninstaller shortcut will be
+  omitted.
 
 .. variable:: CPACK_WIX_CULTURES
 
@@ -123,7 +127,10 @@ Windows using WiX.
 .. variable:: CPACK_WIX_PATCH_FILE
 
  Optional list of XML files with fragments to be inserted into
- generated WiX sources
+ generated WiX sources.
+
+ .. versionadded:: 3.5
+  Support listing multiple patch files.
 
  This optional variable can be used to specify an XML file that the
  WIX generator will use to inject fragments into its generated
@@ -152,10 +159,17 @@ Windows using WiX.
  Currently fragments can be injected into most
  Component, File, Directory and Feature elements.
 
- The following additional special Ids can be used:
+ .. versionadded:: 3.3
+  The following additional special Ids can be used:
+
+  * ``#PRODUCT`` for the ``<Product>`` element.
+  * ``#PRODUCTFEATURE`` for the root ``<Feature>`` element.
 
- * ``#PRODUCT`` for the ``<Product>`` element.
- * ``#PRODUCTFEATURE`` for the root ``<Feature>`` element.
+ .. versionadded:: 3.7
+  Support patching arbitrary ``<Feature>`` elements.
+
+ .. versionadded:: 3.9
+  Allow setting additional attributes.
 
  The following example illustrates how this works.
 
@@ -227,6 +241,8 @@ Windows using WiX.
 
 .. variable:: CPACK_WIX_PROPERTY_<PROPERTY>
 
+ .. versionadded:: 3.1
+
  This variable can be used to provide a value for
  the Windows Installer property ``<PROPERTY>``
 
@@ -243,16 +259,22 @@ Windows using WiX.
 
 .. variable:: CPACK_WIX_ROOT_FEATURE_TITLE
 
+ .. versionadded:: 3.7
+
  Sets the name of the root install feature in the WIX installer. Same as
  CPACK_COMPONENT_<compName>_DISPLAY_NAME for components.
 
 .. variable:: CPACK_WIX_ROOT_FEATURE_DESCRIPTION
 
+ .. versionadded:: 3.7
+
  Sets the description of the root install feature in the WIX installer. Same as
  CPACK_COMPONENT_<compName>_DESCRIPTION for components.
 
 .. variable:: CPACK_WIX_SKIP_PROGRAM_FOLDER
 
+ .. versionadded:: 3.7
+
  If this variable is set to true, the default install location
  of the generated package will be CPACK_PACKAGE_INSTALL_DIRECTORY directly.
  The install location will not be located relatively below
@@ -270,6 +292,8 @@ Windows using WiX.
 
 .. variable:: CPACK_WIX_ROOT_FOLDER_ID
 
+ .. versionadded:: 3.9
+
  This variable allows specification of a custom root folder ID.
  The generator specific ``<64>`` token can be used for
  folder IDs that come in 32-bit and 64-bit variants.
@@ -289,6 +313,8 @@ Windows using WiX.
 
 .. variable:: CPACK_WIX_CUSTOM_XMLNS
 
+ .. versionadded:: 3.19
+
  This variable provides a list of custom namespace declarations that are necessary
  for using WiX extensions. Each declaration should be in the form name=url, where
  name is the plain namespace without the usual xmlns: prefix and url is an unquoted
index 84da4f1..9c3878b 100644 (file)
@@ -37,9 +37,11 @@ CMake developer documentation is provided by the following documents:
 
 * The `CMake Source Code Guide`_.
 * The `CMake Documentation Guide`_.
+* The `CMake Experimental Features Guide`_.
 
 .. _`CMake Source Code Guide`: source.rst
 .. _`CMake Documentation Guide`: documentation.rst
+.. _`CMake Experimental Features Guide`: experimental.rst
 
 Maintainer Documentation
 ========================
index c302790..29fc880 100644 (file)
@@ -123,10 +123,23 @@ documentation:
 ``command``
  A CMake language command.
 
+``cpack_gen``
+ A CPack package generator.
+ See the `cpack(1)`_ command-line tool's ``-G`` option.
+
+``envvar``
+ An environment variable.
+ See the `cmake-env-variables(7)`_ manual
+ and the `set()`_ command.
+
 ``generator``
  A CMake native build system generator.
  See the `cmake(1)`_ command-line tool's ``-G`` option.
 
+``genex``
+ A CMake generator expression.
+ See the `cmake-generator-expressions(7)`_ manual.
+
 ``manual``
  A CMake manual page, like the `cmake(1)`_ manual.
 
@@ -160,10 +173,12 @@ which is expected to be of the form::
  -------------
 
 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
+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.
+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:
@@ -174,6 +189,14 @@ other documents:
 
   This indented block documents <command-name>.
 
+ .. envvar:: <envvar-name>
+
+  This indented block documents <envvar-name>.
+
+ .. genex:: <genex-name>
+
+  This indented block documents <genex-name>.
+
  .. variable:: <variable-name>
 
   This indented block documents <variable-name>.
@@ -183,11 +206,14 @@ the first approach above.
 
 .. _`Sphinx Domain`: http://sphinx-doc.org/domains.html
 .. _`cmake(1)`: https://cmake.org/cmake/help/latest/manual/cmake.1.html
+.. _`cmake-env-variables(7)`: https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html
+.. _`cmake-generator-expressions(7)`: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html
 .. _`cmake-modules(7)`: https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html
 .. _`cmake-policies(7)`: https://cmake.org/cmake/help/latest/manual/cmake-policies.7.html
 .. _`cmake-properties(7)`: https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html
 .. _`cmake-variables(7)`: https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html
 .. _`cmake_policy()`: https://cmake.org/cmake/help/latest/command/cmake_policy.html
+.. _`cpack(1)`: https://cmake.org/cmake/help/latest/manual/cpack.1.html
 .. _`include()`: https://cmake.org/cmake/help/latest/command/include.html
 .. _`set()`: https://cmake.org/cmake/help/latest/command/set.html
 .. _`set_property()`: https://cmake.org/cmake/help/latest/command/set_property.html
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst
new file mode 100644 (file)
index 0000000..d019161
--- /dev/null
@@ -0,0 +1,70 @@
+CMake Experimental Features Guide
+*********************************
+
+The following is a guide to CMake experimental features that are
+under development and not yet included in official documentation.
+See documentation on `CMake Development`_ for more information.
+
+.. _`CMake Development`: README.rst
+
+C++20 Module Dependencies
+=========================
+
+The Ninja generator has experimental infrastructure supporting C++20 module
+dependency scanning.  This is similar to the Fortran modules support, but
+relies on external tools to scan C++20 translation units for module
+dependencies.  The approach is described by Kitware's `D1483r1`_ paper.
+
+The ``CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP`` variable can be set to ``1``
+in order to activate this undocumented experimental infrastructure.  This
+is **intended to make the functionality available to compiler writers** so
+they can use it to develop and test their dependency scanning tool.
+The ``CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE`` variable must also be set
+to tell CMake how to invoke the C++20 module dependency scanning tool.
+
+For example, add code like the following to a test project:
+
+.. code-block:: cmake
+
+  set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+  string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
+    "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> <SOURCE>"
+    " -MT <DYNDEP_FILE> -MD -MF <DEP_FILE>"
+    " ${flags_to_scan_deps} -fdep-file=<DYNDEP_FILE> -fdep-output=<OBJECT>"
+    )
+
+The tool specified by ``CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE`` is
+expected to process the translation unit, write preprocessor dependencies
+to the file specified by the ``<DEP_FILE>`` placeholder, and write module
+dependencies to the file specified by the ``<DYNDEP_FILE>`` placeholder.
+
+The module dependencies should be written in the format described
+by the `P1689r3`_ paper.
+
+Compiler writers may try out their scanning functionality using
+the `cxx-modules-sandbox`_ test project, modified to set variables
+as above for their compiler.
+
+For compilers that generate module maps, tell CMake as follows:
+
+.. code-block:: cmake
+
+  set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "gcc")
+  set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG
+    "${compiler_flags_for_module_map} -fmodule-mapper=<MODULE_MAP_FILE>")
+
+Currently, the only supported format is ``gcc``.  The format is described in
+the GCC documentation, but the relevant section for the purposes of CMake is:
+
+    A mapping file consisting of space-separated module-name, filename
+    pairs, one per line.  Only the mappings for the direct imports and any
+    module export name need be provided.  If other mappings are provided,
+    they override those stored in any imported CMI files.  A repository
+    root may be specified in the mapping file by using ``$root`` as the
+    module name in the first active line.
+
+    -- GCC module mapper documentation
+
+.. _`D1483r1`: https://mathstuf.fedorapeople.org/fortran-modules/fortran-modules.html
+.. _`P1689r3`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1689r3.html
+.. _`cxx-modules-sandbox`: https://github.com/mathstuf/cxx-modules-sandbox
index 75d685c..664b7a4 100644 (file)
@@ -357,3 +357,13 @@ policies added for that version.  Commit with a message such as::
   The files generatd by `install(EXPORT)` and `export()` commands
   are known to work with policies as of CMake $prev, so enable them
   in sufficiently new CMake versions.
+
+Update the ``cmake_minimum_required`` version range in CMake itself:
+
+* ``CMakeLists.txt``
+* ``Utilities/Doxygen/CMakeLists.txt``
+* ``Utilities/Sphinx/CMakeLists.txt``
+
+to end in the previous release.  Commit with a message such as::
+
+  Configure CMake itself with policies through CMake $prev
diff --git a/Help/envvar/CUDAARCHS.rst b/Help/envvar/CUDAARCHS.rst
new file mode 100644 (file)
index 0000000..82369cd
--- /dev/null
@@ -0,0 +1,13 @@
+CUDAARCHS
+---------
+
+.. versionadded:: 3.20
+
+.. include:: ENV_VAR.txt
+
+Value used to initialize :variable:`CMAKE_CUDA_ARCHITECTURES` on the first
+configuration if it's not already defined. Subsequent runs will use the value
+stored in the cache.
+
+This is a semicolon-separated list of architectures as described in
+:prop_tgt:`CUDA_ARCHITECTURES`.
index 19b15e9..963f9d1 100644 (file)
@@ -13,5 +13,8 @@ configuration run (including the first), the environment variable will be
 ignored if the :variable:`CMAKE_CUDA_HOST_COMPILER` variable is defined.
 
 This environment variable is primarily meant for use with projects that
-enable ``CUDA`` as a first-class language.  The :module:`FindCUDA`
-module will also use it to initialize its ``CUDA_HOST_COMPILER`` setting.
+enable ``CUDA`` as a first-class language.
+
+.. versionadded:: 3.13
+  The :module:`FindCUDA`
+  module will use this variable to initialize its ``CUDA_HOST_COMPILER`` setting.
index d830542..85da715 100644 (file)
@@ -7,13 +7,15 @@ Project files for CodeBlocks will be created in the top directory and
 in every subdirectory which features a ``CMakeLists.txt`` file containing
 a :command:`project` call.  Additionally a hierarchy of makefiles is generated
 into the build tree.
-The :variable:`CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES` variable may
-be set to ``ON`` to exclude any files which are located outside of
-the project root directory.
 The appropriate make program can build the
 project through the default ``all`` target.  An ``install`` target is
 also provided.
 
+.. versionadded:: 3.10
+ The :variable:`CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES` variable may
+ be set to ``ON`` to exclude any files which are located outside of
+ the project root directory.
+
 This "extra" generator may be specified as:
 
 ``CodeBlocks - MinGW Makefiles``
@@ -23,7 +25,8 @@ This "extra" generator may be specified as:
  Generate with :generator:`NMake Makefiles`.
 
 ``CodeBlocks - NMake Makefiles JOM``
- Generate with :generator:`NMake Makefiles JOM`.
+ .. versionadded:: 3.8
+  Generate with :generator:`NMake Makefiles JOM`.
 
 ``CodeBlocks - Ninja``
  Generate with :generator:`Ninja`.
index 46fa5be..4f276df 100644 (file)
@@ -6,13 +6,15 @@ Generates CodeLite project files.
 Project files for CodeLite will be created in the top directory and
 in every subdirectory which features a CMakeLists.txt file containing
 a :command:`project` call.
-The :variable:`CMAKE_CODELITE_USE_TARGETS` variable may be set to ``ON``
-to change the default behavior from projects to targets as the basis
-for project files.
 The appropriate make program can build the
 project through the default ``all`` target.  An ``install`` target
 is also provided.
 
+.. versionadded:: 3.7
+ The :variable:`CMAKE_CODELITE_USE_TARGETS` variable may be set to ``ON``
+ to change the default behavior from projects to targets as the basis
+ for project files.
+
 This "extra" generator may be specified as:
 
 ``CodeLite - MinGW Makefiles``
index 2246699..5d2b1cd 100644 (file)
@@ -3,22 +3,36 @@ Green Hills MULTI
 
 .. versionadded:: 3.3
 
+.. versionadded:: 3.15
+  Linux support.
+
 Generates Green Hills MULTI project files (experimental, work-in-progress).
 
-The buildsystem has predetermined build-configuration settings that can be controlled
-via the :variable:`CMAKE_BUILD_TYPE` variable.
+Customizations are available through the following cache variables:
+
+* ``GHS_CUSTOMIZATION``
+* ``GHS_GPJ_MACROS``
+
+.. versionadded:: 3.14
+  The buildsystem has predetermined build-configuration settings that can be controlled
+  via the :variable:`CMAKE_BUILD_TYPE` variable.
+
+Toolset and Platform Selection
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.13
 
 Customizations that are used to pick toolset and target system:
 
-The ``-A <arch>`` can be supplied for setting the target architecture.
-``<arch>`` usually is one of ``arm``, ``ppc``, ``86``, etcetera.
-If the target architecture is not specified then
-the default architecture of ``arm`` will be used.
+The ``-A <arch>`` can be supplied for setting the target architecture.
+  ``<arch>`` usually is one of ``arm``, ``ppc``, ``86``, etcetera.
+  If the target architecture is not specified then
+  the default architecture of ``arm`` will be used.
 
-The ``-T <toolset>`` option can be used to set the directory location of the toolset.
-Both absolute and relative paths are valid. Relative paths use ``GHS_TOOLSET_ROOT``
-as the root. If the toolset is not specified then the latest toolset found in
-``GHS_TOOLSET_ROOT`` will be used.
+The ``-T <toolset>`` option can be used to set the directory location of the toolset.
+  Both absolute and relative paths are valid. Relative paths use ``GHS_TOOLSET_ROOT``
+  as the root. If the toolset is not specified then the latest toolset found in
+  ``GHS_TOOLSET_ROOT`` will be used.
 
 Cache variables that are used for toolset and target system customization:
 
@@ -50,15 +64,18 @@ Cache variables that are used for toolset and target system customization:
     a specific RTOS is to be used.
   | ``GHS_OS_DIR_OPTION`` default value is ``-os_dir``.
 
+  .. versionadded:: 3.15
+    The ``GHS_OS_DIR_OPTION`` variable.
+
 * ``GHS_BSP_NAME``
 
   | Sets ``-bsp`` entry in project file.
   | Defaults to ``sim<arch>`` for ``integrity`` platforms.
 
-Customizations are available through the following cache variables:
+Target Properties
+^^^^^^^^^^^^^^^^^
 
-* ``GHS_CUSTOMIZATION``
-* ``GHS_GPJ_MACROS``
+.. versionadded:: 3.14
 
 The following properties are available:
 
index 3a8744c..e0f4c90 100644 (file)
@@ -2,3 +2,6 @@ NMake Makefiles JOM
 -------------------
 
 Generates JOM makefiles.
+
+.. versionadded:: 3.8
+  :generator:`CodeBlocks` generator can be used as an extra generator.
index 112db74..8901192 100644 (file)
@@ -86,3 +86,78 @@ used to generate ``generated.c``, which would be used to build the ``Debug``
 configuration of ``generated``. This is useful for running a release-optimized
 version of a generator utility while still building the debug version of the
 targets built with the generated code.
+
+Custom Commands
+^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+The ``Ninja Multi-Config`` generator adds extra capabilities to
+:command:`add_custom_command` and :command:`add_custom_target` through its
+cross-config mode. The ``COMMAND``, ``DEPENDS``, and ``WORKING_DIRECTORY``
+arguments can be evaluated in the context of either the "command config" (the
+"native" configuration of the ``build-<Config>.ninja`` file in use) or the
+"output config" (the configuration used to evaluate the ``OUTPUT`` and
+``BYPRODUCTS``).
+
+If either ``OUTPUT`` or ``BYPRODUCTS`` names a path that is common to
+more than one configuration (e.g. it does not use any generator expressions),
+all arguments are evaluated in the command config by default.
+If all ``OUTPUT`` and ``BYPRODUCTS`` paths are unique to each configuration
+(e.g. by using the ``$<CONFIG>`` generator expression), the first argument of
+``COMMAND`` is still evaluated in the command config by default, while all
+subsequent arguments, as well as the arguments to ``DEPENDS`` and
+``WORKING_DIRECTORY``, are evaluated in the output config. These defaults can
+be overridden with the ``$<OUTPUT_CONFIG:...>`` and ``$<COMMAND_CONFIG:...>``
+generator-expressions. Note that if a target is specified by its name in
+``DEPENDS``, or as the first argument of ``COMMAND``, it is always evaluated
+in the command config, even if it is wrapped in ``$<OUTPUT_CONFIG:...>``
+(because its plain name is not a generator expression).
+
+As an example, consider the following:
+
+.. code-block:: cmake
+
+  add_custom_command(
+    OUTPUT "$<CONFIG>.txt"
+    COMMAND generator "$<CONFIG>.txt" "$<OUTPUT_CONFIG:$<CONFIG>>" "$<COMMAND_CONFIG:$<CONFIG>>"
+    DEPENDS tgt1 "$<TARGET_FILE:tgt2>" "$<OUTPUT_CONFIG:$<TARGET_FILE:tgt3>>" "$<COMMAND_CONFIG:$<TARGET_FILE:tgt4>>"
+    )
+
+Assume that ``generator``, ``tgt1``, ``tgt2``, ``tgt3``, and ``tgt4`` are all
+executable targets, and assume that ``$<CONFIG>.txt`` is built in the ``Debug``
+output config using the ``Release`` command config. The ``Release`` build of
+the ``generator`` target is called with ``Debug.txt Debug Release`` as
+arguments. The command depends on the ``Release`` builds of ``tgt1`` and
+``tgt4``, and the ``Debug`` builds of ``tgt2`` and ``tgt3``.
+
+``PRE_BUILD``, ``PRE_LINK``, and ``POST_BUILD`` custom commands for targets
+only get run in their "native" configuration (the ``Release`` configuration in
+the ``build-Release.ninja`` file) unless they have no ``BYPRODUCTS`` or their
+``BYPRODUCTS`` are unique per config. Consider the following example:
+
+.. code-block:: cmake
+
+  add_executable(exe main.c)
+  add_custom_command(
+    TARGET exe
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E echo "Running no-byproduct command"
+    )
+  add_custom_command(
+    TARGET exe
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E echo "Running separate-byproduct command for $<CONFIG>"
+    BYPRODUCTS $<CONFIG>.txt
+    )
+  add_custom_command(
+    TARGET exe
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E echo "Running common-byproduct command for $<CONFIG>"
+    BYPRODUCTS exe.txt
+    )
+
+In this example, if you build ``exe:Debug`` in ``build-Release.ninja``, the
+first and second custom commands get run, since their byproducts are unique
+per-config, but the last custom command does not. However, if you build
+``exe:Release`` in ``build-Release.ninja``, all three custom commands get run.
index 08ee81b..f3ba222 100644 (file)
@@ -11,32 +11,57 @@ For each subdirectory ``sub/dir`` of the project, additional targets
 are generated:
 
 ``sub/dir/all``
-  Depends on all targets required by the subdirectory.
+
+  .. versionadded:: 3.6
+
+    Depends on all targets required by the subdirectory.
 
 ``sub/dir/install``
-  Runs the install step in the subdirectory, if any.
+
+  .. versionadded:: 3.7
+
+    Runs the install step in the subdirectory, if any.
 
 ``sub/dir/install/strip``
-  Runs the install step in the subdirectory followed by a ``CMAKE_STRIP`` command,
-  if any.
 
-  The ``CMAKE_STRIP`` variable will contain the platform's ``strip`` utility, which
-  removes symbols information from generated binaries.
+  .. versionadded:: 3.7
+    Runs the install step in the subdirectory followed by a ``CMAKE_STRIP`` command,
+    if any.
+
+    The ``CMAKE_STRIP`` variable will contain the platform's ``strip`` utility, which
+    removes symbols information from generated binaries.
 
 ``sub/dir/test``
-  Runs the test step in the subdirectory, if any.
+
+  .. versionadded:: 3.7
+
+    Runs the test step in the subdirectory, if any.
 
 ``sub/dir/package``
-  Runs the package step in the subdirectory, if any.
+
+  .. versionadded:: 3.7
+
+    Runs the package step in the subdirectory, if any.
 
 Fortran Support
 ^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.7
+
 The ``Ninja`` generator conditionally supports Fortran when the ``ninja``
 tool is at least version 1.10 (which has the required features).
 
+Swift Support
+^^^^^^^^^^^^^
+
+.. versionadded:: 3.15
+
+The Swift support is experimental, not considered stable, and may change
+in future releases of CMake.
+
 See Also
 ^^^^^^^^
 
-The :generator:`Ninja Multi-Config` generator is similar to the ``Ninja``
-generator, but generates multiple configurations at once.
+.. versionadded:: 3.17
+  The :generator:`Ninja Multi-Config` generator is similar to the ``Ninja``
+  generator, but generates multiple configurations at once.
index 0293631..e361719 100644 (file)
@@ -1,7 +1,11 @@
-For each toolset that comes with this version of Visual Studio, there are
-variants that are themselves compiled for 32-bit (``x86``) and
-64-bit (``x64``) hosts (independent of the architecture they target).
-|VS_TOOLSET_HOST_ARCH_DEFAULT|
-One may explicitly request use of either the 32-bit or 64-bit host tools
-by adding either ``host=x86`` or ``host=x64`` to the toolset specification.
-See the :variable:`CMAKE_GENERATOR_TOOLSET` variable for details.
+.. versionadded:: 3.8
+  For each toolset that comes with this version of Visual Studio, there are
+  variants that are themselves compiled for 32-bit (``x86``) and
+  64-bit (``x64``) hosts (independent of the architecture they target).
+  |VS_TOOLSET_HOST_ARCH_DEFAULT|
+  One may explicitly request use of either the 32-bit or 64-bit host tools
+  by adding either ``host=x86`` or ``host=x64`` to the toolset specification.
+  See the :variable:`CMAKE_GENERATOR_TOOLSET` variable for details.
+
+.. versionadded:: 3.14
+  Added suport for ``host=x86`` option.
index 4bf9a8f..b4376d8 100644 (file)
@@ -17,13 +17,14 @@ Platform Selection
 
 The default target platform name (architecture) is ``Win32``.
 
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
-via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
-name (architecture).  For example:
-
-* ``cmake -G "Visual Studio 10 2010" -A Win32``
-* ``cmake -G "Visual Studio 10 2010" -A x64``
-* ``cmake -G "Visual Studio 10 2010" -A Itanium``
+.. versionadded:: 3.1
+  The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+  via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+  name (architecture).  For example:
+
+  * ``cmake -G "Visual Studio 10 2010" -A Win32``
+  * ``cmake -G "Visual Studio 10 2010" -A x64``
+  * ``cmake -G "Visual Studio 10 2010" -A Itanium``
 
 For compatibility with CMake versions prior to 3.1, one may specify
 a target platform name optionally at the end of the generator name.
index 5d89a6e..932548b 100644 (file)
@@ -17,15 +17,16 @@ Platform Selection
 
 The default target platform name (architecture) is ``Win32``.
 
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
-via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
-name (architecture).  For example:
-
-* ``cmake -G "Visual Studio 11 2012" -A Win32``
-* ``cmake -G "Visual Studio 11 2012" -A x64``
-* ``cmake -G "Visual Studio 11 2012" -A ARM``
-* ``cmake -G "Visual Studio 11 2012" -A <WinCE-SDK>``
-  (Specify a target platform matching a Windows CE SDK name.)
+.. versionadded:: 3.1
+  The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+  via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+  name (architecture).  For example:
+
+  * ``cmake -G "Visual Studio 11 2012" -A Win32``
+  * ``cmake -G "Visual Studio 11 2012" -A x64``
+  * ``cmake -G "Visual Studio 11 2012" -A ARM``
+  * ``cmake -G "Visual Studio 11 2012" -A <WinCE-SDK>``
+    (Specify a target platform matching a Windows CE SDK name.)
 
 For compatibility with CMake versions prior to 3.1, one may specify
 a target platform name optionally at the end of the generator name.
index fb8e021..b5fa1bf 100644 (file)
@@ -17,13 +17,14 @@ Platform Selection
 
 The default target platform name (architecture) is ``Win32``.
 
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
-via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
-name (architecture).  For example:
-
-* ``cmake -G "Visual Studio 12 2013" -A Win32``
-* ``cmake -G "Visual Studio 12 2013" -A x64``
-* ``cmake -G "Visual Studio 12 2013" -A ARM``
+.. versionadded:: 3.1
+  The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+  via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+  name (architecture).  For example:
+
+  * ``cmake -G "Visual Studio 12 2013" -A Win32``
+  * ``cmake -G "Visual Studio 12 2013" -A x64``
+  * ``cmake -G "Visual Studio 12 2013" -A ARM``
 
 For compatibility with CMake versions prior to 3.1, one may specify
 a target platform name optionally at the end of the generator name.
index 5b319bb..9c61641 100644 (file)
@@ -51,6 +51,8 @@ via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
 Windows 10 SDK Maximum Version for VS 2015
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.19
+
 Microsoft stated in a "Windows 10 October 2018 Update" blog post that Windows
 10 SDK versions (15063, 16299, 17134, 17763) are not supported by VS 2015 and
 are only supported by VS 2017 and later.  Therefore by default CMake
index e7baaad..a002f2f 100644 (file)
@@ -14,18 +14,20 @@ projects (JavaScript, Powershell, Python, etc.) are not supported.
 Instance Selection
 ^^^^^^^^^^^^^^^^^^
 
-VS 2017 supports multiple installations on the same machine.
-The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a
-cache entry containing the absolute path to a Visual Studio instance.
-If the value is not specified explicitly by the user or a toolchain file,
-CMake queries the Visual Studio Installer to locate VS instances, chooses
-one, and sets the variable as a cache entry to hold the value persistently.
-
-When CMake first chooses an instance, if the ``VS150COMNTOOLS`` environment
-variable is set and points to the ``Common7/Tools`` directory within
-one of the instances, that instance will be used.  Otherwise, if more
-than one instance is installed we do not define which one is chosen
-by default.
+.. versionadded:: 3.9
+  VS 2017 supports multiple installations on the same machine.
+  The :variable:`CMAKE_GENERATOR_INSTANCE` variable may be set as a
+  cache entry containing the absolute path to a Visual Studio instance.
+  If the value is not specified explicitly by the user or a toolchain file,
+  CMake queries the Visual Studio Installer to locate VS instances, chooses
+  one, and sets the variable as a cache entry to hold the value persistently.
+
+.. versionadded:: 3.11
+  When CMake first chooses an instance, if the ``VS150COMNTOOLS`` environment
+  variable is set and points to the ``Common7/Tools`` directory within
+  one of the instances, that instance will be used.  Otherwise, if more
+  than one instance is installed we do not define which one is chosen
+  by default.
 
 Platform Selection
 ^^^^^^^^^^^^^^^^^^
index a09d047..644f936 100644 (file)
@@ -8,15 +8,16 @@ Platform Selection
 
 The default target platform name (architecture) is ``Win32``.
 
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
-via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
-name (architecture).  For example:
-
-* ``cmake -G "Visual Studio 9 2008" -A Win32``
-* ``cmake -G "Visual Studio 9 2008" -A x64``
-* ``cmake -G "Visual Studio 9 2008" -A Itanium``
-* ``cmake -G "Visual Studio 9 2008" -A <WinCE-SDK>``
-  (Specify a target platform matching a Windows CE SDK name.)
+.. versionadded:: 3.1
+  The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+  via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+  name (architecture).  For example:
+
+  * ``cmake -G "Visual Studio 9 2008" -A Win32``
+  * ``cmake -G "Visual Studio 9 2008" -A x64``
+  * ``cmake -G "Visual Studio 9 2008" -A Itanium``
+  * ``cmake -G "Visual Studio 9 2008" -A <WinCE-SDK>``
+    (Specify a target platform matching a Windows CE SDK name.)
 
 For compatibility with CMake versions prior to 3.1, one may specify
 a target platform name optionally at the end of the generator name.
index be03a22..e4900a1 100644 (file)
@@ -3,7 +3,8 @@ Xcode
 
 Generate Xcode project files.
 
-This supports Xcode 5.0 and above.
+.. versionchanged:: 3.15
+  This generator supports Xcode 5.0 and above.
 
 .. _`Xcode Build System Selection`:
 
@@ -14,7 +15,8 @@ By default Xcode is allowed to select its own default toolchain.
 The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
 via the :manual:`cmake(1)` ``-T`` option, to specify another toolset.
 
-This generator supports toolset specification using one of these forms:
+.. versionadded:: 3.19
+  This generator supports toolset specification using one of these forms:
 
 * ``toolset``
 * ``toolset[,key=value]*``
@@ -33,3 +35,12 @@ Supported pairs are:
 
   For example, to select the original build system under Xcode 12,
   run :manual:`cmake(1)` with the option ``-T buildsystem=1``.
+
+Swift Support
+^^^^^^^^^^^^^
+
+.. versionadded:: 3.4
+
+When using the :generator:`Xcode` generator with Xcode 6.1 or higher,
+one may enable the ``Swift`` language with the :command:`enable_language`
+command or the :command:`project`.
index 8ea31a0..addf932 100644 (file)
@@ -82,8 +82,8 @@ as the include directories, compile definitions, etc. used to build the
 artifacts. Such information can be obtained by using the
 :manual:`File API <cmake-file-api(7)>`. The manual page for the File API
 contains more information about the API and how to invoke it.
-:manual:`Server mode <cmake-server(7)>` is deprecated and should not be
-used on CMake 3.14 or later.
+:manual:`Server mode <cmake-server(7)>` was removed as of CMake 3.20 and
+should not be used on CMake 3.14 or later.
 
 IDEs should avoid creating more build trees than necessary, and only create
 multiple build trees if the user wishes to switch to a different compiler,
index 13c82dd..9a9e40e 100644 (file)
@@ -31,7 +31,7 @@ install(FILES MathFunctions.h DESTINATION include)
 install(EXPORT MathFunctionsTargets
         FILE MathFunctionsTargets.cmake
         NAMESPACE MathFunctions::
-        DESTINATION lib/cmake
+        DESTINATION lib/cmake/MathFunctions
 )
 
 # include CMakePackageConfigHelpers macro
@@ -58,14 +58,14 @@ write_basic_package_version_file(
 # create config file
 configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
   "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
-  INSTALL_DESTINATION lib/cmake
+  INSTALL_DESTINATION lib/cmake/MathFunctions
 )
 
 # install config files
 install(FILES
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
-        DESTINATION lib/cmake
+        DESTINATION lib/cmake/MathFunctions
 )
 
 # generate the export targets for the build tree
index e3cf711..17ad952 100644 (file)
@@ -26,5 +26,5 @@ install(FILES Addition.h DESTINATION include)
 install(EXPORT AdditionTargets
         FILE MathFunctionsAdditionTargets.cmake
         NAMESPACE MathFunctions::
-        DESTINATION lib/cmake
+        DESTINATION lib/cmake/MathFunctions
 )
index 4e3496d..fd95e28 100644 (file)
@@ -24,7 +24,7 @@ write_basic_package_version_file(
 # create config file
 configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
   "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
-  INSTALL_DESTINATION lib/cmake
+  INSTALL_DESTINATION lib/cmake/MathFunctions
   NO_CHECK_REQUIRED_COMPONENTS_MACRO
 )
 
@@ -32,5 +32,5 @@ configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
 install(FILES
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
-        DESTINATION lib/cmake
+        DESTINATION lib/cmake/MathFunctions
 )
index ffa1e3d..be5ae65 100644 (file)
@@ -26,5 +26,5 @@ install(FILES SquareRoot.h DESTINATION include)
 install(EXPORT SquareRootTargets
         FILE MathFunctionsSquareRootTargets.cmake
         NAMESPACE MathFunctions::
-        DESTINATION lib/cmake
+        DESTINATION lib/cmake/MathFunctions
 )
index 4b09e53..94753d5 100644 (file)
@@ -176,7 +176,7 @@ directory:
 To make use of the new library we will add an :command:`add_subdirectory`
 call in the top-level ``CMakeLists.txt`` file so that the library will get
 built. We add the new library to the executable, and add ``MathFunctions`` as
-an include directory so that the ``mqsqrt.h`` header file can be found. The
+an include directory so that the ``mysqrt.h`` header file can be found. The
 last few lines of the top-level ``CMakeLists.txt`` file should now look like:
 
 .. code-block:: cmake
@@ -414,27 +414,23 @@ tutorial assume that they are not common.
 
 If the platform has ``log`` and ``exp`` then we will use them to compute the
 square root in the ``mysqrt`` function. We first test for the availability of
-these functions using the :module:`CheckSymbolExists` module in the top-level
-``CMakeLists.txt``. On some platforms, we will need to link to the m library.
-If ``log`` and ``exp`` are not initially found, require the m library and try
-again.
-
-We're going to use the new defines in ``TutorialConfig.h.in``, so be sure to
-set them before that file is configured.
+these functions using the :module:`CheckSymbolExists` module in
+``MathFunctions/CMakeLists.txt``. On some platforms, we will need to link to
+the m library. If ``log`` and ``exp`` are not initially found, require the m
+library and try again.
 
 .. literalinclude:: Step6/MathFunctions/CMakeLists.txt
   :language: cmake
   :start-after: # does this system provide the log and exp functions?
   :end-before: # add compile definitions
 
-Now let's add these defines to ``TutorialConfig.h.in`` so that we can use them
-from ``mysqrt.cxx``:
-
-.. code-block:: console
+If available, use :command:`target_compile_definitions` to specify
+``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions.
 
-  // does the platform provide exp and log functions?
-  #cmakedefine HAVE_LOG
-  #cmakedefine HAVE_EXP
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+  :language: cmake
+  :start-after: # add compile definitions
+  :end-before: # install rules
 
 If ``log`` and ``exp`` are available on the system, then we will use them to
 compute the square root in the ``mysqrt`` function. Add the following code to
@@ -456,51 +452,8 @@ Run the :manual:`cmake  <cmake(1)>` executable or the
 :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
 with your chosen build tool and run the Tutorial executable.
 
-You will notice that we're not using ``log`` and ``exp``, even if we think they
-should be available. We should realize quickly that we have forgotten to
-include ``TutorialConfig.h`` in ``mysqrt.cxx``.
-
-We will also need to update ``MathFunctions/CMakeLists.txt`` so ``mysqrt.cxx``
-knows where this file is located:
-
-.. code-block:: cmake
-
-  target_include_directories(MathFunctions
-            INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
-            PRIVATE ${CMAKE_BINARY_DIR}
-            )
-
-After making this update, go ahead and build the project again and run the
-built Tutorial executable. If ``log`` and ``exp`` are still not being used,
-open the generated ``TutorialConfig.h`` file from the build directory. Maybe
-they aren't available on the current system?
-
 Which function gives better results now, sqrt or mysqrt?
 
-Specify Compile Definition
---------------------------
-
-Is there a better place for us to save the ``HAVE_LOG`` and ``HAVE_EXP`` values
-other than in ``TutorialConfig.h``? Let's try to use
-:command:`target_compile_definitions`.
-
-First, remove the defines from ``TutorialConfig.h.in``. We no longer need to
-include ``TutorialConfig.h`` from ``mysqrt.cxx`` or the extra include in
-``MathFunctions/CMakeLists.txt``.
-
-Next, we can move the check for ``HAVE_LOG`` and ``HAVE_EXP`` to
-``MathFunctions/CMakeLists.txt`` and then specify those values as ``PRIVATE``
-compile definitions.
-
-.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
-  :language: cmake
-  :start-after: # does this system provide the log and exp functions?
-  :end-before: # install rules
-
-After making these updates, go ahead and build the project again. Run the
-built Tutorial executable and verify that the results are same as earlier in
-this step.
-
 Adding a Custom Command and Generated File (Step 6)
 ===================================================
 
index 9e9f2a5..ba8196b 100644 (file)
@@ -228,7 +228,7 @@ The Visual Studio toolset can be specified with the
 .. code-block:: console
 
     $ # Build with the clang-cl toolset
-    $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T LLVM
+    $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T ClangCL
     $ # Build targeting Windows XP
     $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp
 
index 0aa4f75..036fa8f 100644 (file)
@@ -20,6 +20,7 @@ These commands are always available.
    /command/cmake_language
    /command/cmake_minimum_required
    /command/cmake_parse_arguments
+   /command/cmake_path
    /command/cmake_policy
    /command/configure_file
    /command/continue
index 690d293..0d15ddf 100644 (file)
@@ -89,6 +89,8 @@ Feature requirements are evaluated transitively by consuming the link
 implementation.  See :manual:`cmake-buildsystem(7)` for more on
 transitive behavior of build properties and usage requirements.
 
+.. _`Requiring Language Standards`:
+
 Requiring Language Standards
 ----------------------------
 
@@ -358,6 +360,7 @@ versions specified for each:
 
 * ``Cray``: Cray Compiler Environment version 8.1+.
 * ``PGI``: PGI version 12.10+.
+* ``NVHPC``: NVIDIA HPC compilers version 11.0+.
 * ``TI``: Texas Instruments compiler.
 * ``XL``: IBM XL version 10.1+.
 
@@ -373,4 +376,5 @@ their associated meta-features (e.g. ``cuda_std_11``) available from the
 following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
 versions specified for each:
 
+* ``Clang``: Clang compiler 5.0+.
 * ``NVIDIA``: NVIDIA nvcc compiler 7.5+.
index 85ed935..af9a8ab 100644 (file)
@@ -23,15 +23,14 @@ in turn link to developer guides for CMake itself.
 Find Modules
 ============
 
-A "find module" is a ``Find<PackageName>.cmake`` file to be loaded
-by the :command:`find_package` command when invoked for ``<PackageName>``.
+A "find module" is a ``Find<PackageName>.cmake`` file to be loaded by the
+:command:`find_package` command when invoked for ``<PackageName>``.
 
-The primary task of a find module is to determine whether a package
-exists on the system, set the ``<PackageName>_FOUND`` variable to reflect
-this and provide any variables, macros and imported targets required to
-use the package.  A find module is useful in cases where an upstream
-library does not provide a
-:ref:`config file package <Config File Packages>`.
+The primary task of a find module is to determine whether a package is
+available, set the ``<PackageName>_FOUND`` variable to reflect this and
+provide any variables, macros and imported targets required to use the
+package.  A find module is useful in cases where an upstream library does
+not provide a :ref:`config file package <Config File Packages>`.
 
 The traditional approach is to use variables for everything, including
 libraries and executables: see the `Standard Variable Names`_ section
@@ -91,55 +90,92 @@ Standard Variable Names
 For a ``FindXxx.cmake`` module that takes the approach of setting
 variables (either instead of or in addition to creating imported
 targets), the following variable names should be used to keep things
-consistent between find modules.  Note that all variables start with
-``Xxx_`` to make sure they do not interfere with other find modules; the
-same consideration applies to macros, functions and imported targets.
+consistent between Find modules.  Note that all variables start with
+``Xxx_``, which (unless otherwise noted) must match exactly the name
+of the ``FindXxx.cmake`` file, including upper/lowercase.
+This prefix on the variable names ensures that they do not conflict with
+variables of other Find modules.  The same pattern should also be followed
+for any macros, functions and imported targets defined by the Find module.
 
 ``Xxx_INCLUDE_DIRS``
   The final set of include directories listed in one variable for use by
-  client code.  This should not be a cache entry.
+  client code. This should not be a cache entry (note that this also means
+  this variable should not be used as the result variable of a
+  :command:`find_path` command - see ``Xxx_INCLUDE_DIR`` below for that).
 
 ``Xxx_LIBRARIES``
-  The libraries to link against to use Xxx. These should include full
-  paths.  This should not be a cache entry.
+  The libraries to use with the module.  These may be CMake targets, full
+  absolute paths to a library binary or the name of a library that the
+  linker must find in its search path.  This should not be a cache entry
+  (note that this also means this variable should not be used as the
+  result variable of a :command:`find_library` command - see
+  ``Xxx_LIBRARY`` below for that).
 
 ``Xxx_DEFINITIONS``
-  Definitions to use when compiling code that uses Xxx. This really
-  shouldn't include options such as ``-DHAS_JPEG`` that a client
+  The compile definitions to use when compiling code that uses the module.
+  This really shouldn't include options such as ``-DHAS_JPEG`` that a client
   source-code file uses to decide whether to ``#include <jpeg.h>``
 
 ``Xxx_EXECUTABLE``
-  Where to find the Xxx tool.
-
-``Xxx_Yyy_EXECUTABLE``
-  Where to find the Yyy tool that comes with Xxx.
+  The full absolute path to an executable.  In this case, ``Xxx`` might not
+  be the name of the module, it might be the name of the tool (usually
+  converted to all uppercase), assuming that tool has such a well-known name
+  that it is unlikely that another tool with the same name exists.  It would
+  be appropriate to use this as the result variable of a
+  :command:`find_program` command.
+
+``Xxx_YYY_EXECUTABLE``
+  Similar to ``Xxx_EXECUTABLE`` except here the ``Xxx`` is always the module
+  name and ``YYY`` is the tool name (again, usually fully uppercase).
+  Prefer this form if the tool name is not very widely known or has the
+  potential  to clash with another tool.  For greater consistency, also
+  prefer this form if the module provides more than one executable.
 
 ``Xxx_LIBRARY_DIRS``
   Optionally, the final set of library directories listed in one
-  variable for use by client code.  This should not be a cache entry.
+  variable for use by client code. This should not be a cache entry.
 
 ``Xxx_ROOT_DIR``
-  Where to find the base directory of Xxx.
-
-``Xxx_VERSION_Yy``
-  Expect Version Yy if true. Make sure at most one of these is ever true.
-
-``Xxx_WRAP_Yy``
-  If False, do not try to use the relevant CMake wrapping command.
+  Where to find the base directory of the module.
+
+``Xxx_VERSION_VV``
+  Variables of this form specify whether the ``Xxx`` module being provided
+  is version ``VV`` of the module.  There should not be more than one
+  variable of this form set to true for a given module.  For example, a
+  module ``Barry`` might have evolved over many years and gone through a
+  number of different major versions.  Version 3 of the ``Barry`` module
+  might set the variable ``Barry_VERSION_3`` to true, whereas an older
+  version of the module might set ``Barry_VERSION_2`` to true instead.
+  It would be an error for both ``Barry_VERSION_3`` and ``Barry_VERSION_2``
+  to both be set to true.
+
+``Xxx_WRAP_YY``
+  When a variable of this form is set to false, it indicates that the
+  relevant wrapping command should not be used.  The wrapping command
+  depends on the module, it may be implied by the module name or it might
+  be specified by the ``YY`` part of the variable.
 
 ``Xxx_Yy_FOUND``
-  If False, optional Yy part of Xxx system is not available.
+  For variables of this form, ``Yy`` is the name of a component for the
+  module.  It should match exactly one of the valid component names that
+  may be passed to the :command:`find_package` command for the module.
+  If a variable of this form is set to false, it means that the ``Yy``
+  component of module ``Xxx`` was not found or is not available.
+  Variables of this form would typically be used for optional components
+  so that the caller can check whether an optional component is available.
 
 ``Xxx_FOUND``
-  Set to false, or undefined, if we haven't found, or don't want to use
-  Xxx.
+  When the :command:`find_package` command returns to the caller, this
+  variable will be set to true if the module was deemed to have been found
+  successfully.
 
 ``Xxx_NOT_FOUND_MESSAGE``
   Should be set by config-files in the case that it has set
   ``Xxx_FOUND`` to FALSE.  The contained message will be printed by the
   :command:`find_package` command and by
-  ``find_package_handle_standard_args()`` to inform the user about the
-  problem.
+  :command:`find_package_handle_standard_args` to inform the user about the
+  problem.  Use this instead of calling :command:`message` directly to
+  report a reason for failing to find the module or package.
 
 ``Xxx_RUNTIME_LIBRARY_DIRS``
   Optionally, the runtime library search path for use when running an
@@ -160,23 +196,36 @@ same consideration applies to macros, functions and imported targets.
 ``Xxx_VERSION_PATCH``
   The patch version of the package found, if any.
 
-The following names should not usually be used in CMakeLists.txt files, but
-are typically cache variables for users to edit and control the
-behaviour of find modules (like entering the path to a library manually)
+The following names should not usually be used in ``CMakeLists.txt`` files.
+They are intended for use by Find modules to specify and cache the locations
+of specific files or directories.  Users are typically able to set and edit
+these variables to control the behavior of Find modules (like entering the
+path to a library manually):
 
 ``Xxx_LIBRARY``
-  The path of the Xxx library (as used with :command:`find_library`, for
-  example).
+  The path of the library.  Use this form only when the module provides a
+  single library.  It is appropriate to use this as the result variable
+  in a :command:`find_library` command.
 
 ``Xxx_Yy_LIBRARY``
-  The path of the Yy library that is part of the Xxx system. It may or
-  may not be required to use Xxx.
+  The path of library ``Yy`` provided by the module ``Xxx``.  Use this form
+  when the module provides more than one library or where other modules may
+  also provide a library of the same name. It is also appropriate to use
+  this form as the result variable in a :command:`find_library` command.
 
 ``Xxx_INCLUDE_DIR``
-  Where to find headers for using the Xxx library.
+  When the module provides only a single library, this variable can be used
+  to specify where to find headers for using the library (or more accurately,
+  the path that consumers of the library should add to their header search
+  path).  It would be appropriate to use this as the result variable in a
+  :command:`find_path` command.
 
 ``Xxx_Yy_INCLUDE_DIR``
-  Where to find headers for using the Yy library of the Xxx system.
+  If the module provides more than one library or where other modules may
+  also provide a library of the same name, this form is recommended for
+  specifying where to find headers for using library ``Yy`` provided by
+  the module.  Again, it would be appropriate to use this as the result
+  variable in a :command:`find_path` command.
 
 To prevent users being overwhelmed with settings to configure, try to
 keep as many options as possible out of the cache, leaving at least one
@@ -185,7 +234,8 @@ not-found library (e.g. ``Xxx_ROOT_DIR``).  For the same reason, mark
 most cache options as advanced.  For packages which provide both debug
 and release binaries, it is common to create cache variables with a
 ``_LIBRARY_<CONFIG>`` suffix, such as ``Foo_LIBRARY_RELEASE`` and
-``Foo_LIBRARY_DEBUG``.
+``Foo_LIBRARY_DEBUG``.  The :module:`SelectLibraryConfigurations` module
+can be helpful for such cases.
 
 While these are the standard variable names, you should provide
 backwards compatibility for any old names that were actually in use.
index d9cfa7a..bc1fa1d 100644 (file)
@@ -57,6 +57,7 @@ Environment Variables for Languages
    /envvar/CC
    /envvar/CFLAGS
    /envvar/CSFLAGS
+   /envvar/CUDAARCHS
    /envvar/CUDACXX
    /envvar/CUDAFLAGS
    /envvar/CUDAHOSTCXX
index 6876e1c..89739b7 100644 (file)
@@ -1154,3 +1154,160 @@ The members specific to ``cmakeFiles`` objects are:
   ``isCMake``
     Optional member that is present with boolean value ``true``
     if the path specifies a file in the CMake installation.
+
+Object Kind "toolchains"
+------------------------
+
+The ``toolchains`` object kind lists properties of the toolchains used during
+the build.  These include the language, compiler path, ID, and version.
+
+There is only one ``toolchains`` object major version, version 1.
+
+"toolchains" version 1
+^^^^^^^^^^^^^^^^^^^^^^
+
+``toolchains`` object version 1 is a JSON object:
+
+.. code-block:: json
+
+  {
+    "kind": "toolchains",
+    "version": { "major": 1, "minor": 0 },
+    "toolchains": [
+      {
+        "language": "C",
+        "compiler": {
+          "path": "/usr/bin/cc",
+          "id": "GNU",
+          "version": "9.3.0",
+          "implicit": {
+            "includeDirectories": [
+              "/usr/lib/gcc/x86_64-linux-gnu/9/include",
+              "/usr/local/include",
+              "/usr/include/x86_64-linux-gnu",
+              "/usr/include"
+            ],
+            "linkDirectories": [
+              "/usr/lib/gcc/x86_64-linux-gnu/9",
+              "/usr/lib/x86_64-linux-gnu",
+              "/usr/lib",
+              "/lib/x86_64-linux-gnu",
+              "/lib"
+            ],
+            "linkFrameworkDirectories": [],
+            "linkLibraries": [ "gcc", "gcc_s", "c", "gcc", "gcc_s" ]
+          }
+        },
+        "sourceFileExtensions": [ "c", "m" ]
+      },
+      {
+        "language": "CXX",
+        "compiler": {
+          "path": "/usr/bin/c++",
+          "id": "GNU",
+          "version": "9.3.0",
+          "implicit": {
+            "includeDirectories": [
+              "/usr/include/c++/9",
+              "/usr/include/x86_64-linux-gnu/c++/9",
+              "/usr/include/c++/9/backward",
+              "/usr/lib/gcc/x86_64-linux-gnu/9/include",
+              "/usr/local/include",
+              "/usr/include/x86_64-linux-gnu",
+              "/usr/include"
+            ],
+            "linkDirectories": [
+              "/usr/lib/gcc/x86_64-linux-gnu/9",
+              "/usr/lib/x86_64-linux-gnu",
+              "/usr/lib",
+              "/lib/x86_64-linux-gnu",
+              "/lib"
+            ],
+            "linkFrameworkDirectories": [],
+            "linkLibraries": [
+              "stdc++", "m", "gcc_s", "gcc", "c", "gcc_s", "gcc"
+            ]
+          }
+        },
+        "sourceFileExtensions": [
+          "C", "M", "c++", "cc", "cpp", "cxx", "mm", "CPP"
+        ]
+      }
+    ]
+  }
+
+The members specific to ``toolchains`` objects are:
+
+``toolchains``
+  A JSON array whose entries are each a JSON object specifying a toolchain
+  associated with a particular language. The members of each entry are:
+
+  ``language``
+    A JSON string specifying the toolchain language, like C or CXX. Language
+    names are the same as langauge names that can be passed to the
+    :command:`project` command. Because CMake only supports a single toolchain
+    per language, this field can be used as a key.
+
+  ``compiler``
+    A JSON object containing members:
+
+    ``path``
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER` variable is defined for the current
+      language. Its value is a JSON string holding the path to the compiler.
+
+    ``id``
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER_ID` variable is defined for the current
+      language. Its value is a JSON string holding the ID (GNU, MSVC, etc.) of
+      the compiler.
+
+    ``version``
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable is defined for the
+      current language. Its value is a JSON string holding the version of the
+      compiler.
+
+    ``target``
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER_TARGET` variable is defined for the
+      current language. Its value is a JSON string holding the cross-compiling
+      target of the compiler.
+
+    ``implicit``
+      A JSON object containing members:
+
+      ``includeDirectories``
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES` variable is
+        defined for the current language. Its value is a JSON array of JSON
+        strings where each string holds a path to an implicit include
+        directory for the compiler.
+
+      ``linkDirectories``
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES` variable is
+        defined for the current language. Its value is a JSON array of JSON
+        strings where each string holds a path to an implicit link directory
+        for the compiler.
+
+      ``linkFrameworkDirectories``
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` variable
+        is defined for the current language. Its value is a JSON array of JSON
+        strings where each string holds a path to an implicit link framework
+        directory for the compiler.
+
+      ``linkLibraries``
+        Optional member that is present when the
+        :variable:`CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES` variable is defined
+        for the current language. Its value is a JSON array of JSON strings
+        where each string holds a path to an implicit link library for the
+        compiler.
+
+  ``sourceFileExtensions``
+    Optional member that is present when the
+    :variable:`CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS` variable is defined for
+    the current language. Its value is a JSON array of JSON strings where each
+    each string holds a file extension (without the leading dot) for the
+    language.
index 482b14e..ca4ea3e 100644 (file)
@@ -46,7 +46,8 @@ Available boolean expressions are:
 Logical Operators
 -----------------
 
-``$<BOOL:string>``
+.. genex:: $<BOOL:string>
+
   Converts ``string`` to ``0`` or ``1``. Evaluates to ``0`` if any of the
   following is true:
 
@@ -57,23 +58,27 @@ Logical Operators
 
   Otherwise evaluates to ``1``.
 
-``$<AND:conditions>``
+.. genex:: $<AND:conditions>
+
   where ``conditions`` is a comma-separated list of boolean expressions.
   Evaluates to ``1`` if all conditions are ``1``.
   Otherwise evaluates to ``0``.
 
-``$<OR:conditions>``
+.. genex:: $<OR:conditions>
+
   where ``conditions`` is a comma-separated list of boolean expressions.
   Evaluates to ``1`` if at least one of the conditions is ``1``.
   Otherwise evaluates to ``0``.
 
-``$<NOT:condition>``
+.. genex:: $<NOT:condition>
+
   ``0`` if ``condition`` is ``1``, else ``1``.
 
 String Comparisons
 ------------------
 
-``$<STREQUAL:string1,string2>``
+.. genex:: $<STREQUAL:string1,string2>
+
   ``1`` if ``string1`` and ``string2`` are equal, else ``0``.
   The comparison is case-sensitive.  For a case-insensitive comparison,
   combine with a :ref:`string transforming generator expression
@@ -83,101 +88,150 @@ String Comparisons
 
     $<STREQUAL:$<UPPER_CASE:${foo}>,"BAR"> # "1" if ${foo} is any of "BAR", "Bar", "bar", ...
 
-``$<EQUAL:value1,value2>``
+.. genex:: $<EQUAL:value1,value2>
+
   ``1`` if ``value1`` and ``value2`` are numerically equal, else ``0``.
-``$<IN_LIST:string,list>``
+
+.. genex:: $<IN_LIST:string,list>
+
   ``1`` if ``string`` is member of the semicolon-separated ``list``, else ``0``.
   Uses case-sensitive comparisons.
-``$<VERSION_LESS:v1,v2>``
+
+.. genex:: $<VERSION_LESS:v1,v2>
+
   ``1`` if ``v1`` is a version less than ``v2``, else ``0``.
-``$<VERSION_GREATER:v1,v2>``
+
+.. genex:: $<VERSION_GREATER:v1,v2>
+
   ``1`` if ``v1`` is a version greater than ``v2``, else ``0``.
-``$<VERSION_EQUAL:v1,v2>``
+
+.. genex:: $<VERSION_EQUAL:v1,v2>
+
   ``1`` if ``v1`` is the same version as ``v2``, else ``0``.
-``$<VERSION_LESS_EQUAL:v1,v2>``
+
+.. genex:: $<VERSION_LESS_EQUAL:v1,v2>
+
   ``1`` if ``v1`` is a version less than or equal to ``v2``, else ``0``.
-``$<VERSION_GREATER_EQUAL:v1,v2>``
-  ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``.
 
+.. genex:: $<VERSION_GREATER_EQUAL:v1,v2>
+
+  ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``.
 
 Variable Queries
 ----------------
 
-``$<TARGET_EXISTS:target>``
+.. genex:: $<TARGET_EXISTS:target>
+
   ``1`` if ``target`` exists, else ``0``.
-``$<CONFIG:cfgs>``
+
+.. genex:: $<CONFIG:cfgs>
+
   ``1`` if config is any one of the entries in ``cfgs``, else ``0``. This is a
   case-insensitive comparison. The mapping in
   :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by this
   expression when it is evaluated on a property on an :prop_tgt:`IMPORTED`
   target.
-``$<PLATFORM_ID:platform_ids>``
+
+.. genex:: $<PLATFORM_ID:platform_ids>
+
   where ``platform_ids`` is a comma-separated list.
   ``1`` if the CMake's platform id matches any one of the entries in
   ``platform_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_SYSTEM_NAME` variable.
-``$<C_COMPILER_ID:compiler_ids>``
+
+.. genex:: $<C_COMPILER_ID:compiler_ids>
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the C compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<CXX_COMPILER_ID:compiler_ids>``
+
+.. genex:: $<CXX_COMPILER_ID:compiler_ids>
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the CXX compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<CUDA_COMPILER_ID:compiler_ids>``
+
+.. genex:: $<CUDA_COMPILER_ID:compiler_ids>
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the CUDA compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<OBJC_COMPILER_ID:compiler_ids>``
+
+.. genex:: $<OBJC_COMPILER_ID:compiler_ids>
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the Objective-C compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<OBJCXX_COMPILER_ID:compiler_ids>``
+
+.. genex:: $<OBJCXX_COMPILER_ID:compiler_ids>
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the Objective-C++ compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<Fortran_COMPILER_ID:compiler_ids>``
+
+.. genex:: $<Fortran_COMPILER_ID:compiler_ids>
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the Fortran compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<ISPC_COMPILER_ID:compiler_ids>``
+
+.. genex:: $<ISPC_COMPILER_ID:compiler_ids>
+
   where ``compiler_ids`` is a comma-separated list.
   ``1`` if the CMake's compiler id of the ISPC compiler matches any one
   of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<C_COMPILER_VERSION:version>``
+
+.. genex:: $<C_COMPILER_VERSION:version>
+
   ``1`` if the version of the C compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<CXX_COMPILER_VERSION:version>``
+
+.. genex:: $<CXX_COMPILER_VERSION:version>
+
   ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<CUDA_COMPILER_VERSION:version>``
+
+.. genex:: $<CUDA_COMPILER_VERSION:version>
+
   ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<OBJC_COMPILER_VERSION:version>``
+
+.. genex:: $<OBJC_COMPILER_VERSION:version>
+
   ``1`` if the version of the OBJC compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<OBJCXX_COMPILER_VERSION:version>``
+
+.. genex:: $<OBJCXX_COMPILER_VERSION:version>
+
   ``1`` if the version of the OBJCXX compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<Fortran_COMPILER_VERSION:version>``
+
+.. genex:: $<Fortran_COMPILER_VERSION:version>
+
   ``1`` if the version of the Fortran compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<ISPC_COMPILER_VERSION:version>``
+
+.. genex:: $<ISPC_COMPILER_VERSION:version>
+
   ``1`` if the version of the ISPC compiler matches ``version``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<TARGET_POLICY:policy>``
+
+.. genex:: $<TARGET_POLICY:policy>
+
   ``1`` if the ``policy`` was NEW when the 'head' target was created,
   else ``0``.  If the ``policy`` was not set, the warning message for the policy
   will be emitted. This generator expression only works for a subset of
   policies.
-``$<COMPILE_FEATURES:features>``
+
+.. genex:: $<COMPILE_FEATURES:features>
+
   where ``features`` is a comma-spearated list.
   Evaluates to ``1`` if all of the ``features`` are available for the 'head'
   target, and ``0`` otherwise. If this expression is used while evaluating
@@ -189,7 +243,8 @@ Variable Queries
 
 .. _`Boolean COMPILE_LANGUAGE Generator Expression`:
 
-``$<COMPILE_LANG_AND_ID:language,compiler_ids>``
+.. genex:: $<COMPILE_LANG_AND_ID:language,compiler_ids>
+
   ``1`` when the language used for compilation unit matches ``language`` and
   the CMake's compiler id of the language compiler matches any one of the
   entries in ``compiler_ids``, otherwise ``0``. This expression is a short form
@@ -225,7 +280,8 @@ Variable Queries
               $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:Clang>>:COMPILING_C_WITH_CLANG>
     )
 
-``$<COMPILE_LANGUAGE:languages>``
+.. genex:: $<COMPILE_LANGUAGE:languages>
+
   ``1`` when the language used for compilation unit matches any of the entries
   in ``languages``, otherwise ``0``.  This expression may be used to specify
   compile options, compile definitions, and include directories for source files of a
@@ -270,7 +326,8 @@ Variable Queries
 
 .. _`Boolean LINK_LANGUAGE Generator Expression`:
 
-``$<LINK_LANG_AND_ID:language,compiler_ids>``
+.. genex:: $<LINK_LANG_AND_ID:language,compiler_ids>
+
   ``1`` when the language used for link step matches ``language`` and the
   CMake's compiler id of the language linker matches any one of the entries
   in ``compiler_ids``, otherwise ``0``. This expression is a short form for the
@@ -309,7 +366,8 @@ Variable Queries
   ``$<LINK_LANGUAGE:language>`` for constraints about the usage of this
   generator expression.
 
-``$<LINK_LANGUAGE:languages>``
+.. genex:: $<LINK_LANGUAGE:languages>
+
   ``1`` when the language used for link step matches any of the entries
   in ``languages``, otherwise ``0``.  This expression may be used to specify
   link libraries, link options, link directories and link dependencies of a
@@ -371,14 +429,16 @@ Variable Queries
     evaluation will give ``C`` as link language, so the second pass will
     correctly add target ``libother`` as link dependency.
 
-``$<DEVICE_LINK:list>``
+.. genex:: $<DEVICE_LINK:list>
+
   Returns the list if it is the device link step, an empty list otherwise.
   The device link step is controlled by :prop_tgt:`CUDA_SEPARABLE_COMPILATION`
   and :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and
   policy :policy:`CMP0105`. This expression can only be used to specify link
   options.
 
-``$<HOST_LINK:list>``
+.. genex:: $<HOST_LINK:list>
+
   Returns the list if it is the normal link step, an empty list otherwise.
   This expression is mainly useful when a device link step is also involved
   (see ``$<DEVICE_LINK:list>`` generator expression). This expression can only
@@ -434,11 +494,16 @@ Escaped Characters
 
 String literals to escape the special meaning a character would otherwise have:
 
-``$<ANGLE-R>``
+.. genex:: $<ANGLE-R>
+
   A literal ``>``. Used for example to compare strings that contain a ``>``.
-``$<COMMA>``
+
+.. genex:: $<COMMA>
+
   A literal ``,``. Used for example to compare strings which contain a ``,``.
-``$<SEMICOLON>``
+
+.. genex:: $<SEMICOLON>
+
   A literal ``;``. Used to prevent list expansion on an argument with ``;``.
 
 .. _`Conditional Generator Expressions`:
@@ -449,11 +514,13 @@ Conditional Expressions
 Conditional generator expressions depend on a boolean condition
 that must be ``0`` or ``1``.
 
-``$<condition:true_string>``
+.. genex:: $<condition:true_string>
+
   Evaluates to ``true_string`` if ``condition`` is ``1``.
   Otherwise evaluates to the empty string.
 
-``$<IF:condition,true_string,false_string>``
+.. genex:: $<IF:condition,true_string,false_string>
+
   Evaluates to ``true_string`` if ``condition`` is ``1``.
   Otherwise evaluates to ``false_string``.
 
@@ -472,22 +539,34 @@ otherwise expands to the empty string.
 String Transformations
 ----------------------
 
-``$<JOIN:list,string>``
+.. genex:: $<JOIN:list,string>
+
   Joins the list with the content of ``string``.
-``$<REMOVE_DUPLICATES:list>``
+
+.. genex:: $<REMOVE_DUPLICATES:list>
+
   Removes duplicated items in the given ``list``.
-``$<FILTER:list,INCLUDE|EXCLUDE,regex>``
+
+.. genex:: $<FILTER:list,INCLUDE|EXCLUDE,regex>
+
   Includes or removes items from ``list`` that match the regular expression ``regex``.
-``$<LOWER_CASE:string>``
+
+.. genex:: $<LOWER_CASE:string>
+
   Content of ``string`` converted to lower case.
-``$<UPPER_CASE:string>``
+
+.. genex:: $<UPPER_CASE:string>
+
   Content of ``string`` converted to upper case.
 
-``$<GENEX_EVAL:expr>``
+.. genex:: $<GENEX_EVAL:expr>
+
   Content of ``expr`` evaluated as a generator expression in the current
   context. This enables consumption of generator expressions whose
   evaluation results itself in generator expressions.
-``$<TARGET_GENEX_EVAL:tgt,expr>``
+
+.. genex:: $<TARGET_GENEX_EVAL:tgt,expr>
+
   Content of ``expr`` evaluated as a generator expression in the context of
   ``tgt`` target. This enables consumption of custom target properties that
   themselves contain generator expressions.
@@ -526,62 +605,99 @@ String Transformations
 Variable Queries
 ----------------
 
-``$<CONFIG>``
+.. genex:: $<CONFIG>
+
   Configuration name.
-``$<CONFIGURATION>``
+
+.. genex:: $<CONFIGURATION>
+
   Configuration name. Deprecated since CMake 3.0. Use ``CONFIG`` instead.
-``$<PLATFORM_ID>``
+
+.. genex:: $<PLATFORM_ID>
+
   The current system's CMake platform id.
   See also the :variable:`CMAKE_SYSTEM_NAME` variable.
-``$<C_COMPILER_ID>``
+
+.. genex:: $<C_COMPILER_ID>
+
   The CMake's compiler id of the C compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<CXX_COMPILER_ID>``
+
+.. genex:: $<CXX_COMPILER_ID>
+
   The CMake's compiler id of the CXX compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<CUDA_COMPILER_ID>``
+
+.. genex:: $<CUDA_COMPILER_ID>
+
   The CMake's compiler id of the CUDA compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<OBJC_COMPILER_ID>``
+
+.. genex:: $<OBJC_COMPILER_ID>
+
   The CMake's compiler id of the OBJC compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<OBJCXX_COMPILER_ID>``
+
+.. genex:: $<OBJCXX_COMPILER_ID>
+
   The CMake's compiler id of the OBJCXX compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<Fortran_COMPILER_ID>``
+
+.. genex:: $<Fortran_COMPILER_ID>
+
   The CMake's compiler id of the Fortran compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<ISPC_COMPILER_ID>``
+
+.. genex:: $<ISPC_COMPILER_ID>
+
   The CMake's compiler id of the ISPC compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<C_COMPILER_VERSION>``
+
+.. genex:: $<C_COMPILER_VERSION>
+
   The version of the C compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<CXX_COMPILER_VERSION>``
+
+.. genex:: $<CXX_COMPILER_VERSION>
+
   The version of the CXX compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<CUDA_COMPILER_VERSION>``
+
+.. genex:: $<CUDA_COMPILER_VERSION>
+
   The version of the CUDA compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<OBJC_COMPILER_VERSION>``
+
+.. genex:: $<OBJC_COMPILER_VERSION>
+
   The version of the OBJC compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<OBJCXX_COMPILER_VERSION>``
+
+.. genex:: $<OBJCXX_COMPILER_VERSION>
+
   The version of the OBJCXX compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<Fortran_COMPILER_VERSION>``
+
+.. genex:: $<Fortran_COMPILER_VERSION>
+
   The version of the Fortran compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<ISPC_COMPILER_VERSION>``
+
+.. genex:: $<ISPC_COMPILER_VERSION>
+
   The version of the ISPC compiler used.
   See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable.
-``$<COMPILE_LANGUAGE>``
+
+.. genex:: $<COMPILE_LANGUAGE>
+
   The compile language of source files when evaluating compile options.
   See :ref:`the related boolean expression
   <Boolean COMPILE_LANGUAGE Generator Expression>`
   ``$<COMPILE_LANGUAGE:language>``
   for notes about the portability of this generator expression.
-``$<LINK_LANGUAGE>``
+
+.. genex:: $<LINK_LANGUAGE>
+
   The link language of target when evaluating link options.
   See :ref:`the related boolean expression
   <Boolean LINK_LANGUAGE Generator Expression>` ``$<LINK_LANGUAGE:language>``
@@ -608,14 +724,19 @@ In the following, "the ``tgt`` filename" means the name of the ``tgt``
 binary file. This has to be distinguished from "the target name",
 which is just the string ``tgt``.
 
-``$<TARGET_NAME_IF_EXISTS:tgt>``
+.. genex:: $<TARGET_NAME_IF_EXISTS:tgt>
+
   The target name ``tgt`` if the target exists, an empty string otherwise.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_FILE:tgt>``
+
+.. genex:: $<TARGET_FILE:tgt>
+
   Full path to the ``tgt`` binary file.
-``$<TARGET_FILE_BASE_NAME:tgt>``
+
+.. genex:: $<TARGET_FILE_BASE_NAME:tgt>
+
   Base name of ``tgt``, i.e. ``$<TARGET_FILE_NAME:tgt>`` without prefix and
   suffix.
   For example, if the ``tgt`` filename is ``libbase.so``, the base name is ``base``.
@@ -632,36 +753,48 @@ which is just the string ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_FILE_PREFIX:tgt>``
+
+.. genex:: $<TARGET_FILE_PREFIX:tgt>
+
   Prefix of the ``tgt`` filename (such as ``lib``).
 
   See also the :prop_tgt:`PREFIX` target property.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_FILE_SUFFIX:tgt>``
+
+.. genex:: $<TARGET_FILE_SUFFIX:tgt>
+
   Suffix of the ``tgt`` filename (extension such as ``.so`` or ``.exe``).
 
   See also the :prop_tgt:`SUFFIX` target property.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_FILE_NAME:tgt>``
+
+.. genex:: $<TARGET_FILE_NAME:tgt>
+
   The ``tgt`` filename.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_FILE_DIR:tgt>``
+
+.. genex:: $<TARGET_FILE_DIR:tgt>
+
   Directory of the ``tgt`` binary file.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_LINKER_FILE:tgt>``
+
+.. genex:: $<TARGET_LINKER_FILE:tgt>
+
   File used when linking to the ``tgt`` target.  This will usually
   be the library that ``tgt`` represents (``.a``, ``.lib``, ``.so``),
   but for a shared library on DLL platforms, it would be the ``.lib``
   import library associated with the DLL.
-``$<TARGET_LINKER_FILE_BASE_NAME:tgt>``
+
+.. genex:: $<TARGET_LINKER_FILE_BASE_NAME:tgt>
+
   Base name of file used to link the target ``tgt``, i.e.
   ``$<TARGET_LINKER_FILE_NAME:tgt>`` without prefix and suffix. For example,
   if target file name is ``libbase.a``, the base name is ``base``.
@@ -677,7 +810,9 @@ which is just the string ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_LINKER_FILE_PREFIX:tgt>``
+
+.. genex:: $<TARGET_LINKER_FILE_PREFIX:tgt>
+
   Prefix of file used to link target ``tgt``.
 
   See also the :prop_tgt:`PREFIX` and :prop_tgt:`IMPORT_PREFIX` target
@@ -685,7 +820,9 @@ which is just the string ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_LINKER_FILE_SUFFIX:tgt>``
+
+.. genex:: $<TARGET_LINKER_FILE_SUFFIX:tgt>
+
   Suffix of file used to link where ``tgt`` is the name of a target.
 
   The suffix corresponds to the file extension (such as ".so" or ".lib").
@@ -695,36 +832,49 @@ which is just the string ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_LINKER_FILE_NAME:tgt>``
+
+.. genex:: $<TARGET_LINKER_FILE_NAME:tgt>
+
   Name of file used to link target ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_LINKER_FILE_DIR:tgt>``
+
+.. genex:: $<TARGET_LINKER_FILE_DIR:tgt>
+
   Directory of file used to link target ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_SONAME_FILE:tgt>``
+
+.. genex:: $<TARGET_SONAME_FILE:tgt>
+
   File with soname (``.so.3``) where ``tgt`` is the name of a target.
-``$<TARGET_SONAME_FILE_NAME:tgt>``
+.. genex:: $<TARGET_SONAME_FILE_NAME:tgt>
+
   Name of file with soname (``.so.3``).
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_SONAME_FILE_DIR:tgt>``
+
+.. genex:: $<TARGET_SONAME_FILE_DIR:tgt>
+
   Directory of with soname (``.so.3``).
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_PDB_FILE:tgt>``
+
+.. genex:: $<TARGET_PDB_FILE:tgt>
+
   Full path to the linker generated program database file (.pdb)
   where ``tgt`` is the name of a target.
 
   See also the :prop_tgt:`PDB_NAME` and :prop_tgt:`PDB_OUTPUT_DIRECTORY`
   target properties and their configuration specific variants
   :prop_tgt:`PDB_NAME_<CONFIG>` and :prop_tgt:`PDB_OUTPUT_DIRECTORY_<CONFIG>`.
-``$<TARGET_PDB_FILE_BASE_NAME:tgt>``
+
+.. genex:: $<TARGET_PDB_FILE_BASE_NAME:tgt>
+
   Base name of the linker generated program database file (.pdb)
   where ``tgt`` is the name of a target.
 
@@ -740,23 +890,31 @@ which is just the string ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_PDB_FILE_NAME:tgt>``
+
+.. genex:: $<TARGET_PDB_FILE_NAME:tgt>
+
   Name of the linker generated program database file (.pdb).
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_PDB_FILE_DIR:tgt>``
+
+.. genex:: $<TARGET_PDB_FILE_DIR:tgt>
+
   Directory of the linker generated program database file (.pdb).
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_BUNDLE_DIR:tgt>``
+
+.. genex:: $<TARGET_BUNDLE_DIR:tgt>
+
   Full path to the bundle directory (``my.app``, ``my.framework``, or
   ``my.bundle``) where ``tgt`` is the name of a target.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_BUNDLE_CONTENT_DIR:tgt>``
+
+.. genex:: $<TARGET_BUNDLE_CONTENT_DIR:tgt>
+
   Full path to the bundle content directory where ``tgt`` is the name of a
   target. For the macOS SDK it leads to ``my.app/Contents``, ``my.framework``,
   or ``my.bundle/Contents``. For all other SDKs (e.g. iOS) it leads to
@@ -765,17 +923,23 @@ which is just the string ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on (see policy :policy:`CMP0112`).
-``$<TARGET_PROPERTY:tgt,prop>``
+
+.. genex:: $<TARGET_PROPERTY:tgt,prop>
+
   Value of the property ``prop`` on the target ``tgt``.
 
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
-``$<TARGET_PROPERTY:prop>``
+
+.. genex:: $<TARGET_PROPERTY:prop>
+
   Value of the property ``prop`` on the target for which the expression
   is being evaluated. Note that for generator expressions in
   :ref:`Target Usage Requirements` this is the consuming target rather
   than the target specifying the requirement.
-``$<INSTALL_PREFIX>``
+
+.. genex:: $<INSTALL_PREFIX>
+
   Content of the install prefix when the target is exported via
   :command:`install(EXPORT)`, or when evaluated in
   :prop_tgt:`INSTALL_NAME_DIR`, and empty otherwise.
@@ -783,30 +947,43 @@ which is just the string ``tgt``.
 Output-Related Expressions
 --------------------------
 
-``$<TARGET_NAME:...>``
+.. genex:: $<TARGET_NAME:...>
+
   Marks ``...`` as being the name of a target.  This is required if exporting
   targets to multiple dependent export sets.  The ``...`` must be a literal
   name of a target- it may not contain generator expressions.
-``$<LINK_ONLY:...>``
+
+.. genex:: $<LINK_ONLY:...>
+
   Content of ``...`` except when evaluated in a link interface while
   propagating :ref:`Target Usage Requirements`, in which case it is the
   empty string.
   Intended for use only in an :prop_tgt:`INTERFACE_LINK_LIBRARIES` target
   property, perhaps via the :command:`target_link_libraries` command,
   to specify private link dependencies without other usage requirements.
-``$<INSTALL_INTERFACE:...>``
+
+.. genex:: $<INSTALL_INTERFACE:...>
+
   Content of ``...`` when the property is exported using :command:`install(EXPORT)`,
   and empty otherwise.
-``$<BUILD_INTERFACE:...>``
+
+.. genex:: $<BUILD_INTERFACE:...>
+
   Content of ``...`` when the property is exported using :command:`export`, or
   when the target is used by another target in the same buildsystem. Expands to
   the empty string otherwise.
-``$<MAKE_C_IDENTIFIER:...>``
+
+.. genex:: $<MAKE_C_IDENTIFIER:...>
+
   Content of ``...`` converted to a C identifier.  The conversion follows the
   same behavior as :command:`string(MAKE_C_IDENTIFIER)`.
-``$<TARGET_OBJECTS:objLib>``
+
+.. genex:: $<TARGET_OBJECTS:objLib>
+
   List of objects resulting from build of ``objLib``.
-``$<SHELL_PATH:...>``
+
+.. genex:: $<SHELL_PATH:...>
+
   Content of ``...`` converted to shell path style. For example, slashes are
   converted to backslashes in Windows shells and drive letters are converted
   to posix paths in MSYS shells. The ``...`` must be an absolute path.
@@ -816,6 +993,26 @@ Output-Related Expressions
   ``;`` on Windows).  Be sure to enclose the argument containing this genex
   in double quotes in CMake source code so that ``;`` does not split arguments.
 
+.. genex:: $<OUTPUT_CONFIG:...>
+
+  .. versionadded:: 3.20
+
+  Only valid in :command:`add_custom_command` and :command:`add_custom_target`
+  as the outer-most generator expression in an argument.
+  With the :generator:`Ninja Multi-Config` generator, generator expressions
+  in ``...`` are evaluated using the custom command's "output config".
+  With other generators, the content of ``...`` is evaluated normally.
+
+.. genex:: $<COMMAND_CONFIG:...>
+
+  .. versionadded:: 3.20
+
+  Only valid in :command:`add_custom_command` and :command:`add_custom_target`
+  as the outer-most generator expression in an argument.
+  With the :generator:`Ninja Multi-Config` generator, generator expressions
+  in ``...`` are evaluated using the custom command's "command config".
+  With other generators, the content of ``...`` is evaluated normally.
+
 Debugging
 =========
 
index 431797f..17c1a1e 100644 (file)
@@ -15,7 +15,6 @@ These modules are loaded using the :command:`include` command.
 .. toctree::
    :maxdepth: 1
 
-   /module/AddFileDependencies
    /module/AndroidTestUtilities
    /module/BundleUtilities
    /module/CheckCCompilerFlag
@@ -75,7 +74,6 @@ These modules are loaded using the :command:`include` command.
    /module/CTestUseLaunchers
    /module/Dart
    /module/DeployQt4
-   /module/Documentation
    /module/ExternalData
    /module/ExternalProject
    /module/FeatureSummary
@@ -98,11 +96,8 @@ These modules are loaded using the :command:`include` command.
    /module/TestForSTDNamespace
    /module/UseEcos
    /module/UseJava
-   /module/UseJavaClassFilelist
-   /module/UseJavaSymlinks
    /module/UseSWIG
    /module/UsewxWidgets
-   /module/WriteCompilerDetectionHeader
 
 Find Modules
 ^^^^^^^^^^^^
@@ -276,15 +271,20 @@ Deprecated Utility Modules
 .. toctree::
    :maxdepth: 1
 
+   /module/AddFileDependencies
    /module/CMakeDetermineVSServicePack
    /module/CMakeExpandImportedTargets
    /module/CMakeForceCompiler
    /module/CMakeParseArguments
+   /module/Documentation
    /module/MacroAddFileDependencies
    /module/TestCXXAcceptsFlag
+   /module/UseJavaClassFilelist
+   /module/UseJavaSymlinks
    /module/UsePkgConfig
    /module/Use_wxWindows
    /module/WriteBasicConfigVersionFile
+   /module/WriteCompilerDetectionHeader
 
 Deprecated Find Modules
 =======================
index fa10f66..bd6b2f0 100644 (file)
@@ -51,6 +51,19 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used
 to determine whether to report an error on use of deprecated macros or
 functions.
 
+Policies Introduced by CMake 3.20
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0120: The WriteCompilerDetectionHeader module is removed. </policy/CMP0120>
+   CMP0119: LANGUAGE source file property explicitly compiles as language. </policy/CMP0119>
+   CMP0118: The GENERATED source file property is now visible in all directories. </policy/CMP0118>
+   CMP0117: MSVC RTTI flag /GR is not added to CMAKE_CXX_FLAGS by default. </policy/CMP0117>
+   CMP0116: Ninja generators transform DEPFILEs from add_custom_command(). </policy/CMP0116>
+   CMP0115: Source file extensions must be explicit. </policy/CMP0115>
+
 Policies Introduced by CMake 3.19
 =================================
 
index 6f137c4..467818d 100644 (file)
@@ -29,337 +29,839 @@ is using Git, ``CMakePresets.json`` may be tracked, and
 Format
 ======
 
-  The files are a JSON document with an object as the root:
+The files are a JSON document with an object as the root:
 
-  .. literalinclude:: presets/example.json
-    :language: json
+.. literalinclude:: presets/example.json
+  :language: json
 
-  The root object recognizes the following fields:
+The root object recognizes the following fields:
 
-  ``version``
+``version``
 
-    A required integer representing the version of the JSON schema. Currently,
-    the only supported version is 1.
+  A required integer representing the version of the JSON schema.
+  The supported versions are ``1`` and ``2``.
 
-  ``cmakeMinimumRequired``
+``cmakeMinimumRequired``
 
-    An optional object representing the minimum version of CMake needed to
-    build this project. This object consists of the following fields:
+  An optional object representing the minimum version of CMake needed to
+  build this project. This object consists of the following fields:
 
-    ``major``
+  ``major``
 
-      An optional integer representing the major version.
+    An optional integer representing the major version.
 
-    ``minor``
+  ``minor``
 
-      An optional integer representing the minor version.
+    An optional integer representing the minor version.
 
-    ``patch``
+  ``patch``
 
-      An optional integer representing the patch version.
+    An optional integer representing the patch version.
 
-  ``vendor``
+``vendor``
 
-    An optional map containing vendor-specific information. CMake does not
-    interpret the contents of this field except to verify that it is a map if
-    it does exist. However, the keys should be a vendor-specific domain name
-    followed by a ``/``-separated path. For example, the Example IDE 1.0 could
-    use ``example.com/ExampleIDE/1.0``. The value of each field can be anything
-    desired by the vendor, though will typically be a map.
+  An optional map containing vendor-specific information. CMake does not
+  interpret the contents of this field except to verify that it is a map if
+  it does exist. However, the keys should be a vendor-specific domain name
+  followed by a ``/``-separated path. For example, the Example IDE 1.0 could
+  use ``example.com/ExampleIDE/1.0``. The value of each field can be anything
+  desired by the vendor, though will typically be a map.
 
-  ``configurePresets``
+``configurePresets``
 
-    An optional array of configure preset objects. Each preset may contain the
-    following fields:
+  An optional array of `Configure Preset`_ objects.
+  This is allowed in preset files specifying version 1 or above.
 
-    ``name``
+``buildPresets``
+
+  An optional array of `Build Preset`_ objects.
+  This is allowed in preset files specifying version 2 or above.
+
+``testPresets``
+
+  An optional array of `Test Preset`_ objects.
+  This is allowed in preset files specifying version 2 or above.
+
+Configure Preset
+^^^^^^^^^^^^^^^^
+
+Each entry of the ``configurePresets`` array is a JSON object
+that may contain the following fields:
+
+``name``
+
+  A required string representing the machine-friendly name of the preset.
+  This identifier is used in the :ref:`cmake --preset <CMake Options>` option.
+  There must not be two configure presets in the union of ``CMakePresets.json``
+  and ``CMakeUserPresets.json`` in the same directory with the same name.
+  However, a configure preset may have the same name as a build or test preset.
+
+``hidden``
+
+  An optional boolean specifying whether or not a preset should be hidden.
+  If a preset is hidden, it cannot be used in the ``--preset=`` argument,
+  will not show up in the :manual:`CMake GUI <cmake-gui(1)>`, and does not
+  have to have a valid ``generator`` or ``binaryDir``, even from
+  inheritance. ``hidden`` presets are intended to be used as a base for
+  other presets to inherit via the ``inherits`` field.
+
+``inherits``
+
+  An optional array of strings representing the names of presets to inherit
+  from. The preset will inherit all of the fields from the ``inherits``
+  presets by default (except ``name``, ``hidden``, ``inherits``,
+  ``description``, and ``displayName``), but can override them as
+  desired. If multiple ``inherits`` presets provide conflicting values for
+  the same field, the earlier preset in the ``inherits`` list will be
+  preferred. Presets in ``CMakePresets.json`` may not inherit from presets
+  in ``CMakeUserPresets.json``.
+
+  This field can also be a string, which is equivalent to an array
+  containing one string.
+
+``vendor``
+
+  An optional map containing vendor-specific information. CMake does not
+  interpret the contents of this field except to verify that it is a map
+  if it does exist. However, it should follow the same conventions as the
+  root-level ``vendor`` field. If vendors use their own per-preset
+  ``vendor`` field, they should implement inheritance in a sensible manner
+  when appropriate.
+
+``displayName``
+
+  An optional string with a human-friendly name of the preset.
+
+``description``
+
+  An optional string with a human-friendly description of the preset.
+
+``generator``
+
+  An optional string representing the generator to use for the preset. If
+  ``generator`` is not specified, it must be inherited from the
+  ``inherits`` preset (unless this preset is ``hidden``).
+
+  Note that for Visual Studio generators, unlike in the command line ``-G``
+  argument, you cannot include the platform name in the generator name. Use
+  the ``architecture`` field instead.
+
+``architecture``, ``toolset``
+
+  Optional fields representing the platform and toolset, respectively, for
+  generators that support them. Each may be either a string or an object
+  with the following fields:
+
+  ``value``
+
+    An optional string representing the value.
+
+  ``strategy``
+
+    An optional string telling CMake how to handle the ``architecture`` or
+    ``toolset`` field. Valid values are:
+
+    ``"set"``
+
+      Set the respective value. This will result in an error for generators
+      that do not support the respective field.
+
+    ``"external"``
+
+      Do not set the value, even if the generator supports it. This is
+      useful if, for example, a preset uses the Ninja generator, and an IDE
+      knows how to set up the Visual C++ environment from the
+      ``architecture`` and ``toolset`` fields. In that case, CMake will
+      ignore the field, but the IDE can use them to set up the environment
+      before invoking CMake.
+
+``binaryDir``
+
+  An optional string representing the path to the output binary directory.
+  This field supports `macro expansion`_. If a relative path is specified,
+  it is calculated relative to the source directory. If ``binaryDir`` is not
+  specified, it must be inherited from the ``inherits`` preset (unless this
+  preset is ``hidden``).
+
+``cmakeExecutable``
+
+  An optional string representing the path to the CMake executable to use
+  for this preset. This is reserved for use by IDEs, and is not used by
+  CMake itself. IDEs that use this field should expand any macros in it.
+
+``cacheVariables``
+
+  An optional map of cache variables. The key is the variable name (which
+  may not be an empty string), and the value is either ``null``, a boolean
+  (which is equivalent to a value of ``"TRUE"`` or ``"FALSE"`` and a type
+  of ``BOOL``), a string representing the value of the variable (which
+  supports `macro expansion`_), or an object with the following fields:
+
+  ``type``
+
+    An optional string representing the type of the variable.
+
+  ``value``
+
+    A required string or boolean representing the value of the variable.
+    A boolean is equivalent to ``"TRUE"`` or ``"FALSE"``. This field
+    supports `macro expansion`_.
+
+  Cache variables are inherited through the ``inherits`` field, and the
+  preset's variables will be the union of its own ``cacheVariables`` and
+  the ``cacheVariables`` from all its parents. If multiple presets in this
+  union define the same variable, the standard rules of ``inherits`` are
+  applied. Setting a variable to ``null`` causes it to not be set, even if
+  a value was inherited from another preset.
+
+``environment``
+
+  An optional map of environment variables. The key is the variable name
+  (which may not be an empty string), and the value is either ``null`` or
+  a string representing the value of the variable. Each variable is set
+  regardless of whether or not a value was given to it by the process's
+  environment. This field supports `macro expansion`_, and environment
+  variables in this map may reference each other, and may be listed in any
+  order, as long as such references do not cause a cycle (for example,
+  if ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
+
+  Environment variables are inherited through the ``inherits`` field, and
+  the preset's environment will be the union of its own ``environment`` and
+  the ``environment`` from all its parents. If multiple presets in this
+  union define the same variable, the standard rules of ``inherits`` are
+  applied. Setting a variable to ``null`` causes it to not be set, even if
+  a value was inherited from another preset.
+
+``warnings``
+
+  An optional object specifying the warnings to enable. The object may
+  contain the following fields:
+
+  ``dev``
+
+    An optional boolean. Equivalent to passing ``-Wdev`` or ``-Wno-dev``
+    on the command line. This may not be set to ``false`` if ``errors.dev``
+    is set to ``true``.
+
+  ``deprecated``
+
+    An optional boolean. Equivalent to passing ``-Wdeprecated`` or
+    ``-Wno-deprecated`` on the command line. This may not be set to
+    ``false`` if ``errors.deprecated`` is set to ``true``.
+
+  ``uninitialized``
+
+    An optional boolean. Setting this to ``true`` is equivalent to passing
+    ``--warn-uninitialized`` on the command line.
+
+  ``unusedCli``
+
+    An optional boolean. Setting this to ``false`` is equivalent to passing
+    ``--no-warn-unused-cli`` on the command line.
+
+  ``systemVars``
+
+    An optional boolean. Setting this to ``true`` is equivalent to passing
+    ``--check-system-vars`` on the command line.
+
+``errors``
+
+  An optional object specifying the errors to enable. The object may
+  contain the following fields:
+
+  ``dev``
+
+    An optional boolean. Equivalent to passing ``-Werror=dev`` or
+    ``-Wno-error=dev`` on the command line. This may not be set to ``true``
+    if ``warnings.dev`` is set to ``false``.
+
+  ``deprecated``
+
+    An optional boolean. Equivalent to passing ``-Werror=deprecated`` or
+    ``-Wno-error=deprecated`` on the command line. This may not be set to
+    ``true`` if ``warnings.deprecated`` is set to ``false``.
+
+``debug``
+
+  An optional object specifying debug options. The object may contain the
+  following fields:
+
+  ``output``
+
+    An optional boolean. Setting this to ``true`` is equivalent to passing
+    ``--debug-output`` on the command line.
+
+  ``tryCompile``
+
+    An optional boolean. Setting this to ``true`` is equivalent to passing
+    ``--debug-trycompile`` on the command line.
+
+  ``find``
+
+    An optional boolean. Setting this to ``true`` is equivalent to passing
+    ``--debug-find`` on the command line.
+
+Build Preset
+^^^^^^^^^^^^
+
+Each entry of the ``buildPresets`` array is a JSON object
+that may contain the following fields:
+
+``name``
+
+  A required string representing the machine-friendly name of the preset.
+  This identifier is used in the
+  :ref:`cmake --build --preset <Build Tool Mode>` option.
+  There must not be two build presets in the union of ``CMakePresets.json``
+  and ``CMakeUserPresets.json`` in the same directory with the same name.
+  However, a build preset may have the same name as a configure or test preset.
+
+``hidden``
+
+  An optional boolean specifying whether or not a preset should be hidden.
+  If a preset is hidden, it cannot be used in the ``--preset`` argument
+  and does not have to have a valid ``configurePreset``, even from
+  inheritance. ``hidden`` presets are intended to be used as a base for
+  other presets to inherit via the ``inherits`` field.
+
+``inherits``
+
+  An optional array of strings representing the names of presets to
+  inherit from. The preset will inherit all of the fields from the
+  ``inherits`` presets by default (except ``name``, ``hidden``,
+  ``inherits``, ``description``, and ``displayName``), but can override
+  them as desired. If multiple ``inherits`` presets provide conflicting
+  values for the same field, the earlier preset in the ``inherits`` list
+  will be preferred. Presets in ``CMakePresets.json`` may not inherit from
+  presets in ``CMakeUserPresets.json``.
+
+  This field can also be a string, which is equivalent to an array
+  containing one string.
+
+``vendor``
+
+  An optional map containing vendor-specific information. CMake does not
+  interpret the contents of this field except to verify that it is a map
+  if it does exist. However, it should follow the same conventions as the
+  root-level ``vendor`` field. If vendors use their own per-preset
+  ``vendor`` field, they should implement inheritance in a sensible manner
+  when appropriate.
+
+``displayName``
+
+  An optional string with a human-friendly name of the preset.
+
+``description``
+
+  An optional string with a human-friendly description of the preset.
 
-      A required string representing the machine-friendly name of the preset.
-      This identifier is used in the ``--preset`` argument. There must not be
-      two presets in the union of ``CMakePresets.json`` and
-      ``CMakeUserPresets.json`` in the same directory with the same name.
+``environment``
 
-    ``hidden``
+  An optional map of environment variables. The key is the variable name
+  (which may not be an empty string), and the value is either ``null`` or
+  a string representing the value of the variable. Each variable is set
+  regardless of whether or not a value was given to it by the process's
+  environment. This field supports macro expansion, and environment
+  variables in this map may reference each other, and may be listed in any
+  order, as long as such references do not cause a cycle (for example, if
+  ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
 
-      An optional boolean specifying whether or not a preset should be hidden.
-      If a preset is hidden, it cannot be used in the ``--preset=`` argument,
-      will not show up in the :manual:`CMake GUI <cmake-gui(1)>`, and does not
-      have to have a valid ``generator`` or ``binaryDir``, even from
-      inheritance. ``hidden`` presets are intended to be used as a base for
-      other presets to inherit via the ``inherits`` field.
+  Environment variables are inherited through the ``inherits`` field, and
+  the preset's environment will be the union of its own ``environment``
+  and the ``environment`` from all its parents. If multiple presets in
+  this union define the same variable, the standard rules of ``inherits``
+  are applied. Setting a variable to ``null`` causes it to not be set,
+  even if a value was inherited from another preset.
 
-    ``inherits``
+``configurePreset``
 
-      An optional array of strings representing the names of presets to inherit
-      from. The preset will inherit all of the fields from the ``inherits``
-      presets by default (except ``name``, ``hidden``, ``inherits``,
-      ``description``, and ``displayName``), but can override them as
-      desired. If multiple ``inherits`` presets provide conflicting values for
-      the same field, the earlier preset in the ``inherits`` list will be
-      preferred. Presets in ``CMakePresets.json`` may not inherit from presets
-      in ``CMakeUserPresets.json``.
+  An optional string specifying the name of a configure preset to
+  associate with this build preset. If ``configurePreset`` is not
+  specified, it must be inherited from the inherits preset (unless this
+  preset is hidden). The build directory is inferred from the configure
+  preset, so the build will take place in the same ``binaryDir`` that the
+  configuration did.
 
-      This field can also be a string, which is equivalent to an array
-      containing one string.
+``inheritConfigureEnvironment``
 
-    ``vendor``
+  An optional boolean that defaults to true. If true, the environment
+  variables from the associated configure preset are inherited after all
+  inherited build preset environments, but before environment variables
+  explicitly specified in this build preset.
 
-      An optional map containing vendor-specific information. CMake does not
-      interpret the contents of this field except to verify that it is a map
-      if it does exist. However, it should follow the same conventions as the
-      root-level ``vendor`` field. If vendors use their own per-preset
-      ``vendor`` field, they should implement inheritance in a sensible manner
-      when appropriate.
+``jobs``
 
-    ``displayName``
+  An optional integer. Equivalent to passing ``--parallel`` or ``-j`` on
+  the command line.
 
-      An optional string with a human-friendly name of the preset.
+``targets``
 
-    ``description``
+  An optional string or array of strings. Equivalent to passing
+  ``--target`` or ``-t`` on the command line. Vendors may ignore the
+  targets property or hide build presets that explicitly specify targets.
+  This field supports macro expansion.
 
-      An optional string with a human-friendly description of the preset.
+``configuration``
 
-    ``generator``
+  An optional string. Equivalent to passing ``--config`` on the command
+  line.
 
-      An optional string representing the generator to use for the preset. If
-      ``generator`` is not specified, it must be inherited from the
-      ``inherits`` preset (unless this preset is ``hidden``).
+``cleanFirst``
 
-      Note that for Visual Studio generators, unlike in the command line ``-G``
-      argument, you cannot include the platform name in the generator name. Use
-      the ``architecture`` field instead.
+  An optional bool. If true, equivalent to passing ``--clean-first`` on
+  the command line.
 
-    ``architecture``
-    ``toolset``
+``verbose``
 
-      Optional fields representing the platform and toolset, respectively, for
-      generators that support them. Each may be either a string or an object
-      with the following fields:
+  An optional bool. If true, equivalent to passing ``--verbose`` on the
+  command line.
 
-      ``value``
+``nativeToolOptions``
 
-        An optional string representing the value.
+  An optional array of strings. Equivalent to passing options after ``--``
+  on the command line. The array values support macro expansion.
 
-      ``strategy``
+Test Preset
+^^^^^^^^^^^
 
-        An optional string telling CMake how to handle the ``architecture`` or
-        ``toolset`` field. Valid values are:
+Each entry of the ``testPresets`` array is a JSON object
+that may contain the following fields:
 
-        ``"set"``
+``name``
 
-          Set the respective value. This will result in an error for generators
-          that do not support the respective field.
+  A required string representing the machine-friendly name of the preset.
+  This identifier is used in the :ref:`ctest --preset <CTest Options>` option.
+  There must not be two test presets in the union of ``CMakePresets.json``
+  and ``CMakeUserPresets.json`` in the same directory with the same name.
+  However, a test preset may have the same name as a configure or build preset.
 
-        ``"external"``
+``hidden``
 
-          Do not set the value, even if the generator supports it. This is
-          useful if, for example, a preset uses the Ninja generator, and an IDE
-          knows how to set up the Visual C++ environment from the
-          ``architecture`` and ``toolset`` fields. In that case, CMake will
-          ignore the field, but the IDE can use them to set up the environment
-          before invoking CMake.
+  An optional boolean specifying whether or not a preset should be hidden.
+  If a preset is hidden, it cannot be used in the ``--preset`` argument
+  and does not have to have a valid ``configurePreset``, even from
+  inheritance. ``hidden`` presets are intended to be used as a base for
+  other presets to inherit via the ``inherits`` field.
 
-    ``binaryDir``
+``inherits``
 
-      An optional string representing the path to the output binary directory.
-      This field supports macro expansion. If a relative path is specified, it
-      is calculated relative to the source directory. If ``binaryDir`` is not
-      specified, it must be inherited from the ``inherits`` preset (unless this
-      preset is ``hidden``).
+  An optional array of strings representing the names of presets to
+  inherit from. The preset will inherit all of the fields from the
+  ``inherits`` presets by default (except ``name``, ``hidden``,
+  ``inherits``, ``description``, and ``displayName``), but can override
+  them as desired. If multiple ``inherits`` presets provide conflicting
+  values for the same field, the earlier preset in the ``inherits`` list
+  will be preferred. Presets in ``CMakePresets.json`` may not inherit from
+  presets in ``CMakeUserPresets.json``.
 
-    ``cmakeExecutable``
+  This field can also be a string, which is equivalent to an array
+  containing one string.
 
-      An optional string representing the path to the CMake executable to use
-      for this preset. This is reserved for use by IDEs, and is not used by
-      CMake itself. IDEs that use this field should expand any macros in it.
+``vendor``
 
-    ``cacheVariables``
+  An optional map containing vendor-specific information. CMake does not
+  interpret the contents of this field except to verify that it is a map
+  if it does exist. However, it should follow the same conventions as the
+  root-level ``vendor`` field. If vendors use their own per-preset
+  ``vendor`` field, they should implement inheritance in a sensible manner
+  when appropriate.
 
-      An optional map of cache variables. The key is the variable name (which
-      may not be an empty string), and the value is either ``null``, a boolean
-      (which is equivalent to a value of ``"TRUE"`` or ``"FALSE"`` and a type
-      of ``BOOL``), a string representing the value of the variable (which
-      supports macro expansion), or an object with the following fields:
+``displayName``
 
-      ``type``
+  An optional string with a human-friendly name of the preset.
 
-        An optional string representing the type of the variable.
+``description``
 
-      ``value``
+  An optional string with a human-friendly description of the preset.
 
-        A required string or boolean representing the value of the variable.
-        A boolean is equivalent to ``"TRUE"`` or ``"FALSE"``. This field
+``environment``
+
+  An optional map of environment variables. The key is the variable name
+  (which may not be an empty string), and the value is either ``null`` or
+  a string representing the value of the variable. Each variable is set
+  regardless of whether or not a value was given to it by the process's
+  environment. This field supports macro expansion, and environment
+  variables in this map may reference each other, and may be listed in any
+  order, as long as such references do not cause a cycle (for example, if
+  ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
+
+  Environment variables are inherited through the ``inherits`` field, and
+  the preset's environment will be the union of its own ``environment``
+  and the ``environment`` from all its parents. If multiple presets in
+  this union define the same variable, the standard rules of ``inherits``
+  are applied. Setting a variable to ``null`` causes it to not be set,
+  even if a value was inherited from another preset.
+
+``configurePreset``
+
+  An optional string specifying the name of a configure preset to
+  associate with this test preset. If ``configurePreset`` is not
+  specified, it must be inherited from the inherits preset (unless this
+  preset is hidden). The build directory is inferred from the configure
+  preset, so tests will run in the same ``binaryDir`` that the
+  configuration did and build did.
+
+``inheritConfigureEnvironment``
+
+  An optional boolean that defaults to true. If true, the environment
+  variables from the associated configure preset are inherited after all
+  inherited test preset environments, but before environment variables
+  explicitly specified in this test preset.
+
+``configuration``
+
+  An optional string. Equivalent to passing ``--build-config`` on the
+  command line.
+
+``overwriteConfigurationFile``
+
+  An optional array of configuration options to overwrite options
+  specified in the CTest configuration file. Equivalent to passing
+  ``--overwrite`` for each value in the array. The array values
+  support macro expansion.
+
+``output``
+
+  An optional object specifying output options. The object may contain the
+  following fields.
+
+  ``shortProgress``
+
+    An optional bool. If true, equivalent to passing ``--progress`` on the
+    command line.
+
+  ``verbosity``
+
+    An optional string specifying verbosity level. Must be one of the
+    following:
+
+    ``default``
+
+      Equivalent to passing no verbosity flags on the command line.
+
+    ``verbose``
+
+      Equivalent to passing ``--verbose`` on the command line.
+
+    ``extra``
+
+      Equivalent to passing ``--extra-verbose`` on the command line.
+
+  ``debug``
+
+    An optional bool. If true, equivalent to passing ``--debug`` on the
+    command line.
+
+  ``outputOnFailure``
+
+    An optional bool. If true, equivalent to passing
+    ``--output-on-failure`` on the command line.
+
+  ``quiet``
+
+    An optional bool. If true, equivalent to passing ``--quiet`` on the
+    command line.
+
+  ``outputLogFile``
+
+    An optional string specifying a path to a log file. Equivalent to
+    passing ``--output-log`` on the command line. This field supports
+    macro expansion.
+
+  ``labelSummary``
+
+    An optional bool. If false, equivalent to passing
+    ``--no-label-summary`` on the command line.
+
+  ``subprojectSummary``
+
+    An optional bool. If false, equivalent to passing
+    ``--no-subproject-summary`` on the command line.
+
+  ``maxPassedTestOutputSize``
+
+    An optional integer specifying the maximum output for passed tests in
+    bytes. Equivalent to passing ``--test-output-size-passed`` on the
+    command line.
+
+  ``maxFailedTestOutputSize``
+
+    An optional integer specifying the maximum output for failed tests in
+    bytes. Equivalent to passing ``--test-output-size-failed`` on the
+    command line.
+
+  ``maxTestNameWidth``
+
+    An optional integer specifying the maximum width of a test name to
+    output. Equivalent to passing ``--max-width`` on the command line.
+
+``filter``
+
+  An optional object specifying how to filter the tests to run. The object
+  may contain the following fields.
+
+  ``include``
+
+    An optional object specifying which tests to include. The object may
+    contain the following fields.
+
+    ``name``
+
+      An optional string specifying a regex for test names. Equivalent to
+      passing ``--tests-regex`` on the command line. This field supports
+      macro expansion.
+
+
+    ``label``
+
+      An optional string specifying a regex for test labels. Equivalent to
+      passing ``--label-regex`` on the command line. This field supports
+      macro expansion.
+
+    ``useUnion``
+
+      An optional bool. Equivalent to passing ``--union`` on the command
+      line.
+
+    ``index``
+
+      An optional object specifying tests to include by test index. The
+      object may contain the following fields. Can also be an optional
+      string specifying a file with the command line syntax for
+      ``--tests-information``. If specified as a string, this field
+      supports macro expansion.
+
+      ``start``
+
+        An optional integer specifying a test index to start testing at.
+
+      ``end``
+
+        An optional integer specifying a test index to stop testing at.
+
+      ``stride``
+
+        An optional integer specifying the increment.
+
+      ``specificTests``
+
+        An optional array of integers specifying specific test indices to
+        run.
+
+  ``exclude``
+
+    An optional object specifying which tests to exclude. The object may
+    contain the following fields.
+
+    ``name``
+
+      An optional string specifying a regex for test names. Equivalent to
+      passing ``--exclude-regex`` on the command line. This field supports
+      macro expansion.
+
+    ``label``
+
+      An optional string specifying a regex for test labels. Equivalent to
+      passing ``--label-exclude`` on the command line. This field supports
+      macro expansion.
+
+    ``fixtures``
+
+      An optional object specifying which fixtures to exclude from adding
+      tests. The object may contain the following fields.
+
+      ``any``
+
+        An optional string specifying a regex for text fixtures to exclude
+        from adding any tests. Equivalent to ``--fixture-exclude-any`` on
+        the command line. This field supports macro expansion.
+
+      ``setup``
+
+        An optional string specifying a regex for text fixtures to exclude
+        from adding setup tests. Equivalent to ``--fixture-exclude-setup``
+        on the command line. This field supports macro expansion.
+
+      ``cleanup``
+
+        An optional string specifying a regex for text fixtures to exclude
+        from adding cleanup tests. Equivalent to
+        ``--fixture-exclude-cleanup`` on the command line. This field
         supports macro expansion.
 
-      Cache variables are inherited through the ``inherits`` field, and the
-      preset's variables will be the union of its own ``cacheVariables`` and
-      the ``cacheVariables`` from all its parents. If multiple presets in this
-      union define the same variable, the standard rules of ``inherits`` are
-      applied. Setting a variable to ``null`` causes it to not be set, even if
-      a value was inherited from another preset.
+``execution``
+
+  An optional object specifying options for test execution. The object may
+  contain the following fields.
+
+  ``stopOnFailure``
+
+    An optional bool. If true, equivalent to passing ``--stop-on-failure``
+    on the command line.
+
+  ``enableFailover``
+
+    An optional bool. If true, equivalent to passing ``-F`` on the command
+    line.
+
+  ``jobs``
+
+    An optional integer. Equivalent to passing ``--parallel`` on the
+    command line.
+
+  ``resourceSpecFile``
+
+    An optional string. Equivalent to passing ``--resource-spec-file`` on
+    the command line. This field supports macro expansion.
+
+  ``testLoad``
 
-    ``environment``
+    An optional integer. Equivalent to passing ``--test-load`` on the
+    command line.
 
-      An optional map of environment variables. The key is the variable name
-      (which may not be an empty string), and the value is either ``null`` or
-      a string representing the value of the variable. Each variable is set
-      regardless of whether or not a value was given to it by the process's
-      environment. This field supports macro expansion, and environment
-      variables in this map may reference each other, and may be listed in any
-      order, as long as such references do not cause a cycle (for example,
-      if ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
+  ``showOnly``
 
-      Environment variables are inherited through the ``inherits`` field, and
-      the preset's environment will be the union of its own ``environment`` and
-      the ``environment`` from all its parents. If multiple presets in this
-      union define the same variable, the standard rules of ``inherits`` are
-      applied. Setting a variable to ``null`` causes it to not be set, even if
-      a value was inherited from another preset.
+    An optional string. Equivalent to passing ``--show-only`` on the
+    command line. The string must be one of the following values:
 
-    ``warnings``
+    ``human``
 
-      An optional object specifying the warnings to enable. The object may
-      contain the following fields:
+    ``json-v1``
 
-      ``dev``
+  ``repeat``
 
-        An optional boolean. Equivalent to passing ``-Wdev`` or ``-Wno-dev``
-        on the command line. This may not be set to ``false`` if ``errors.dev``
-        is set to ``true``.
+    An optional object specifying how to repeat tests. Equivalent to
+    passing ``--repeat`` on the command line. The object must have the
+    following fields.
 
-      ``deprecated``
+    ``mode``
 
-        An optional boolean. Equivalent to passing ``-Wdeprecated`` or
-        ``-Wno-deprecated`` on the command line. This may not be set to
-        ``false`` if ``errors.deprecated`` is set to ``true``.
+      A required string. Must be one of the following values:
 
-      ``uninitialized``
+      ``until-fail``
 
-        An optional boolean. Setting this to ``true`` is equivalent to passing
-        ``--warn-uninitialized`` on the command line.
+      ``until-pass``
 
-      ``unusedCli``
+      ``after-timeout``
 
-        An optional boolean. Setting this to ``false`` is equivalent to passing
-        ``--no-warn-unused-cli`` on the command line.
+    ``count``
 
-      ``systemVars``
+      A required integer.
 
-        An optional boolean. Setting this to ``true`` is equivalent to passing
-        ``--check-system-vars`` on the command line.
+  ``interactiveDebugging``
 
-    ``errors``
+    An optional bool. If true, equivalent to passing
+    ``--interactive-debug-mode 1`` on the command line. If false,
+    equivalent to passing ``--interactive-debug-mode 0`` on the command
+    line.
 
-      An optional object specifying the errors to enable. The object may
-      contain the following fields:
+  ``scheduleRandom``
 
-      ``dev``
+    An optional bool. If true, equivalent to passing ``--schedule-random``
+    on the command line.
 
-        An optional boolean. Equivalent to passing ``-Werror=dev`` or
-        ``-Wno-error=dev`` on the command line. This may not be set to ``true``
-        if ``warnings.dev`` is set to ``false``.
+  ``timeout``
 
-      ``deprecated``
+    An optional integer. Equivalent to passing ``--timeout`` on the
+    command line.
 
-        An optional boolean. Equivalent to passing ``-Werror=deprecated`` or
-        ``-Wno-error=deprecated`` on the command line. This may not be set to
-        ``true`` if ``warnings.deprecated`` is set to ``false``.
+  ``noTestsAction``
 
-    ``debug``
+    An optional string specifying the behavior if no tests are found. Must
+    be one of the following values:
 
-      An optional object specifying debug options. The object may contain the
-      following fields:
+    ``default``
 
-      ``output``
+      Equivalent to not passing any value on the command line.
 
-        An optional boolean. Setting this to ``true`` is equivalent to passing
-        ``--debug-output`` on the command line.
+    ``error``
 
-      ``tryCompile``
+      Equivalent to passing ``--no-tests=error`` on the command line.
 
-        An optional boolean. Setting this to ``true`` is equivalent to passing
-        ``--debug-trycompile`` on the command line.
+    ``ignore``
 
-      ``find``
+      Equivalent to passing ``--no-tests=ignore`` on the command line.
 
-        An optional boolean. Setting this to ``true`` is equivalent to passing
-        ``--debug-find`` on the command line.
+Macro Expansion
+^^^^^^^^^^^^^^^
 
-  As mentioned above, some fields support macro expansion. Macros are
-  recognized in the form ``$<macro-namespace>{<macro-name>}``. All macros are
-  evaluated in the context of the preset being used, even if the macro is in a
-  field that was inherited from another preset. For example, if the ``Base``
-  preset sets variable ``PRESET_NAME`` to ``${presetName}``, and the
-  ``Derived`` preset inherits from ``Base``, ``PRESET_NAME`` will be set to
-  ``Derived``.
+As mentioned above, some fields support macro expansion. Macros are
+recognized in the form ``$<macro-namespace>{<macro-name>}``. All macros are
+evaluated in the context of the preset being used, even if the macro is in a
+field that was inherited from another preset. For example, if the ``Base``
+preset sets variable ``PRESET_NAME`` to ``${presetName}``, and the
+``Derived`` preset inherits from ``Base``, ``PRESET_NAME`` will be set to
+``Derived``.
 
-  It is an error to not put a closing brace at the end of a macro name. For
-  example, ``${sourceDir`` is invalid. A dollar sign (``$``) followed by
-  anything other than a left curly brace (``{``) with a possible namespace is
-  interpreted as a literal dollar sign.
+It is an error to not put a closing brace at the end of a macro name. For
+example, ``${sourceDir`` is invalid. A dollar sign (``$``) followed by
+anything other than a left curly brace (``{``) with a possible namespace is
+interpreted as a literal dollar sign.
 
-  Recognized macros include:
+Recognized macros include:
 
-  ``${sourceDir}``
+``${sourceDir}``
 
-    Path to the project source directory.
+  Path to the project source directory.
 
-  ``${sourceParentDir}``
+``${sourceParentDir}``
 
-    Path to the project source directory's parent directory.
+  Path to the project source directory's parent directory.
 
-  ``${sourceDirName}``
+``${sourceDirName}``
 
-    The last filename component of ``${sourceDir}``. For example, if
-    ``${sourceDir}`` is ``/path/to/source``, this would be ``source``.
+  The last filename component of ``${sourceDir}``. For example, if
+  ``${sourceDir}`` is ``/path/to/source``, this would be ``source``.
 
-  ``${presetName}``
+``${presetName}``
 
-    Name specified in the preset's ``name`` field.
+  Name specified in the preset's ``name`` field.
 
-  ``${generator}``
+``${generator}``
 
-    Generator specified in the preset's ``generator`` field.
+  Generator specified in the preset's ``generator`` field. For build and
+  test presets, this will evaluate to the generator specified by
+  ``configurePreset``.
 
-  ``${dollar}``
+``${dollar}``
 
-    A literal dollar sign (``$``).
+  A literal dollar sign (``$``).
 
-  ``$env{<variable-name>}``
+``$env{<variable-name>}``
 
-    Environment variable with name ``<variable-name>``. The variable name may
-    not be an empty string. If the variable is defined in the ``environment``
-    field, that value is used instead of the value from the parent environment.
-    If the environment variable is not defined, this evaluates as an empty
-    string.
+  Environment variable with name ``<variable-name>``. The variable name may
+  not be an empty string. If the variable is defined in the ``environment``
+  field, that value is used instead of the value from the parent environment.
+  If the environment variable is not defined, this evaluates as an empty
+  string.
 
-    Note that while Windows environment variable names are case-insensitive,
-    variable names within a preset are still case-sensitive. This may lead to
-    unexpected results when using inconsistent casing. For best results, keep
-    the casing of environment variable names consistent.
+  Note that while Windows environment variable names are case-insensitive,
+  variable names within a preset are still case-sensitive. This may lead to
+  unexpected results when using inconsistent casing. For best results, keep
+  the casing of environment variable names consistent.
 
-  ``$penv{<variable-name>}``
+``$penv{<variable-name>}``
 
-    Similar to ``$env{<variable-name>}``, except that the value only comes from
-    the parent environment, and never from the ``environment`` field. This
-    allows you to prepend or append values to existing environment variables.
-    For example, setting ``PATH`` to ``/path/to/ninja/bin:$penv{PATH}`` will
-    prepend ``/path/to/ninja/bin`` to the ``PATH`` environment variable. This
-    is needed because ``$env{<variable-name>}`` does not allow circular
-    references.
+  Similar to ``$env{<variable-name>}``, except that the value only comes from
+  the parent environment, and never from the ``environment`` field. This
+  allows you to prepend or append values to existing environment variables.
+  For example, setting ``PATH`` to ``/path/to/ninja/bin:$penv{PATH}`` will
+  prepend ``/path/to/ninja/bin`` to the ``PATH`` environment variable. This
+  is needed because ``$env{<variable-name>}`` does not allow circular
+  references.
 
-  ``$vendor{<macro-name>}``
+``$vendor{<macro-name>}``
 
-    An extension point for vendors to insert their own macros. CMake will not
-    be able to use presets which have a ``$vendor{<macro-name>}`` macro, and
-    effectively ignores such presets. However, it will still be able to use
-    other presets from the same file.
+  An extension point for vendors to insert their own macros. CMake will not
+  be able to use presets which have a ``$vendor{<macro-name>}`` macro, and
+  effectively ignores such presets. However, it will still be able to use
+  other presets from the same file.
 
-    CMake does not make any attempt to interpret ``$vendor{<macro-name>}``
-    macros. However, to avoid name collisions, IDE vendors should prefix
-    ``<macro-name>`` with a very short (preferably <= 4 characters) vendor
-    identifier prefix, followed by a ``.``, followed by the macro name. For
-    example, the Example IDE could have ``$vendor{xide.ideInstallDir}``.
+  CMake does not make any attempt to interpret ``$vendor{<macro-name>}``
+  macros. However, to avoid name collisions, IDE vendors should prefix
+  ``<macro-name>`` with a very short (preferably <= 4 characters) vendor
+  identifier prefix, followed by a ``.``, followed by the macro name. For
+  example, the Example IDE could have ``$vendor{xide.ideInstallDir}``.
 
 Schema
 ======
index 5c8a05a..af170da 100644 (file)
@@ -196,6 +196,7 @@ Properties on Targets
    /prop_tgt/EXCLUDE_FROM_ALL
    /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD
    /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG
+   /prop_tgt/EXPORT_COMPILE_COMMANDS
    /prop_tgt/EXPORT_NAME
    /prop_tgt/EXPORT_PROPERTIES
    /prop_tgt/FOLDER
@@ -354,6 +355,7 @@ Properties on Targets
    /prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE
    /prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE
    /prop_tgt/UNITY_BUILD_MODE
+   /prop_tgt/UNITY_BUILD_UNIQUE_ID
    /prop_tgt/VERSION
    /prop_tgt/VISIBILITY_INLINES_HIDDEN
    /prop_tgt/VS_CONFIGURATION_TYPE
@@ -397,6 +399,10 @@ Properties on Targets
    /prop_tgt/WIN32_EXECUTABLE
    /prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS
    /prop_tgt/XCODE_ATTRIBUTE_an-attribute
+   /prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY
+   /prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY
+   /prop_tgt/XCODE_EMBED_type
+   /prop_tgt/XCODE_EMBED_type_PATH
    /prop_tgt/XCODE_EXPLICIT_FILE_TYPE
    /prop_tgt/XCODE_GENERATE_SCHEME
    /prop_tgt/XCODE_LINK_BUILD_PHASE_MODE
index d8d6172..f156f95 100644 (file)
@@ -48,6 +48,8 @@ and ``rcc`` for virtual file system content generation.  These tools may be
 automatically invoked by :manual:`cmake(1)` if the appropriate conditions
 are met.  The automatic tool invocation may be used with both Qt 4 and Qt 5.
 
+.. _`Qt AUTOMOC`:
+
 AUTOMOC
 ^^^^^^^
 
@@ -77,8 +79,9 @@ automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
 
 Not included ``moc_<basename>.cpp`` files will be generated in custom
 folders to avoid name collisions and included in a separate
-``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` file which is compiled
-into the target.
+file which is compiled into the target, named either
+``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp`` or
+``<AUTOGEN_BUILD_DIR>/mocs_compilation_$<CONFIG>.cpp``.
 
 * See :prop_tgt:`AUTOGEN_BUILD_DIR`.
 
index 8f10b9f..6c8d0f4 100644 (file)
@@ -3,742 +3,5 @@
 cmake-server(7)
 ***************
 
-.. only:: html
-
-   .. contents::
-
-.. deprecated:: 3.15
-
-  This will be removed from a future version of CMake.
-  Clients should use the :manual:`cmake-file-api(7)` instead.
-
-Introduction
-============
-
-:manual:`cmake(1)` is capable of providing semantic information about
-CMake code it executes to generate a buildsystem.  If executed with
-the ``-E server`` command line options, it starts in a long running mode
-and allows a client to request the available information via a JSON protocol.
-
-The protocol is designed to be useful to IDEs, refactoring tools, and
-other tools which have a need to understand the buildsystem in entirety.
-
-A single :manual:`cmake-buildsystem(7)` may describe buildsystem contents
-and build properties which differ based on
-:manual:`generation-time context <cmake-generator-expressions(7)>`
-including:
-
-* The Platform (eg, Windows, APPLE, Linux).
-* The build configuration (eg, Debug, Release, Coverage).
-* The Compiler (eg, MSVC, GCC, Clang) and compiler version.
-* The language of the source files compiled.
-* Available compile features (eg CXX variadic templates).
-* CMake policies.
-
-The protocol aims to provide information to tooling to satisfy several
-needs:
-
-#. Provide a complete and easily parsed source of all information relevant
-   to the tooling as it relates to the source code.  There should be no need
-   for tooling to parse generated buildsystems to access include directories
-   or compile definitions for example.
-#. Semantic information about the CMake buildsystem itself.
-#. Provide a stable interface for reading the information in the CMake cache.
-#. Information for determining when cmake needs to be re-run as a result of
-   file changes.
-
-
-Operation
-=========
-
-Start :manual:`cmake(1)` in the server command mode, supplying the path to
-the build directory to process::
-
-  cmake -E server (--debug|--pipe=<NAMED_PIPE>)
-
-The server will communicate using stdin/stdout (with the ``--debug`` parameter)
-or using a named pipe (with the ``--pipe=<NAMED_PIPE>`` parameter).  Note
-that "named pipe" refers to a local domain socket on Unix and to a named pipe
-on Windows.
-
-When connecting to the server (via named pipe or by starting it in ``--debug``
-mode), the server will reply with a hello message::
-
-  [== "CMake Server" ==[
-  {"supportedProtocolVersions":[{"major":1,"minor":0}],"type":"hello"}
-  ]== "CMake Server" ==]
-
-Messages sent to and from the process are wrapped in magic strings::
-
-  [== "CMake Server" ==[
-  {
-    ... some JSON message ...
-  }
-  ]== "CMake Server" ==]
-
-The server is now ready to accept further requests via the named pipe
-or stdin.
-
-
-Debugging
-=========
-
-CMake server mode can be asked to provide statistics on execution times, etc.
-or to dump a copy of the response into a file. This is done passing a "debug"
-JSON object as a child of the request.
-
-The debug object supports the "showStats" key, which takes a boolean and makes
-the server mode return a "zzzDebug" object with stats as part of its response.
-"dumpToFile" takes a string value and will cause the cmake server to copy
-the response into the given filename.
-
-This is a response from the cmake server with "showStats" set to true::
-
-  [== "CMake Server" ==[
-  {
-    "cookie":"",
-    "errorMessage":"Waiting for type \"handshake\".",
-    "inReplyTo":"unknown",
-   "type":"error",
-    "zzzDebug": {
-      "dumpFile":"/tmp/error.txt",
-      "jsonSerialization":0.011016,
-      "size":111,
-      "totalTime":0.025995
-    }
-  }
-  ]== "CMake Server" ==]
-
-The server has made a copy of this response into the file /tmp/error.txt and
-took 0.011 seconds to turn the JSON response into a string, and it took 0.025
-seconds to process the request in total. The reply has a size of 111 bytes.
-
-
-Protocol API
-============
-
-
-General Message Layout
-----------------------
-
-All messages need to have a "type" value, which identifies the type of
-message that is passed back or forth. E.g. the initial message sent by the
-server is of type "hello". Messages without a type will generate an response
-of type "error".
-
-All requests sent to the server may contain a "cookie" value. This value
-will he handed back unchanged in all responses triggered by the request.
-
-All responses will contain a value "inReplyTo", which may be empty in
-case of parse errors, but will contain the type of the request message
-in all other cases.
-
-
-Type "reply"
-^^^^^^^^^^^^
-
-This type is used by the server to reply to requests.
-
-The message may -- depending on the type of the original request --
-contain values.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"}
-  ]== "CMake Server" ==]
-
-
-Type "error"
-^^^^^^^^^^^^
-
-This type is used to return an error condition to the client. It will
-contain an "errorMessage".
-
-Example::
-
-  [== "CMake Server" ==[
-  {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"}
-  ]== "CMake Server" ==]
-
-
-Type "progress"
-^^^^^^^^^^^^^^^
-
-When the server is busy for a long time, it is polite to send back replies of
-type "progress" to the client. These will contain a "progressMessage" with a
-string describing the action currently taking place as well as
-"progressMinimum", "progressMaximum" and "progressCurrent" with integer values
-describing the range of progress.
-
-Messages of type "progress" will be followed by more "progress" messages or with
-a message of type "reply" or "error" that complete the request.
-
-"progress" messages may not be emitted after the "reply" or "error" message for
-the request that triggered the responses was delivered.
-
-
-Type "message"
-^^^^^^^^^^^^^^
-
-A message is triggered when the server processes a request and produces some
-form of output that should be displayed to the user. A Message has a "message"
-with the actual text to display as well as a "title" with a suggested dialog
-box title.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"cookie":"","message":"Something happened.","title":"Title Text","inReplyTo":"handshake","type":"message"}
-  ]== "CMake Server" ==]
-
-
-Type "signal"
-^^^^^^^^^^^^^
-
-The server can send signals when it detects changes in the system state. Signals
-are of type "signal", have an empty "cookie" and "inReplyTo" field and always
-have a "name" set to show which signal was sent.
-
-
-Specific Signals
-----------------
-
-The cmake server may sent signals with the following names:
-
-"dirty" Signal
-^^^^^^^^^^^^^^
-
-The "dirty" signal is sent whenever the server determines that the configuration
-of the project is no longer up-to-date. This happens when any of the files that have
-an influence on the build system is changed.
-
-The "dirty" signal may look like this::
-
-  [== "CMake Server" ==[
-  {
-    "cookie":"",
-    "inReplyTo":"",
-    "name":"dirty",
-    "type":"signal"}
-  ]== "CMake Server" ==]
-
-
-"fileChange" Signal
-^^^^^^^^^^^^^^^^^^^
-
-The "fileChange" signal is sent whenever a watched file is changed. It contains
-the "path" that has changed and a list of "properties" with the kind of change
-that was detected. Possible changes are "change" and "rename".
-
-The "fileChange" signal looks like this::
-
-  [== "CMake Server" ==[
-  {
-    "cookie":"",
-    "inReplyTo":"",
-    "name":"fileChange",
-    "path":"/absolute/CMakeLists.txt",
-    "properties":["change"],
-    "type":"signal"}
-  ]== "CMake Server" ==]
-
-
-Specific Message Types
-----------------------
-
-
-Type "hello"
-^^^^^^^^^^^^
-
-The initial message send by the cmake server on startup is of type "hello".
-This is the only message ever sent by the server that is not of type "reply",
-"progress" or "error".
-
-It will contain "supportedProtocolVersions" with an array of server protocol
-versions supported by the cmake server. These are JSON objects with "major" and
-"minor" keys containing non-negative integer values. Some versions may be marked
-as experimental. These will contain the "isExperimental" key set to true. Enabling
-these requires a special command line argument when starting the cmake server mode.
-
-Within a "major" version all "minor" versions are fully backwards compatible.
-New "minor" versions may introduce functionality in such a way that existing
-clients of the same "major" version will continue to work, provided they
-ignore keys in the output that they do not know about.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"supportedProtocolVersions":[{"major":0,"minor":1}],"type":"hello"}
-  ]== "CMake Server" ==]
-
-
-Type "handshake"
-^^^^^^^^^^^^^^^^
-
-The first request that the client may send to the server is of type "handshake".
-
-This request needs to pass one of the "supportedProtocolVersions" of the "hello"
-type response received earlier back to the server in the "protocolVersion" field.
-Giving the "major" version of the requested protocol version will make the server
-use the latest minor version of that protocol. Use this if you do not explicitly
-need to depend on a specific minor version.
-
-Protocol version 1.0 requires the following attributes to be set:
-
-  * "sourceDirectory" with a path to the sources
-  * "buildDirectory" with a path to the build directory
-  * "generator" with the generator name
-  * "extraGenerator" (optional!) with the extra generator to be used
-  * "platform" with the generator platform (if supported by the generator)
-  * "toolset" with the generator toolset (if supported by the generator)
-
-Protocol version 1.2 makes all but the build directory optional, provided
-there is a valid cache in the build directory that contains all the other
-information already.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"cookie":"zimtstern","type":"handshake","protocolVersion":{"major":0},
-   "sourceDirectory":"/home/code/cmake", "buildDirectory":"/tmp/testbuild",
-   "generator":"Ninja"}
-  ]== "CMake Server" ==]
-
-which will result in a response type "reply"::
-
-  [== "CMake Server" ==[
-  {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"}
-  ]== "CMake Server" ==]
-
-indicating that the server is ready for action.
-
-
-Type "globalSettings"
-^^^^^^^^^^^^^^^^^^^^^
-
-This request can be sent after the initial handshake. It will return a
-JSON structure with information on cmake state.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"globalSettings"}
-  ]== "CMake Server" ==]
-
-which will result in a response type "reply"::
-
-  [== "CMake Server" ==[
-  {
-    "buildDirectory": "/tmp/test-build",
-    "capabilities": {
-      "generators": [
-        {
-          "extraGenerators": [],
-          "name": "Watcom WMake",
-          "platformSupport": false,
-          "toolsetSupport": false
-        },
-        <...>
-      ],
-      "serverMode": false,
-      "version": {
-        "isDirty": false,
-        "major": 3,
-        "minor": 6,
-        "patch": 20160830,
-        "string": "3.6.20160830-gd6abad",
-        "suffix": "gd6abad"
-      }
-    },
-    "checkSystemVars": false,
-    "cookie": "",
-    "extraGenerator": "",
-    "generator": "Ninja",
-    "debugOutput": false,
-    "inReplyTo": "globalSettings",
-    "sourceDirectory": "/home/code/cmake",
-    "trace": false,
-    "traceExpand": false,
-    "type": "reply",
-    "warnUninitialized": false,
-    "warnUnused": false,
-    "warnUnusedCli": true
-  }
-  ]== "CMake Server" ==]
-
-
-Type "setGlobalSettings"
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-This request can be sent to change the global settings attributes. Unknown
-attributes are going to be ignored. Read-only attributes reported by
-"globalSettings" are all capabilities, buildDirectory, generator,
-extraGenerator and sourceDirectory. Any attempt to set these will be ignored,
-too.
-
-All other settings will be changed.
-
-The server will respond with an empty reply message or an error.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"setGlobalSettings","debugOutput":true}
-  ]== "CMake Server" ==]
-
-CMake will reply to this with::
-
-  [== "CMake Server" ==[
-  {"inReplyTo":"setGlobalSettings","type":"reply"}
-  ]== "CMake Server" ==]
-
-
-Type "configure"
-^^^^^^^^^^^^^^^^
-
-This request will configure a project for build.
-
-To configure a build directory already containing cmake files, it is enough to
-set "buildDirectory" via "setGlobalSettings". To create a fresh build directory
-you also need to set "currentGenerator" and "sourceDirectory" via "setGlobalSettings"
-in addition to "buildDirectory".
-
-You may a list of strings to "configure" via the "cacheArguments" key. These
-strings will be interpreted similar to command line arguments related to
-cache handling that are passed to the cmake command line client.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"configure", "cacheArguments":["-Dsomething=else"]}
-  ]== "CMake Server" ==]
-
-CMake will reply like this (after reporting progress for some time)::
-
-  [== "CMake Server" ==[
-  {"cookie":"","inReplyTo":"configure","type":"reply"}
-  ]== "CMake Server" ==]
-
-
-Type "compute"
-^^^^^^^^^^^^^^
-
-This request will generate build system files in the build directory and
-is only available after a project was successfully "configure"d.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"compute"}
-  ]== "CMake Server" ==]
-
-CMake will reply (after reporting progress information)::
-
-  [== "CMake Server" ==[
-  {"cookie":"","inReplyTo":"compute","type":"reply"}
-  ]== "CMake Server" ==]
-
-
-Type "codemodel"
-^^^^^^^^^^^^^^^^
-
-The "codemodel" request can be used after a project was "compute"d successfully.
-
-It will list the complete project structure as it is known to cmake.
-
-The reply will contain a key "configurations", which will contain a list of
-configuration objects. Configuration objects are used to destinquish between
-different configurations the build directory might have enabled. While most
-generators only support one configuration, others might support several.
-
-Each configuration object can have the following keys:
-
-"name"
-  contains the name of the configuration. The name may be empty.
-"projects"
-  contains a list of project objects, one for each build project.
-
-Project objects define one (sub-)project defined in the cmake build system.
-
-Each project object can have the following keys:
-
-"name"
-  contains the (sub-)projects name.
-"minimumCMakeVersion"
-  contains the minimum cmake version allowed for this project, null if the
-  project doesn't specify one.
-"hasInstallRule"
-  true if the project contains any install rules, false otherwise.
-"sourceDirectory"
-  contains the current source directory
-"buildDirectory"
-  contains the current build directory.
-"targets"
-  contains a list of build system target objects.
-
-Target objects define individual build targets for a certain configuration.
-
-Each target object can have the following keys:
-
-"name"
-  contains the name of the target.
-"type"
-  defines the type of build of the target. Possible values are
-  "STATIC_LIBRARY", "MODULE_LIBRARY", "SHARED_LIBRARY", "OBJECT_LIBRARY",
-  "EXECUTABLE", "UTILITY" and "INTERFACE_LIBRARY".
-"fullName"
-  contains the full name of the build result (incl. extensions, etc.).
-"sourceDirectory"
-  contains the current source directory.
-"buildDirectory"
-  contains the current build directory.
-"isGeneratorProvided"
-  true if the target is auto-created by a generator, false otherwise
-"hasInstallRule"
-  true if the target contains any install rules, false otherwise.
-"installPaths"
-  full path to the destination directories defined by target install rules.
-"artifacts"
-  with a list of build artifacts. The list is sorted with the most
-  important artifacts first (e.g. a .DLL file is listed before a
-  .PDB file on windows).
-"linkerLanguage"
-  contains the language of the linker used to produce the artifact.
-"linkLibraries"
-  with a list of libraries to link to. This value is encoded in the
-  system's native shell format.
-"linkFlags"
-  with a list of flags to pass to the linker. This value is encoded in
-  the system's native shell format.
-"linkLanguageFlags"
-  with the flags for a compiler using the linkerLanguage. This value is
-  encoded in the system's native shell format.
-"frameworkPath"
-  with the framework path (on Apple computers). This value is encoded
-  in the system's native shell format.
-"linkPath"
-  with the link path. This value is encoded in the system's native shell
-  format.
-"sysroot"
-  with the sysroot path.
-"fileGroups"
-  contains the source files making up the target.
-
-FileGroups are used to group sources using similar settings together.
-
-Each fileGroup object may contain the following keys:
-
-"language"
-  contains the programming language used by all files in the group.
-"compileFlags"
-  with a string containing all the flags passed to the compiler
-  when building any of the files in this group. This value is encoded in
-  the system's native shell format.
-"includePath"
-  with a list of include paths. Each include path is an object
-  containing a "path" with the actual include path and "isSystem" with a bool
-  value informing whether this is a normal include or a system include. This
-  value is encoded in the system's native shell format.
-"defines"
-  with a list of defines in the form "SOMEVALUE" or "SOMEVALUE=42". This
-  value is encoded in the system's native shell format.
-"sources"
-  with a list of source files.
-
-All file paths in the fileGroup are either absolute or relative to the
-sourceDirectory of the target.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"codemodel"}
-  ]== "CMake Server" ==]
-
-CMake will reply::
-
-  [== "CMake Server" ==[
-  {
-    "configurations": [
-      {
-        "name": "",
-        "projects": [
-          {
-            "buildDirectory": "/tmp/build/Source/CursesDialog/form",
-            "name": "CMAKE_FORM",
-            "sourceDirectory": "/home/code/src/cmake/Source/CursesDialog/form",
-            "targets": [
-              {
-                "artifacts": [ "/tmp/build/Source/CursesDialog/form/libcmForm.a" ],
-                "buildDirectory": "/tmp/build/Source/CursesDialog/form",
-                "fileGroups": [
-                  {
-                    "compileFlags": "  -std=gnu11",
-                    "defines": [ "CURL_STATICLIB", "LIBARCHIVE_STATIC" ],
-                    "includePath": [ { "path": "/tmp/build/Utilities" }, <...> ],
-                    "isGenerated": false,
-                    "language": "C",
-                    "sources": [ "fld_arg.c", <...> ]
-                  }
-                ],
-                "fullName": "libcmForm.a",
-                "linkerLanguage": "C",
-                "name": "cmForm",
-                "sourceDirectory": "/home/code/src/cmake/Source/CursesDialog/form",
-                "type": "STATIC_LIBRARY"
-              }
-            ]
-          },
-          <...>
-        ]
-      }
-    ],
-    "cookie": "",
-    "inReplyTo": "codemodel",
-    "type": "reply"
-  }
-  ]== "CMake Server" ==]
-
-
-Type "ctestInfo"
-^^^^^^^^^^^^^^^^
-
-The "ctestInfo" request can be used after a project was "compute"d successfully.
-
-It will list the complete project test structure as it is known to cmake.
-
-The reply will contain a key "configurations", which will contain a list of
-configuration objects. Configuration objects are used to destinquish between
-different configurations the build directory might have enabled. While most
-generators only support one configuration, others might support several.
-
-Each configuration object can have the following keys:
-
-"name"
-  contains the name of the configuration. The name may be empty.
-"projects"
-  contains a list of project objects, one for each build project.
-
-Project objects define one (sub-)project defined in the cmake build system.
-
-Each project object can have the following keys:
-
-"name"
-  contains the (sub-)projects name.
-"ctestInfo"
-  contains a list of test objects.
-
-Each test object can have the following keys:
-
-"ctestName"
-  contains the name of the test.
-"ctestCommand"
-  contains the test command.
-"properties"
-  contains a list of test property objects.
-
-Each test property object can have the following keys:
-
-"key"
-  contains the test property key.
-"value"
-  contains the test property value.
-
-
-Type "cmakeInputs"
-^^^^^^^^^^^^^^^^^^
-
-The "cmakeInputs" requests will report files used by CMake as part
-of the build system itself.
-
-This request is only available after a project was successfully
-"configure"d.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"cmakeInputs"}
-  ]== "CMake Server" ==]
-
-CMake will reply with the following information::
-
-  [== "CMake Server" ==[
-  {"buildFiles":
-    [
-      {"isCMake":true,"isTemporary":false,"sources":["/usr/lib/cmake/...", ... ]},
-      {"isCMake":false,"isTemporary":false,"sources":["CMakeLists.txt", ...]},
-      {"isCMake":false,"isTemporary":true,"sources":["/tmp/build/CMakeFiles/...", ...]}
-    ],
-    "cmakeRootDirectory":"/usr/lib/cmake",
-    "sourceDirectory":"/home/code/src/cmake",
-    "cookie":"",
-    "inReplyTo":"cmakeInputs",
-    "type":"reply"
-  }
-  ]== "CMake Server" ==]
-
-All file names are either relative to the top level source directory or
-absolute.
-
-The list of files which "isCMake" set to true are part of the cmake installation.
-
-The list of files witch "isTemporary" set to true are part of the build directory
-and will not survive the build directory getting cleaned out.
-
-
-Type "cache"
-^^^^^^^^^^^^
-
-The "cache" request will list the cached configuration values.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"cache"}
-  ]== "CMake Server" ==]
-
-CMake will respond with the following output::
-
-  [== "CMake Server" ==[
-  {
-    "cookie":"","inReplyTo":"cache","type":"reply",
-    "cache":
-    [
-      {
-        "key":"SOMEVALUE",
-        "properties":
-        {
-          "ADVANCED":"1",
-          "HELPSTRING":"This is not helpful"
-        }
-        "type":"STRING",
-        "value":"TEST"}
-    ]
-  }
-  ]== "CMake Server" ==]
-
-The output can be limited to a list of keys by passing an array of key names
-to the "keys" optional field of the "cache" request.
-
-
-Type "fileSystemWatchers"
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The server can watch the filesystem for changes. The "fileSystemWatchers"
-command will report on the files and directories watched.
-
-Example::
-
-  [== "CMake Server" ==[
-  {"type":"fileSystemWatchers"}
-  ]== "CMake Server" ==]
-
-CMake will respond with the following output::
-
-  [== "CMake Server" ==[
-  {
-    "cookie":"","inReplyTo":"fileSystemWatchers","type":"reply",
-    "watchedFiles": [ "/absolute/path" ],
-    "watchedDirectories": [ "/absolute" ]
-  }
-  ]== "CMake Server" ==]
+The :manual:`cmake(1)` server mode has been removed since CMake 3.20.
+Clients should use the :manual:`cmake-file-api(7)` instead.
index 88cddf6..1ededee 100644 (file)
@@ -359,6 +359,10 @@ CMake uses the following steps to select one of the environments:
 * Else, an error diagnostic will be issued that neither the NDK or
   Standalone Toolchain can be found.
 
+.. versionadded:: 3.20
+  If an Android NDK is selected, its version number is reported
+  in the :variable:`CMAKE_ANDROID_NDK_VERSION` variable.
+
 .. _`Cross Compiling for Android with the NDK`:
 
 Cross Compiling for Android with the NDK
@@ -386,7 +390,8 @@ Configure use of an Android NDK with the following variables:
 
 :variable:`CMAKE_ANDROID_ARCH_ABI`
   Set to the Android ABI (architecture).  If not specified, this
-  variable will default to ``armeabi``.
+  variable will default to the first supported ABI in the list of
+  ``armeabi``, ``armeabi-v7a`` and ``arm64-v8a``.
   The :variable:`CMAKE_ANDROID_ARCH` variable will be computed
   from ``CMAKE_ANDROID_ARCH_ABI`` automatically.
   Also see the :variable:`CMAKE_ANDROID_ARM_MODE` and
@@ -394,7 +399,6 @@ Configure use of an Android NDK with the following variables:
 
 :variable:`CMAKE_ANDROID_NDK`
   Set to the absolute path to the Android NDK root directory.
-  A ``${CMAKE_ANDROID_NDK}/platforms`` directory must exist.
   If not specified, a default for this variable will be chosen
   as specified :ref:`above <Cross Compiling for Android>`.
 
index 56239ac..4317dd4 100644 (file)
@@ -278,6 +278,7 @@ Variables that Describe the System
    /variable/ANDROID
    /variable/APPLE
    /variable/BORLAND
+   /variable/CMAKE_ANDROID_NDK_VERSION
    /variable/CMAKE_CL_64
    /variable/CMAKE_COMPILER_2005
    /variable/CMAKE_HOST_APPLE
@@ -336,6 +337,7 @@ Variables that Control the Build
    /variable/CMAKE_ANDROID_ARM_MODE
    /variable/CMAKE_ANDROID_ARM_NEON
    /variable/CMAKE_ANDROID_ASSETS_DIRECTORIES
+   /variable/CMAKE_ANDROID_EXCEPTIONS
    /variable/CMAKE_ANDROID_GUI
    /variable/CMAKE_ANDROID_JAR_DEPENDENCIES
    /variable/CMAKE_ANDROID_JAR_DIRECTORIES
@@ -349,6 +351,7 @@ Variables that Control the Build
    /variable/CMAKE_ANDROID_PROCESS_MAX
    /variable/CMAKE_ANDROID_PROGUARD
    /variable/CMAKE_ANDROID_PROGUARD_CONFIG_PATH
+   /variable/CMAKE_ANDROID_RTTI
    /variable/CMAKE_ANDROID_SECURE_PROPS_PATH
    /variable/CMAKE_ANDROID_SKIP_ANT_STEP
    /variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN
@@ -386,6 +389,7 @@ Variables that Control the Build
    /variable/CMAKE_DEFAULT_BUILD_TYPE
    /variable/CMAKE_DEFAULT_CONFIGS
    /variable/CMAKE_DISABLE_PRECOMPILE_HEADERS
+   /variable/CMAKE_DEPENDS_USE_COMPILER
    /variable/CMAKE_ENABLE_EXPORTS
    /variable/CMAKE_EXE_LINKER_FLAGS
    /variable/CMAKE_EXE_LINKER_FLAGS_CONFIG
@@ -467,6 +471,7 @@ Variables that Control the Build
    /variable/CMAKE_TRY_COMPILE_TARGET_TYPE
    /variable/CMAKE_UNITY_BUILD
    /variable/CMAKE_UNITY_BUILD_BATCH_SIZE
+   /variable/CMAKE_UNITY_BUILD_UNIQUE_ID
    /variable/CMAKE_USE_RELATIVE_PATHS
    /variable/CMAKE_VISIBILITY_INLINES_HIDDEN
    /variable/CMAKE_VS_GLOBALS
@@ -523,6 +528,7 @@ Variables for Languages
    /variable/CMAKE_LANG_ARCHIVE_APPEND
    /variable/CMAKE_LANG_ARCHIVE_CREATE
    /variable/CMAKE_LANG_ARCHIVE_FINISH
+   /variable/CMAKE_LANG_BYTE_ORDER
    /variable/CMAKE_LANG_COMPILER
    /variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN
    /variable/CMAKE_LANG_COMPILER_ID
index 921f5c4..157ea5f 100644 (file)
@@ -377,12 +377,13 @@ Options
  about:tracing tab of Google Chrome or using a plugin for a tool like Trace
  Compass.
 
-``--preset=<preset>``
+``--preset <preset>``, ``--preset=<preset>``
  Reads a :manual:`preset <cmake-presets(7)>` from
  ``<path-to-source>/CMakePresets.json`` and
  ``<path-to-source>/CMakeUserPresets.json``. The preset specifies the
  generator and the build directory, and optionally a list of variables and
- other arguments to pass to CMake. The :manual:`CMake GUI <cmake-gui(1)>` can
+ other arguments to pass to CMake. The current working directory must contain
+ CMake preset files. The :manual:`CMake GUI <cmake-gui(1)>` can
  also recognize ``CMakePresets.json`` and ``CMakeUserPresets.json`` files. For
  full details on these files, see :manual:`cmake-presets(7)`.
 
@@ -392,6 +393,10 @@ Options
  a variable called ``MYVAR`` to ``1``, but the user sets it to ``2`` with a
  ``-D`` argument, the value ``2`` is preferred.
 
+``--list-presets, --list-presets=<[configure | build | test | all]>``
+ Lists the available presets. If no option is specified only configure presets
+ will be listed. The current working directory must contain CMake preset files.
+
 .. _`Build Tool Mode`:
 
 Build a Project
@@ -402,13 +407,24 @@ project binary tree:
 
 .. code-block:: shell
 
-  cmake --build <dir> [<options>] [-- <build-tool-options>]
+  cmake --build [<dir> | --preset <preset>] [<options>] [-- <build-tool-options>]
 
 This abstracts a native build tool's command-line interface with the
 following options:
 
 ``--build <dir>``
-  Project binary directory to be built.  This is required and must be first.
+  Project binary directory to be built.  This is required (unless a preset
+  is specified) and must be first.
+
+``--preset <preset>``, ``--preset=<preset>``
+  Use a build preset to specify build options. The project binary directory
+  is inferred from the ``configurePreset`` key. The current working directory
+  must contain CMake preset files.
+  See :manual:`preset <cmake-presets(7)>` for more details.
+
+``--list-presets``
+  Lists the available build presets. The current working directory must
+  contain CMake preset files.
 
 ``--parallel [<jobs>], -j [<jobs>]``
   The maximum number of concurrent processes to use when building.
@@ -580,6 +596,7 @@ Available commands are:
 
   ``serverMode``
     ``true`` if cmake supports server-mode and ``false`` otherwise.
+    Always false since CMake 3.20.
 
 ``cat <files>...``
   Concatenate files and print on the standard output.
index 00df24b..175359d 100644 (file)
@@ -25,9 +25,21 @@ CMake-generated build trees created for projects that use the
 :command:`enable_testing` and :command:`add_test` commands have testing support.
 This program will run the tests and report results.
 
+.. _`CTest Options`:
+
 Options
 =======
 
+``--preset <preset>``, ``--preset=<preset>``
+ Use a test preset to specify test options. The project binary directory
+ is inferred from the ``configurePreset`` key. The current working directory
+ must contain CMake preset files.
+ See :manual:`preset <cmake-presets(7)>` for more details.
+
+``--list-presets``
+ Lists the available test presets. The current working directory must contain
+ CMake preset files.
+
 ``-C <cfg>, --build-config <cfg>``
  Choose configuration to test.
 
@@ -324,6 +336,9 @@ Options
 ``--build-and-test``
 See `Build and Test Mode`_.
 
+``--test-dir <dir>``
+Specify the directory in which to look for tests.
+
 ``--test-output-size-passed <size>``
  Limit the output for passed tests to ``<size>`` bytes.
 
index d3b6f4a..dfc2910 100644 (file)
@@ -1,8 +1,8 @@
 {
-  "version": 1,
+  "version": 2,
   "cmakeMinimumRequired": {
     "major": 3,
-    "minor": 19,
+    "minor": 20,
     "patch": 0
   },
   "configurePresets": [
       "generator": "Ninja Multi-Config"
     }
   ],
+  "buildPresets": [
+    {
+      "name": "default",
+      "configurePreset": "default"
+    }
+  ],
+  "testPresets": [
+    {
+      "name": "default",
+      "configurePreset": "default",
+      "output": {"outputOnFailure": true},
+      "execution": {"noTestsAction": "error", "stopOnFailure": true}
+    }
+  ],
   "vendor": {
     "example.com/ExampleIDE/1.0": {
       "autoFormat": false
index 57b063e..f8faf3d 100644 (file)
@@ -2,13 +2,38 @@
   "$schema": "http://json-schema.org/draft-07/schema#",
   "type": "object",
   "description": "The presets specify the generator and the build directory, and optionally a list of variables and other arguments to pass to CMake.",
-  "properties": {
-    "version": {
-      "type": "integer",
-      "description": "A required integer representing the version of the JSON schema. Currently, the only supported version is 1.",
-      "minimum": 1,
-      "maximum": 1
+  "oneOf": [
+    {
+      "properties": {
+        "version": {
+          "const": 1,
+          "description": "A required integer representing the version of the JSON schema."
+        },
+        "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
+        "vendor": { "$ref": "#/definitions/vendor" },
+        "configurePresets": { "$ref": "#/definitions/configurePresets"}
+      },
+      "additionalProperties": false
     },
+    {
+      "properties": {
+        "version": {
+          "const": 2,
+          "description": "A required integer representing the version of the JSON schema."
+        },
+        "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
+        "vendor": { "$ref": "#/definitions/vendor" },
+        "configurePresets": { "$ref": "#/definitions/configurePresets"},
+        "buildPresets": { "$ref": "#/definitions/buildPresets"},
+        "testPresets": { "$ref": "#/definitions/testPresets"}
+      },
+      "additionalProperties": false
+    }
+  ],
+  "required": [
+    "version"
+  ],
+  "definitions": {
     "cmakeMinimumRequired": {
       "type": "object",
       "description": "An optional object representing the minimum version of CMake needed to build this project.",
@@ -47,7 +72,7 @@
           },
           "hidden": {
             "type": "boolean",
-            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset= argument, will not show up in the CMake GUI, and does not have to have a valid generator or binaryDir, even from inheritance. hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset= argument, will not show up in the CMake GUI, and does not have to have a valid generator or binaryDir, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
           },
           "inherits": {
             "anyOf": [
@@ -58,7 +83,7 @@
               },
               {
                 "type": "array",
-                "description": "An optional array of strings representing the names of presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and longDescription), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+                "description": "An optional array of strings representing the names of presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
                 "items": {
                   "type": "string",
                   "description": "An optional string representing the name of the preset to inherit from.",
         ],
         "additionalProperties": false
       }
+    },
+    "buildPresets": {
+      "type": "array",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, or test) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
+            "minLength": 1
+          },
+          "hidden": {
+            "type": "boolean",
+            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument, will not show up in the CMake GUI, and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+          },
+          "inherits": {
+            "anyOf": [
+              {
+                "type": "string",
+                "description": "An optional string representing the name of the build preset to inherit from.",
+                "minLength": 1
+              },
+              {
+                "type": "array",
+                "description": "An optional array of strings representing the names of build presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+                "items": {
+                  "type": "string",
+                  "description": "An optional string representing the name of the preset to inherit from.",
+                  "minLength": 1
+                }
+              }
+            ]
+          },
+          "configurePreset": {
+            "type": "string",
+            "description": "An optional string specifying the name of a configure preset to associate with this build preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
+            "minLength": 1
+          },
+          "vendor": {
+            "type": "object",
+            "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
+            "properties": {}
+          },
+          "displayName": {
+            "type": "string",
+            "description": "An optional string with a human-friendly name of the preset."
+          },
+          "description": {
+            "type": "string",
+            "description": "An optional string with a human-friendly description of the preset."
+          },
+          "inheritConfigureEnvironment": {
+            "type": "boolean",
+            "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited build preset environments, but before environment variables explicitly specified in this build preset."
+          },
+          "environment": {
+            "type": "object",
+            "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
+            "properties": {},
+            "additionalProperties": {
+              "anyOf": [
+                {
+                  "type": "null",
+                  "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+                },
+                {
+                  "type": "string",
+                  "description": "A string representing the value of the variable."
+                }
+              ]
+            },
+            "propertyNames": {
+              "pattern": "^.+$"
+            }
+          },
+          "jobs": {
+            "type": "integer",
+            "description": "An optional integer. Equivalent to passing --parallel or -j on the command line."
+          },
+          "targets": {
+            "anyOf": [
+              {
+                "type": "string",
+                "description": "An optional string. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets."
+              },
+              {
+                "type": "array",
+                "description": "An optional array of strings. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets.",
+                "items": {
+                  "type": "string",
+                  "description": "An optional string. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets."
+                }
+              }
+            ]
+          },
+          "configuration": {
+            "type": "string",
+            "description": "An optional string. Equivalent to passing --config on the command line."
+          },
+          "cleanFirst": {
+            "type": "boolean",
+            "description": "An optional boolean. If true, equivalent to passing --clean-first on the command line."
+          },
+          "verbose": {
+            "type": "boolean",
+            "description": "An optional boolean. If true, equivalent to passing --verbose on the command line."
+          },
+          "nativeToolOptions": {
+            "type": "array",
+            "description": "An optional array of strings. Equivalent to passing options after -- on the command line.",
+            "items": {
+              "type": "string",
+              "description": "An optional string representing an option to pass after -- on the command line."
+            }
+          }
+        },
+        "required": [
+          "name"
+        ],
+        "additionalProperties": false
+      }
+    },
+    "testPresets": {
+      "type": "array",
+      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, or test) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
+            "minLength": 1
+          },
+          "hidden": {
+            "type": "boolean",
+            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument, will not show up in the CMake GUI, and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+          },
+          "inherits": {
+            "anyOf": [
+              {
+                "type": "string",
+                "description": "An optional string representing the name of the test preset to inherit from.",
+                "minLength": 1
+              },
+              {
+                "type": "array",
+                "description": "An optional array of strings representing the names of test presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json may not inherit from presets in CMakeUserPresets.json.",
+                "items": {
+                  "type": "string",
+                  "description": "An optional string representing the name of the preset to inherit from.",
+                  "minLength": 1
+                }
+              }
+            ]
+          },
+          "configurePreset": {
+            "type": "string",
+            "description": "An optional string specifying the name of a configure preset to associate with this test preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
+            "minLength": 1
+          },
+          "vendor": {
+            "type": "object",
+            "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
+            "properties": {}
+          },
+          "displayName": {
+            "type": "string",
+            "description": "An optional string with a human-friendly name of the preset."
+          },
+          "description": {
+            "type": "string",
+            "description": "An optional string with a human-friendly description of the preset."
+          },
+          "inheritConfigureEnvironment": {
+            "type": "boolean",
+            "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited test preset environments, but before environment variables explicitly specified in this test preset."
+          },
+          "environment": {
+            "type": "object",
+            "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
+            "properties": {},
+            "additionalProperties": {
+              "anyOf": [
+                {
+                  "type": "null",
+                  "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+                },
+                {
+                  "type": "string",
+                  "description": "A string representing the value of the variable."
+                }
+              ]
+            },
+            "propertyNames": {
+              "pattern": "^.+$"
+            }
+          },
+          "configuration": {
+            "type": "string",
+            "description": "An optional string. Equivalent to passing --build-config on the command line."
+          },
+          "overwriteConfigurationFile": {
+            "type": "array",
+            "description": "An optional array of configuration options to overwrite options specified in the CTest configuration file. Equivalent to passing ``--overwrite`` for each value in the array.",
+            "items": {
+              "type": "string",
+              "description": "An option written as a key-value pair in the form \"key=value\"."
+            }
+          },
+          "output": {
+            "type": "object",
+            "description": "An optional object specifying output options.",
+            "properties": {
+              "shortProgress": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing --progress on the command line."
+              },
+              "verbosity": {
+                "type": "string",
+                "description": "An optional string specifying verbosity level. Valid values are \"default\" (equivalent to passing no verbosity flags on the command line), \"verbose\" (equivalent to passing --verbose on the command line), and \"extra\" (equivalent to passing --extra-verbose on the command line).",
+                "enum": [
+                  "default", "verbose", "extra"
+                ]
+              },
+              "debug": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing --debug on the command line."
+              },
+              "outputOnFailure": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing --output-on-failure on the command line."
+              },
+              "quiet": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing --quiet on the command line."
+              },
+              "outputLogFile": {
+                "type": "string",
+                "description": "An optional string specifying a path to a log file. Equivalent to passing --output-log on the command line."
+              },
+              "labelSummary": {
+                "type": "boolean",
+                "description": "An optional boolean. If false, equivalent to passing --no-label-summary on the command line."
+              },
+              "subprojectSummary": {
+                "type": "boolean",
+                "description": "An optional boolean. If false, equivalent to passing --no-subproject-summary on the command line."
+              },
+              "maxPassedTestOutputSize": {
+                "type": "integer",
+                "description": "An optional integer specifying the maximum output for passed tests in bytes. Equivalent to passing --test-output-size-passed on the command line."
+              },
+              "maxFailedTestOutputSize": {
+                "type": "integer",
+                "description": "An optional integer specifying the maximum output for failed tests in bytes. Equivalent to passing --test-output-size-failed on the command line."
+              },
+              "maxTestNameWidth": {
+                "type": "integer",
+                "description": "An optional integer specifying the maximum width of a test name to output. Equivalent to passing --max-width on the command line."
+              }
+            },
+            "additionalProperties": false
+          },
+          "filter": {
+            "type": "object",
+            "description": "An optional object specifying how to filter the tests to run.",
+            "properties": {
+              "include": {
+                "type": "object",
+                "description": "An optional object specifying which tests to include.",
+                "properties": {
+                  "name": {
+                    "type": "string",
+                    "description": "An optional string specifying a regex for test names. Equivalent to passing --tests-regex on the command line."
+                  },
+                  "label": {
+                    "type": "string",
+                    "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-regex on the command line."
+                  },
+                  "index": {
+                    "anyOf": [
+                      {
+                        "type": "object",
+                        "description": "An optional object specifying tests to include by test index.",
+                        "properties": {
+                          "start": {
+                            "type": "integer",
+                            "description": "An optional integer specifying a test index to start testing at."
+                          },
+                          "end": {
+                            "type": "integer",
+                            "description": "An optional integer specifying a test index to stop testing at."
+                          },
+                          "stride": {
+                            "type": "integer",
+                            "description": "An optional integer specifying the increment."
+                          },
+                          "specificTests": {
+                            "type": "array",
+                            "description": "An optional array of integers specifying specific test indices to run.",
+                            "items": {
+                              "type": "integer",
+                              "description": "An integer specifying the test to run by index."
+                            }
+                          }
+                        },
+                        "additionalProperties": false
+                      },
+                      {
+                        "type": "string",
+                        "description": "An optional string specifying a file with the command line syntax for --tests-information."
+                      }
+                    ]
+                  },
+                  "useUnion": {
+                    "type": "boolean",
+                    "description": "An optional boolean. Equivalent to passing --union on the command line."
+                  }
+                },
+                "additionalProperties": false
+              },
+              "exclude": {
+                "type": "object",
+                "description": "An optional object specifying which tests to exclude.",
+                "properties": {
+                  "name": {
+                    "type": "string",
+                    "description": "An optional string specifying a regex for test names. Equivalent to passing --exclude-regex on the command line."
+                  },
+                  "label": {
+                    "type": "string",
+                    "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-exclude on the command line."
+                  },
+                  "fixtures": {
+                    "type": "object",
+                    "description": "An optional object specifying which fixtures to exclude from adding tests.",
+                    "properties": {
+                      "any": {
+                        "type": "string",
+                        "description": "An optional string specifying a regex for text fixtures to exclude from adding any tests. Equivalent to --fixture-exclude-any on the command line."
+                      },
+                      "setup": {
+                        "type": "string",
+                        "description": "An optional string specifying a regex for text fixtures to exclude from adding setup tests. Equivalent to --fixture-exclude-setup on the command line."
+                      },
+                      "cleanup": {
+                        "type": "string",
+                        "description": "An optional string specifying a regex for text fixtures to exclude from adding cleanup tests. Equivalent to --fixture-exclude-cleanup on the command line."
+                      }
+                    },
+                    "additionalProperties": false
+                  }
+                }
+              }
+            },
+            "additionalProperties": false
+          },
+          "execution": {
+            "type": "object",
+            "description": "An optional object specifying options for test execution.",
+            "properties": {
+              "stopOnFailure": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing --stop-on-failure on the command line."
+              },
+              "enableFailover": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing -F on the command line."
+              },
+              "jobs": {
+                "type": "integer",
+                "description": "An optional integer. Equivalent to passing --parallel on the command line."
+              },
+              "resourceSpecFile": {
+                "type": "string",
+                "description": "An optional string. Equivalent to passing --resource-spec-file on the command line."
+              },
+              "testLoad": {
+                "type": "integer",
+                "description": "An optional integer. Equivalent to passing --test-load on the command line."
+              },
+              "showOnly": {
+                "type": "string",
+                "description": "An optional string. Equivalent to passing --show-only on the command line. Value must be \"human\" or \"json-v1\".",
+                "enum": [
+                  "human", "json-v1"
+                ]
+              },
+              "repeat": {
+                "type": "object",
+                "description": "An optional object specifying how to repeat tests. Equivalent to passing --repeat on the command line.",
+                "properties": {
+                  "mode": {
+                    "type": "string",
+                    "description": "A required string. Must be one of the following values: \"until-fail\", \"until-pass\", or \"after-timeout\".",
+                    "enum": [
+                      "until-fail", "until-pass", "after-timeout"
+                    ]
+                  },
+                  "count": {
+                    "type": "integer",
+                    "description": "A required integer."
+                  }
+                },
+                "required": [
+                  "mode", "count"
+                ],
+                "additionalProperties": false
+              },
+              "interactiveDebugging": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing --interactive-debug-mode 1 on the command line. If false, equivalent to passing --interactive-debug-mode 0 on the command line."
+              },
+              "scheduleRandom": {
+                "type": "boolean",
+                "description": "An optional boolean. If true, equivalent to passing --schedule-random on the command line."
+              },
+              "timeout": {
+                "type": "integer",
+                "description": "An optional integer. Equivalent to passing --timeout on the command line."
+              },
+              "noTestsAction": {
+                "type": "string",
+                "description": "An optional string specifying the behavior if no tests are found. Must be one of the following values: \"default\" (equivalent to not passing any value on the command line), \"error\" (equivalent to passing --no-tests=error on the command line), or \"ignore\" (equivalent to passing --no-tests-ignore on the command line).",
+                "enum": [
+                  "default", "error", "ignore"
+                ]
+              }
+            },
+            "additionalProperties": false
+          }
+        },
+        "required": [
+          "name"
+        ],
+        "additionalProperties": false
+      }
     }
-  },
-  "required": [
-    "version"
-  ],
-  "additionalProperties": false
+  }
 }
index b9cd476..29949be 100644 (file)
@@ -1 +1,6 @@
-.. cmake-module:: ../../Modules/UseJavaClassFilelist.cmake
+UseJavaClassFilelist
+--------------------
+
+.. versionchanged:: 3.20
+  This module was previously documented by mistake and was never meant for
+  direct inclusion by project code.  See the :module:`UseJava` module.
index 2fab8e8..1058a68 100644 (file)
@@ -1 +1,6 @@
-.. cmake-module:: ../../Modules/UseJavaSymlinks.cmake
+UseJavaSymlinks
+---------------
+
+.. versionchanged:: 3.20
+  This module was previously documented by mistake and was never meant for
+  direct inclusion by project code.  See the :module:`UseJava` module.
index 3401d4a..e08fd54 100644 (file)
@@ -9,12 +9,12 @@ determine the eventual location of build targets.  This relies on the
 assumption that all necessary information is available at
 configure-time to determine the final location and filename of the
 target.  However, this property is not fully determined until later at
-generate-time.  At generate time, the ``$<TARGET_FILE>`` generator
+generate-time.  At generate time, the :genex:`$<TARGET_FILE>` generator
 expression can be used to determine the eventual :prop_tgt:`LOCATION` of a target
 output.
 
 Code which reads the :prop_tgt:`LOCATION` target property can be ported to
-use the ``$<TARGET_FILE>`` generator expression together with the
+use the :genex:`$<TARGET_FILE>` generator expression together with the
 :command:`file(GENERATE)` subcommand to generate a file containing
 the target location.
 
index 053bc97..3558909 100644 (file)
@@ -3,7 +3,7 @@ CMP0051
 
 .. versionadded:: 3.1
 
-List TARGET_OBJECTS in SOURCES target property.
+List :genex:`TARGET_OBJECTS` in SOURCES target property.
 
 CMake 3.0 and lower did not include the ``TARGET_OBJECTS``
 :manual:`generator expression <cmake-generator-expressions(7)>` when
diff --git a/Help/policy/CMP0115.rst b/Help/policy/CMP0115.rst
new file mode 100644 (file)
index 0000000..7f82c43
--- /dev/null
@@ -0,0 +1,34 @@
+CMP0115
+-------
+
+.. versionadded:: 3.20
+
+Source file extensions must be explicit.
+
+In CMake 3.19 and below, if a source file could not be found by the name
+specified, it would append a list of known extensions to the name to see if
+the file with the extension could be found. For example, this would allow the
+user to run:
+
+.. code-block:: cmake
+
+  add_executable(exe main)
+
+and put ``main.c`` in the executable without specifying the extension.
+
+Starting in CMake 3.20, CMake prefers all source files to have their extensions
+explicitly listed:
+
+.. code-block:: cmake
+
+  add_executable(exe main.c)
+
+The ``OLD`` behavior for this policy is to implicitly append known extensions
+to source files if they can't be found. The ``NEW`` behavior of this policy is
+to not append known extensions and require them to be explicit.
+
+This policy was introduced in CMake version 3.20.  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/CMP0116.rst b/Help/policy/CMP0116.rst
new file mode 100644 (file)
index 0000000..18e5a96
--- /dev/null
@@ -0,0 +1,41 @@
+CMP0116
+-------
+
+.. versionadded:: 3.20
+
+Ninja generators transform ``DEPFILE`` s from :command:`add_custom_command`.
+
+In CMake 3.19 and below, files given to the ``DEPFILE`` argument of
+:command:`add_custom_command` were passed directly to Ninja's ``depfile``
+variable without any path resolution. This meant that if
+:command:`add_custom_command` was called from a subdirectory (created by
+:command:`add_subdirectory`), the ``DEPFILE`` argument would have to be either
+an absolute path or a path relative to :variable:`CMAKE_BINARY_DIR`, rather
+than :variable:`CMAKE_CURRENT_BINARY_DIR`. In addition, no transformation was
+done on the file listed in ``DEPFILE``, which meant that the paths within the
+``DEPFILE`` had the same restrictions.
+
+Starting with CMake 3.20, the ``DEPFILE`` argument is relative to
+:variable:`CMAKE_CURRENT_BINARY_DIR` (unless it is absolute), and the paths in
+the ``DEPFILE`` are also relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
+CMake automatically transforms the paths in the ``DEPFILE`` (unless they are
+absolute) after the custom command is run. The file listed in ``DEPFILE`` is
+not modified in any way. Instead, CMake writes the transformation to its own
+internal file, and passes this internal file to Ninja's ``depfile`` variable.
+This transformation happens regardless of whether or not ``DEPFILE`` is
+relative, and regardless of whether or not :command:`add_custom_command` is
+called from a subdirectory.
+
+The ``OLD`` behavior for this policy is to pass the ``DEPFILE`` to Ninja
+unaltered. The ``NEW`` behavior for this policy is to transform the ``DEPFILE``
+after running the custom command. The status of ``CMP0116`` is recorded at the
+time of the custom command's creation, and you can have custom commands in the
+same directory with different values for ``CMP0116`` by setting the policy
+before each custom command.
+
+This policy was introduced in CMake version 3.20.  Unlike most policies,
+CMake version |release| does *not* warn by default when this policy is not set
+(unless ``DEPFILE`` is used in a subdirectory) and simply uses ``OLD``
+behavior.  See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0116 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
diff --git a/Help/policy/CMP0117.rst b/Help/policy/CMP0117.rst
new file mode 100644 (file)
index 0000000..0c4dd30
--- /dev/null
@@ -0,0 +1,43 @@
+CMP0117
+-------
+
+.. versionadded:: 3.20
+
+MSVC RTTI flag ``/GR`` is not added to
+:variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` by default.
+
+When using MSVC-like compilers in CMake 3.19 and below, the RTTI flag
+``/GR`` is added to :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` by
+default.  This behavior is left from support for MSVC versions from Visual
+Studio 2003 and below that did not enable RTTI by default.  It is no longer
+necessary.  Furthermore, it is problematic for projects that want to change
+to ``/GR-`` programmatically.  In particular, it requires string editing of
+the :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` variable with knowledge
+of the CMake builtin default so it can be replaced.
+
+CMake 3.20 and above prefer to leave out ``/GR`` from the value of
+:variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` by default.
+
+This policy provides compatibility with projects that have not been updated
+to expect the lack of the ``/GR`` flag.  The policy setting takes effect as
+of the first :command:`project` or :command:`enable_language` command that
+initializes :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>`.
+
+.. note::
+
+  Once the policy has taken effect at the top of a project for a given
+  language, that choice must be used throughout the tree for that language.
+  In projects that have nested projects in subdirectories, be sure to
+  convert everything together.
+
+The ``OLD`` behavior for this policy is to place the MSVC ``/GR`` flag in the
+default :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` cache entry.  The
+``NEW`` behavior for this policy is to *not* place the MSVC ``/GR`` flag in
+the default cache entry.
+
+This policy was introduced in CMake version 3.20.  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/policy/CMP0118.rst b/Help/policy/CMP0118.rst
new file mode 100644 (file)
index 0000000..aa7e0f7
--- /dev/null
@@ -0,0 +1,25 @@
+CMP0118
+-------
+
+.. versionadded:: 3.20
+
+The :prop_sf:`GENERATED` source file property is now visible in all directories.
+
+Whether or not a source file is generated is an all-or-nothing global
+property of the source.  Consequently, the associated ``GENERATED``
+property is now visible from any directory scope, not only from the scope
+for which it was set.
+
+Additionally, the ``GENERATED`` property may now be set only to boolean
+values, and may not be turned off once turned on.
+
+The ``OLD`` behavior of this policy is to only allow ``GENERATED`` to be
+visible from the directory scope for which it was set.  The ``NEW``
+behavior on the other hand allows it to be visible from any scope.
+
+This policy was introduced in CMake version 3.20.  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 with regard
+to visibility of the ``GENERATED`` property.  However, CMake does warn
+about setting the ``GENERATED`` property to a non-boolean value.
diff --git a/Help/policy/CMP0119.rst b/Help/policy/CMP0119.rst
new file mode 100644 (file)
index 0000000..61c8bdc
--- /dev/null
@@ -0,0 +1,36 @@
+CMP0119
+-------
+
+.. versionadded:: 3.20
+
+:prop_sf:`LANGUAGE` source file property explicitly compiles as specified
+language.
+
+The :prop_sf:`LANGUAGE` source file property is documented to mean that the
+source file is written in the specified language.  In CMake 3.19 and below,
+setting this property causes CMake to compile the source file using the
+compiler for the specified language.  However, it only passes an explicit
+flag to tell the compiler to treat the source as the specified language
+for MSVC-like, XL, and Embarcadero compilers for the ``CXX`` language.
+CMake 3.20 and above prefer to also explicitly tell the compiler to use
+the specified language using a flag such as ``-x c`` on all compilers
+for which such flags are known.
+
+This policy provides compatibility for projects that have not been updated
+to expect this behavior.  For example, some projects were setting the
+``LANGUAGE`` property to ``C`` on assembly-language ``.S`` source files
+in order to compile them using the C compiler.  Such projects should be
+updated to use ``enable_language(ASM)``, for which CMake will often choose
+the C compiler as the assembler on relevant platforms anyway.
+
+The ``OLD`` behavior for this policy is to interpret the ``LANGUAGE <LANG>``
+property using its undocumented meaning to "use the ``<LANG>`` compiler".
+The ``NEW`` behavior for this policy is to interpret the ``LANGUAGE <LANG>``
+property using its documented meaning to "compile as a ``<LANG>`` source".
+
+This policy was introduced in CMake version 3.20.  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/policy/CMP0120.rst b/Help/policy/CMP0120.rst
new file mode 100644 (file)
index 0000000..9d2f6c9
--- /dev/null
@@ -0,0 +1,47 @@
+CMP0120
+-------
+
+.. versionadded:: 3.20
+
+The :module:`WriteCompilerDetectionHeader` module is removed.
+
+CMake versions 3.1 through 3.19 provide this module to generate a
+C++ compatibility layer by re-using information from CMake's table of
+preprocessor checks for :manual:`cmake-compile-features(7)`.  However:
+
+* Those granular features have been superseded by meta-features for
+  :ref:`Requiring Language Standards` such as ``cxx_std_11``.  Therefore
+  no new granular feature checks will be added and projects will need to
+  use other means to conditionally use new C++ features.
+
+* The module exposes some of CMake's implementation details directly
+  to C++ translation units.
+
+* The module's approach effectively provides a header file with CMake,
+  thus tying the version of the header to the version of CMake.
+  Many projects found that the :module:`WriteCompilerDetectionHeader` was
+  best used by manually generating its header locally with a recent version
+  of CMake and then bundling it with the project source so that it could
+  be used with older CMake versions.
+
+For reasons including the above, CMake 3.20 and above prefer to not
+provide the :module:`WriteCompilerDetectionHeader` module.  This policy
+provides compatibility for projects that have not been ported away from
+it.  Projects using the module should be updated to stop using it.
+Alternatives include:
+
+* Bundle a copy of the generated header in the project's source.
+* Use a third-party alternative, such as the CC0-licensed `Hedley`_.
+* Drop support for compilers too old to provide the features natively.
+
+The ``OLD`` behavior of this policy is for inclusion of the deprecated
+:module:`WriteCompilerDetectionHeader` module to work.  The ``NEW``
+behavior is for inclusion of the module to fail as if it does not exist.
+
+This policy was introduced in CMake version 3.20.  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
+
+.. _`Hedley`: https://nemequ.github.io/hedley/
index e8e3148..6bbb870 100644 (file)
@@ -30,3 +30,6 @@ The features known to this version of CMake are:
 
 ``cuda_std_20``
   Compiler mode is at least CUDA/C++ 20.
+
+``cuda_std_23``
+  Compiler mode is at least CUDA/C++ 23.
index bac3274..73c0b34 100644 (file)
@@ -37,6 +37,8 @@ but it does not necessarily imply complete conformance to that standard.
 ``cxx_std_20``
   Compiler mode is at least C++ 20.
 
+``cxx_std_23``
+  Compiler mode is at least C++ 23.
 
 Low level individual compile features
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 48ff70c..6ef4580 100644 (file)
@@ -3,6 +3,9 @@ GENERATED
 
 Is this source file generated as part of the build or CMake process.
 
+.. versionchanged:: 3.20
+  The GENERATED source file property is now visible in all directories.
+
 Tells the internal CMake engine that a source file is generated by an outside
 process such as another build step, or the execution of CMake itself.
 This information is then used to exempt the file from any existence or
@@ -34,3 +37,11 @@ or :prop_tgt:`AUTORCC` functionality, the :prop_gbl:`AUTOGEN_SOURCE_GROUP`,
 :prop_gbl:`AUTOMOC_SOURCE_GROUP` and :prop_gbl:`AUTORCC_SOURCE_GROUP` target
 properties may influence where the generated sources are grouped in the project's
 file lists.
+
+.. note::
+
+  Starting with CMake 3.20 the ``GENERATED`` source file property can be set
+  and retrieved from any directory scope. It is an all-or-nothing property.
+  It also can no longer be removed or unset if it was set to ``TRUE``. Policy
+  :policy:`CMP0118` was introduced to allow supporting the ``OLD`` behavior
+  for some time.
index 1dd2554..f14c176 100644 (file)
@@ -1,7 +1,7 @@
 LANGUAGE
 --------
 
-What programming language is the file.
+Specify the programming language in which a source file is written.
 
 A property that can be set to indicate what programming language the
 source file is.  If it is not set the language is determined based on
@@ -9,3 +9,9 @@ the file extension.  Typical values are ``CXX`` (i.e.  C++), ``C``,
 ``CSharp``, ``CUDA``, ``Fortran``, ``ISPC``, and ``ASM``.  Setting this
 property for a file means this file will be compiled.  Do not set this
 for headers or files that should not be compiled.
+
+.. versionchanged:: 3.20
+  Setting this property causes the source file to be compiled as the
+  specified language, using explicit flags if possible.  Previously it
+  only caused the specified language's compiler to be used.
+  See policy :policy:`CMP0119`.
index 4221069..677e06d 100644 (file)
@@ -3,7 +3,7 @@ ARCHIVE_OUTPUT_DIRECTORY
 
 .. |XXX| replace:: :ref:`ARCHIVE <Archive Output Artifacts>`
 .. |xxx| replace:: archive
-.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: CMAKE_ARCHIVE_OUTPUT_DIRECTORY
+.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: :variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY`
 .. include:: XXX_OUTPUT_DIRECTORY.txt
 
 See also the :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` target property.
index c18859b..52d96e0 100644 (file)
@@ -137,7 +137,8 @@ parent directory path of the ``moc`` input file.  This scheme allows to have
 All not included ``moc`` output files will be included automatically by the
 CMake generated file
 
-- ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp``,
+- ``<AUTOGEN_BUILD_DIR>/mocs_compilation.cpp``, or
+- ``<AUTOGEN_BUILD_DIR>/mocs_compilation_$<CONFIG>.cpp``,
 
 which is added to the target's sources.
 
index fcc4725..6517035 100644 (file)
@@ -9,7 +9,7 @@ This property specifies the CUDA/C++ standard whose features are requested
 to build this target.  For some compilers, this results in adding a
 flag such as ``-std=gnu++11`` to the compile line.
 
-Supported values are ``98``, ``03``, ``11``, ``14``, ``17``, ``20``.
+Supported values are ``98``, ``03``, ``11``, ``14``, ``17``, ``20``, ``23``.
 
 If the value requested does not result in a compile flag being added for
 the compiler in use, a previous standard flag will be added instead.  This
index f322ffe..be0dab5 100644 (file)
@@ -11,7 +11,7 @@ flag such as ``-std=gnu++11`` to the compile line.  For compilers that
 have no notion of a standard level, such as Microsoft Visual C++ before
 2015 Update 3, this has no effect.
 
-Supported values are ``98``, ``11``, ``14``, ``17``, and ``20``.
+Supported values are ``98``, ``11``, ``14``, ``17``, ``20``, ``23``.
 
 If the value requested does not result in a compile flag being added for
 the compiler in use, a previous standard flag will be added instead.  This
diff --git a/Help/prop_tgt/EXPORT_COMPILE_COMMANDS.rst b/Help/prop_tgt/EXPORT_COMPILE_COMMANDS.rst
new file mode 100644 (file)
index 0000000..0b1145c
--- /dev/null
@@ -0,0 +1,9 @@
+EXPORT_COMPILE_COMMANDS
+-----------------------
+
+.. versionadded:: 3.20
+
+Enable/Disable output of compile commands during generation for a target.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_EXPORT_COMPILE_COMMANDS` if it is set when a target is created.
index bbbcd86..f3577eb 100644 (file)
@@ -3,11 +3,91 @@ IMPORTED_OBJECTS
 
 .. versionadded:: 3.9
 
-A :ref:`semicolon-separated list <CMake Language Lists>` of absolute paths to the object
-files on disk for an :ref:`imported <Imported targets>`
+A :ref:`semicolon-separated list <CMake Language Lists>` of absolute paths
+to the object files on disk for an :ref:`imported <Imported targets>`
 :ref:`object library <object libraries>`.
 
 Ignored for non-imported targets.
 
 Projects may skip ``IMPORTED_OBJECTS`` if the configuration-specific
-property :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` is set instead.
+property :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` is set instead, except in
+situations as noted in the section below.
+
+
+Xcode Generator Considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.20
+
+For Apple platforms, a project may be built for more than one architecture.
+This is controlled by the :variable:`CMAKE_OSX_ARCHITECTURES` variable.
+For all but the :generator:`Xcode` generator, CMake invokes compilers once
+per source file and passes multiple ``-arch`` flags, leading to a single
+object file which will be a universal binary.  Such object files work well
+when listed in the ``IMPORTED_OBJECTS`` of a separate CMake build, even for
+the :generator:`Xcode` generator.  But producing such object files with the
+:generator:`Xcode` generator is more difficult, since it invokes the compiler
+once per architecture for each source file.  Unlike the other generators,
+it does not generate universal object file binaries.
+
+A further complication with the :generator:`Xcode` generator is that when
+targeting device platforms (iOS, tvOS or watchOS), the :generator:`Xcode`
+generator has the ability to use either the device or simulator SDK without
+needing CMake to be re-run.  The SDK can be selected at build time.
+But since some architectures can be supported by both the device and the
+simulator SDKs (e.g. ``arm64`` with Xcode 12 or later), not all combinations
+can be represented in a single universal binary.  The only solution in this
+case is to have multiple object files.
+
+``IMPORTED_OBJECTS`` doesn't support generator expressions, so every file
+it lists needs to be valid for every architecture and SDK.  If incorporating
+object files that are not universal binaries, the path and/or file name of
+each object file has to somehow encapsulate the different architectures and
+SDKs.  With the :generator:`Xcode` generator, Xcode variables of the form
+``$(...)`` can be used to represent these aspects and Xcode will substitute
+the appropriate values at build time.  CMake doesn't interpret these
+variables and embeds them unchanged in the Xcode project file.
+``$(CURRENT_ARCH)`` can be used to represent the architecture, while
+``$(EFFECTIVE_PLATFORM_NAME)`` can be used to differentiate between SDKs.
+
+The following shows one example of how these two variables can be used to
+refer to an object file whose location depends on both the SDK and the
+architecture:
+
+.. code-block:: cmake
+
+  add_library(someObjs OBJECT IMPORTED)
+
+  set_property(TARGET someObjs PROPERTY IMPORTED_OBJECTS
+    # Quotes are required because of the ()
+    "/path/to/somewhere/objects$(EFFECTIVE_PLATFORM_NAME)/$(CURRENT_ARCH)/func.o"
+  )
+
+  # Example paths:
+  #   /path/to/somewhere/objects-iphoneos/arm64/func.o
+  #   /path/to/somewhere/objects-iphonesimulator/x86_64/func.o
+
+In some cases, you may want to have configuration-specific object files
+as well.  The :variable:`CMAKE_CFG_INTDIR` variable can be a convenient
+way of capturing this in combination with the SDK:
+
+.. code-block:: cmake
+
+  add_library(someObjs OBJECT IMPORTED)
+  set_property(TARGET someObjs PROPERTY IMPORTED_OBJECTS
+    "/path/to/somewhere/${CMAKE_CFG_INTDIR}/$(CURRENT_ARCH)/func.o"
+  )
+
+  # Example paths:
+  #   /path/to/somewhere/Release-iphoneos/arm64/func.o
+  #   /path/to/somewhere/Debug-iphonesimulator/x86_64/func.o
+
+When any Xcode variable or :variable:`CMAKE_CFG_INTDIR` is used, CMake is
+not able to fully evaluate the path(s) at configure time.  One consequence
+of this is that the configuration-specific
+:prop_tgt:`IMPORTED_OBJECTS_<CONFIG>` properties cannot be used, since
+CMake cannot determine whether an object file exists at a particular
+``<CONFIG>`` location.  The ``IMPORTED_OBJECTS`` property must be used for
+these situations and the configuration-specific aspects of the path must be
+handled by using :variable:`CMAKE_CFG_INTDIR` or with another Xcode variable
+``$(CONFIGURATION)``.
index b12ca38..238395a 100644 (file)
@@ -3,7 +3,18 @@ IMPORTED_OBJECTS_<CONFIG>
 
 .. versionadded:: 3.9
 
-<CONFIG>-specific version of :prop_tgt:`IMPORTED_OBJECTS` property.
+``<CONFIG>``-specific version of :prop_tgt:`IMPORTED_OBJECTS` property.
 
 Configuration names correspond to those provided by the project from
 which the target is imported.
+
+
+Xcode Generator Considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Do not use this ``<CONFIG>``-specific property if you need to use Xcode
+variables like ``$(CURRENT_ARCH)`` or ``$(EFFECTIVE_PLATFORM_NAME)`` in
+the value.  The ``<CONFIG>``-specific properties will be ignored in such
+cases because CMake cannot determine whether a file exists at the
+configuration-specific path at configuration time.  For such cases, use
+:prop_tgt:`IMPORTED_OBJECTS` instead.
index 747615a..8faefb7 100644 (file)
@@ -12,5 +12,5 @@ This property is initialized by the value of the variable
 created.
 
 This property supports :manual:`generator expressions <cmake-generator-expressions(7)>`.
-In particular, the ``$<INSTALL_PREFIX>`` generator expression can be used to set the
-directory relative to the install-time prefix.
+In particular, the :genex:`$<INSTALL_PREFIX>` generator expression can be
+used to set the directory relative to the install-time prefix.
index 7fc2372..af16d3c 100644 (file)
@@ -3,7 +3,7 @@
 
 .. versionadded:: 3.6
 
-This property is implemented only when ``<LANG>`` is ``C`` or ``CXX``.
+This property is implemented only when ``<LANG>`` is ``C``, ``CXX``, ``OBJC`` or ``OBJCXX``.
 
 Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a command
 line for the ``clang-tidy`` tool.  The :ref:`Makefile Generators`
index 785a57b..9fbe904 100644 (file)
@@ -3,7 +3,7 @@ LIBRARY_OUTPUT_DIRECTORY
 
 .. |XXX| replace:: :ref:`LIBRARY <Library Output Artifacts>`
 .. |xxx| replace:: library
-.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: CMAKE_LIBRARY_OUTPUT_DIRECTORY
+.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: :variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY`
 .. include:: XXX_OUTPUT_DIRECTORY.txt
 
 See also the :prop_tgt:`LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` target property.
index 1067153..96088af 100644 (file)
@@ -9,7 +9,7 @@ This property specifies the ObjC++ standard whose features are requested
 to build this target.  For some compilers, this results in adding a
 flag such as ``-std=gnu++11`` to the compile line.
 
-Supported values are ``98``, ``11``, ``14``, ``17``, and ``20``.
+Supported values are ``98``, ``11``, ``14``, ``17``, ``20``, ``23``.
 
 If the value requested does not result in a compile flag being added for
 the compiler in use, a previous standard flag will be added instead.  This
index 12390f5..3c37546 100644 (file)
@@ -3,7 +3,7 @@ RUNTIME_OUTPUT_DIRECTORY
 
 .. |XXX| replace:: :ref:`RUNTIME <Runtime Output Artifacts>`
 .. |xxx| replace:: runtime
-.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: CMAKE_RUNTIME_OUTPUT_DIRECTORY
+.. |CMAKE_XXX_OUTPUT_DIRECTORY| replace:: :variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY`
 .. include:: XXX_OUTPUT_DIRECTORY.txt
 
 See also the :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` target property.
index 04cede6..f827a20 100644 (file)
@@ -70,6 +70,11 @@ a number of measures to help address such problems:
   problems with specific files than disabling unity builds for an entire
   target.
 
+* Projects can set :prop_tgt:`UNITY_BUILD_UNIQUE_ID` to cause a valid
+  C-identifier to be generated which is unique per file in a unity
+  build.  This can be used to avoid problems with anonymous namespaces
+  in unity builds.
+
 * The :prop_tgt:`UNITY_BUILD_CODE_BEFORE_INCLUDE` and
   :prop_tgt:`UNITY_BUILD_CODE_AFTER_INCLUDE` target properties can be used
   to inject code into the unity source files before and after every
diff --git a/Help/prop_tgt/UNITY_BUILD_UNIQUE_ID.rst b/Help/prop_tgt/UNITY_BUILD_UNIQUE_ID.rst
new file mode 100644 (file)
index 0000000..2c95e02
--- /dev/null
@@ -0,0 +1,55 @@
+UNITY_BUILD_UNIQUE_ID
+---------------------
+
+.. versionadded:: 3.20
+
+The name of a valid C-identifier which is set to a unique per-file
+value during unity builds.
+
+When this property is populated and when :prop_tgt:`UNITY_BUILD`
+is true, the property value is used to define a compiler definition
+of the specified name. The value of the defined symbol is unspecified,
+but it is unique per file path.
+
+Given:
+
+.. code-block:: cmake
+
+  set_target_properties(myTarget PROPERTIES
+    UNITY_BUILD "ON"
+    UNITY_BUILD_UNIQUE_ID "MY_UNITY_ID"
+  )
+
+the ``MY_UNITY_ID`` symbol is defined to a unique per-file value.
+
+One known use case for this identifier is to disambiguate the
+variables in an anonymous namespace in a limited scope.
+Anonymous namespaces present a problem for unity builds because
+they are used to ensure that certain variables and declarations
+are scoped to a translation unit which is approximated by a
+single source file.  When source files are combined in a unity
+build file, those variables in different files are combined in
+a single translation unit and the names clash.  This property can
+be used to avoid that with code like the following:
+
+.. code-block:: cpp
+
+  // Needed for when unity builds are disabled
+  #ifndef MY_UNITY_ID
+  #define MY_UNITY_ID
+  #endif
+
+  namespace { namespace MY_UNITY_ID {
+    // The name 'i' clashes (or could clash) with other
+    // variables in other anonymous namespaces
+    int i = 42;
+  }}
+
+  int use_var()
+  {
+    return MY_UNITY_ID::i;
+  }
+
+The pseudononymous namespace is used within a truly anonymous namespace.
+On many platforms, this maintains the invariant that the symbols within
+do not get external linkage when performing a unity build.
index 71858c5..fbe7608 100644 (file)
@@ -3,9 +3,15 @@ XCODE_ATTRIBUTE_<an-attribute>
 
 Set Xcode target attributes directly.
 
-Tell the :generator:`Xcode` generator to set '<an-attribute>' to a given
+Tell the :generator:`Xcode` generator to set ``<an-attribute>`` to a given
 value in the generated Xcode project.  Ignored on other generators.
 
+This offers low-level control over the generated Xcode project file.
+It is meant as a last resort for specifying settings that CMake does
+not otherwise have a way to control.  Although this can override a
+setting CMake normally produces on its own, doing so bypasses CMake's
+model of the project and can break things.
+
 See the :variable:`CMAKE_XCODE_ATTRIBUTE_<an-attribute>` variable
 to set attributes on all targets in a directory tree.
 
diff --git a/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY.rst b/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY.rst
new file mode 100644 (file)
index 0000000..7b68126
--- /dev/null
@@ -0,0 +1,8 @@
+XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY
+----------------------------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator to perform code signing for all the
+frameworks and libraries that are embedded using the
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS <XCODE_EMBED_<type>>` property.
diff --git a/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY.rst b/Help/prop_tgt/XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY.rst
new file mode 100644 (file)
index 0000000..29f8c5c
--- /dev/null
@@ -0,0 +1,8 @@
+XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY
+---------------------------------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator to remove headers from all the
+frameworks that are embedded using the
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS <XCODE_EMBED_<type>>` property.
diff --git a/Help/prop_tgt/XCODE_EMBED_type.rst b/Help/prop_tgt/XCODE_EMBED_type.rst
new file mode 100644 (file)
index 0000000..90c5bc7
--- /dev/null
@@ -0,0 +1,14 @@
+XCODE_EMBED_<type>
+------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator to embed the specified list of items into
+the target bundle.  ``<type>`` specifies the embed build phase to use.
+
+Currently, the only supported value for ``<type>`` is ``FRAMEWORKS``.
+The specified items will be added to the ``Embed Frameworks`` build phase.
+The items can be CMake target names or paths to frameworks or libraries.
+See also :prop_tgt:`XCODE_EMBED_<type>_PATH`,
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY` and
+:prop_tgt:`XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY`.
diff --git a/Help/prop_tgt/XCODE_EMBED_type_PATH.rst b/Help/prop_tgt/XCODE_EMBED_type_PATH.rst
new file mode 100644 (file)
index 0000000..887cf57
--- /dev/null
@@ -0,0 +1,9 @@
+XCODE_EMBED_<type>_PATH
+-----------------------
+
+.. versionadded:: 3.20
+
+Tell the :generator:`Xcode` generator the relative path to use when embedding
+the items specified by :prop_tgt:`XCODE_EMBED_<type>`.  The path is relative
+to the base location of the ``Embed XXX`` build phase associated with
+``<type>``.
index 3ae5448..d38a96e 100644 (file)
@@ -3,9 +3,10 @@ Output directory in which to build |XXX| target files.
 This property specifies the directory into which |xxx| target files
 should be built.  The property value may use
 :manual:`generator expressions <cmake-generator-expressions(7)>`.
-Multi-configuration generators (VS, Xcode) append a per-configuration
-subdirectory to the specified directory unless a generator expression
-is used.
+Multi-configuration generators (:ref:`Visual Studio <Visual Studio Generators>`,
+:generator:`Xcode`, :generator:`Ninja Multi-Config`) append a
+per-configuration subdirectory to the specified directory unless a generator
+expression is used.
 
-This property is initialized by the value of the variable
-|CMAKE_XXX_OUTPUT_DIRECTORY| if it is set when a target is created.
+This property is initialized by the value of the
+|CMAKE_XXX_OUTPUT_DIRECTORY| variable if it is set when a target is created.
diff --git a/Help/release/3.20.rst b/Help/release/3.20.rst
new file mode 100644 (file)
index 0000000..176447d
--- /dev/null
@@ -0,0 +1,329 @@
+CMake 3.20 Release Notes
+************************
+
+.. only:: html
+
+  .. contents::
+
+Changes made since CMake 3.19 include the following.
+
+New Features
+============
+
+Presets
+-------
+
+* :manual:`cmake-presets(7)` gained support for build and test presets.
+
+Generators
+----------
+
+* :ref:`Makefile Generators`, for some toolchains, now use the compiler
+  to extract implicit dependencies while compiling source files.
+
+Languages
+---------
+
+* C++23 compiler modes may now be specified via the :prop_tgt:`CXX_STANDARD`,
+  :prop_tgt:`CUDA_STANDARD`, or :prop_tgt:`OBJCXX_STANDARD` target properties,
+  or via the :manual:`Compile Features <cmake-compile-features(7)>`
+  functionality's ``cxx_std_23`` meta-feature.
+
+* ``CUDA`` language support now works when ``nvcc`` is a symbolic link,
+  for example due to a ``ccache`` or ``colornvcc`` wrapper script.
+
+* The :envvar:`CUDAARCHS` environment variable was added for initializing
+  :variable:`CMAKE_CUDA_ARCHITECTURES`. Useful in cases where the compiler
+  default is unsuitable for the machine's GPU.
+
+Compilers
+---------
+
+* The NVIDIA HPC SDK compilers are now supported with compiler id ``NVHPC``.
+
+* The Intel oneAPI NextGen LLVM compilers are now supported with
+  compiler id ``IntelLLVM``:
+
+  * The ``icx``/``icpx`` C/C++ compilers on Linux, and the ``icx``
+    C/C++ compiler on Windows, are fully supported as of oneAPI 2021.1.
+
+  * The ``ifx`` Fortran compiler on Linux is partially supported.
+    As of oneAPI 2021.1, ``ifx`` does not define several identification
+    macros, so CMake identifies it as the classic ``Intel`` compiler.
+    This works in many cases because ``ifx`` accepts the same command line
+    parameters as ``ifort``.  A future version of oneAPI may fix this.
+
+  * The ``ifx`` Fortran compiler on Windows is not yet supported.
+
+  The Intel oneAPI Classic compilers (``icc``, ``icpc``, and ``ifort``)
+  continue to be supported with compiler id ``Intel``.
+
+* Support was added for the IAR STM8 compiler.
+
+Platforms
+---------
+
+* CMake's support for :ref:`Cross Compiling for Android`
+  is now merged with the Android NDK's toolchain file.
+  They now have similar behavior, though some variable names differ.
+  User-facing changes include:
+
+  - ``find_*`` functions will search NDK ABI / API specific paths by default.
+
+  - The default :variable:`CMAKE_BUILD_TYPE` for Android is
+    now ``RelWithDebInfo``.
+
+  - The :variable:`CMAKE_ANDROID_NDK_VERSION` variable was added to
+    report the version of the NDK.
+
+File-Based API
+--------------
+
+* The :manual:`cmake-file-api(7)` gained a new "toolchains" object
+  kind that describes the compiler used for each enabled language.
+
+Commands
+--------
+
+* :command:`add_custom_command` and :command:`add_custom_target` now
+  support :manual:`generator expressions <cmake-generator-expressions(7)>`
+  in their ``OUTPUT`` and ``BYPRODUCTS`` options.
+
+  Their ``COMMAND``, ``WORKING_DIRECTORY``, and ``DEPENDS`` options gained
+  support for new generator expressions ``$<COMMAND_CONFIG:...>`` and
+  ``$<OUTPUT_CONFIG:...>`` that control cross-config handling when using
+  the :generator:`Ninja Multi-Config` generator.
+
+* The :command:`add_custom_command` command gained ``DEPFILE`` support on
+  :ref:`Makefile Generators`.
+
+* The :command:`add_library` command previously prohibited imported object
+  libraries when using potentially multi-architecture configurations.
+  This mostly affected the :generator:`Xcode` generator, e.g. when targeting
+  iOS or one of the other device platforms.  This restriction has now been
+  removed.
+
+* The :command:`cmake_path` command was added for operations on
+  filesystem paths.
+
+* The :command:`configure_file` command gained ``USE_SOURCE_PERMISSIONS``
+  and ``FILE_PERMISSIONS`` options to support copying of permissions of the
+  source file and using specified permissions respectively.
+
+* The :command:`file(GENERATE)` command gained a ``NEWLINE_STYLE`` option to
+  specify how newlines are handled for the generated file.
+
+* The :command:`file(GENERATE)` command gained ``NO_SOURCE_PERMISSIONS``,
+  ``USE_SOURCE_PERMISSIONS``, and ``FILE_PERMISSIONS`` options for controlling
+  the permissions of the generated file.
+
+* The :command:`install(FILES)` command ``RENAME`` option learned to
+  support :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :command:`target_include_directories` command gained a new option
+  ``AFTER``.
+
+* The :command:`target_sources` command now supports targets created
+  by the :command:`add_custom_target` command.
+
+* The :command:`try_run` command gained a ``WORKING_DIRECTORY`` option to
+  set the working directory in which to run the compiled check executable.
+
+Variables
+---------
+
+* The :variable:`CMAKE_<LANG>_BYTE_ORDER` variable was added to provide the
+  target architecture byte order detected from the toolchain.
+
+* The :variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY`,
+  :variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY`, and
+  :variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY` variables now support
+  target-dependent generator expressions.
+
+Properties
+----------
+
+* The :prop_tgt:`<LANG>_CLANG_TIDY` target property and the associated
+  :variable:`CMAKE_<LANG>_CLANG_TIDY` variable learned to support
+  the ``OBJC`` and ``OBJCXX`` languages.
+
+* The :prop_tgt:`EXPORT_COMPILE_COMMANDS` target property was added
+  for the associated :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` variable
+  to allow for configuration of exporting compile commands per target.
+
+* The :prop_sf:`GENERATED` source-file property is now visible
+  from any directory scope, regardless of the scope in which it is set.
+  See policy :policy:`CMP0118`.
+
+* The :prop_tgt:`UNITY_BUILD_UNIQUE_ID` target property
+  was added to support generation of an identifier that is
+  unique per source file in unity builds.  It can help to
+  resolve duplicate symbol problems with anonymous namespaces.
+
+* The :prop_tgt:`WIN32_EXECUTABLE` target property now works with Clang
+  on Windows.
+
+* The :prop_tgt:`XCODE_EMBED_FRAMEWORKS <XCODE_EMBED_<type>>` target property
+  was added to tell the :generator:`Xcode` generator to embed frameworks.
+  Aspects of the embedding can be customized with the
+  :prop_tgt:`XCODE_EMBED_FRAMEWORKS_PATH <XCODE_EMBED_<type>>`,
+  :prop_tgt:`XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY`, and
+  :prop_tgt:`XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY` target properties.
+
+Modules
+-------
+
+* The :module:`ExternalData` module :command:`ExternalData_Add_Target`
+  function gained a ``SHOW_PROGRESS <bool>`` option for controlling whether
+  or not to show progress output during the build.
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` function
+  gained a ``CONFIGURE_HANDLED_BY_BUILD`` option.  This can be used to make
+  subsequent runs of the configure step be triggered by the build step when
+  an external project dependency rebuilds instead of always re-running the
+  configure step in such cases.
+
+* The :module:`FindBoost` module gained a ``Boost_NO_WARN_NEW_VERSIONS``
+  option to silence the warning about unknown dependencies for new
+  Boost versions.
+
+* The :module:`FindCUDAToolkit` module gained support for finding CUDA
+  toolkits when ``nvcc`` is a symbolic link,
+  for example due to a ``ccache`` or ``colornvcc`` wrapper script.
+
+* The :module:`FindGDAL` module has been improved to document and mark as
+  advanced its cache variables. There is a new ``FindGDAL_SKIP_GDAL_CONFIG``
+  variable which may be used to skip over the ``gdal-config``-based search.
+  Users may also set ``GDAL_ADDITIONAL_LIBRARY_VERSIONS`` to add additional
+  versions to the library name search strategy.
+
+* The :module:`FindIntl` module now provides an imported target.
+
+* The :module:`FindOpenSSL` module learned to support a version range.
+
+* The :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+  modules gained options controlling how unversioned interpreter names are
+  searched.
+
+* The :module:`UseJava` module ``add_jar()`` command's
+  ``GENERATE_NATIVE_HEADERS`` feature gained options to export the
+  generated target.
+
+* The :module:`UseSWIG` module gained the capability, for
+  :ref:`Makefile <Makefile Generators>` and :ref:`Ninja <Ninja Generators>`
+  generators, to use the ``swig`` tool to generate implicit dependencies.
+
+Autogen
+-------
+
+* The :ref:`Qt AUTOMOC` feature now works with per-config sources.
+
+CTest
+-----
+
+* :manual:`ctest(1)` gained a ``--test-dir`` option to specify the directory
+  in which to look for tests.
+
+CPack
+-----
+
+* :module:`CPack` gained the :variable:`CPACK_THREADS` variable to
+  control the number of threads used for parallelized operations,
+  such as compressing the installer package.
+
+* The :cpack_gen:`CPack DEB Generator` learned a new
+  :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS`
+  variable to specify additional search directories for
+  resolving private library dependencies when using
+  ``dpkg-shlibdeps``.
+
+* The :cpack_gen:`CPack IFW Generator` gained a new
+  :variable:`CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST` variable to
+  control visibility of the widget listing installer pages on the left side
+  of the wizard. This feature available only since QtIFW 4.0.
+
+* The :cpack_gen:`CPack NSIS Generator` gained new
+  :variable:`CPACK_NSIS_BRANDING_TEXT` and
+  :variable:`CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION` variables to change
+  the text at the bottom of the install window and change its trim position
+
+* The :cpack_gen:`CPack NSIS Generator` now correctly handles Unicode
+  characters.  If you want to have a :variable:`CPACK_RESOURCE_FILE_LICENSE`
+  with UTF-8 characters, it needs to be encoded in UTF-8 BOM.
+
+* The :cpack_gen:`CPack NuGet Generator` gained options:
+
+  - :variable:`CPACK_NUGET_PACKAGE_ICON` and
+    :variable:`CPACK_NUGET_<compName>_PACKAGE_ICON`
+    allow package icons to be specified by local files.
+  - :variable:`CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION` and
+    :variable:`CPACK_NUGET_<compName>_PACKAGE_LICENSE_EXPRESSION` add
+    support for specifying licenses recognized by the
+    `Software Package Data Exchange`_ (SPDX).
+  - :variable:`CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME` and
+    :variable:`CPACK_NUGET_<compName>_PACKAGE_LICENSE_FILE_NAME` allow
+    licenses to be specified by local files.
+  - :variable:`CPACK_NUGET_PACKAGE_LANGUAGE` and
+    :variable:`CPACK_NUGET_<compName>_PACKAGE_LANGUAGE` allow the locale
+    for a package to be specified, for example ``en_CA``.
+
+.. _Software Package Data Exchange: https://spdx.org/
+
+Deprecated and Removed Features
+===============================
+
+* The :manual:`cmake-server(7)` mode has been removed.
+  Clients should use the :manual:`cmake-file-api(7)` instead.
+
+* The :module:`WriteCompilerDetectionHeader` module has been deprecated
+  via policy :policy:`CMP0120`.  Projects should be ported away from it.
+
+* The :module:`TestBigEndian` module has been deprecated in favor
+  of the :variable:`CMAKE_<LANG>_BYTE_ORDER` variable.
+
+* The :module:`AddFileDependencies` module is deprecated.
+  Port projects to use :command:`set_property` directly.
+
+* The :cpack_gen:`CPack NuGet Generator` deprecated some variables to reflect
+  changes in the NuGet specification:
+
+  - :variable:`CPACK_NUGET_PACKAGE_ICONURL` and
+    :variable:`CPACK_NUGET_<compName>_PACKAGE_ICONURL` have been deprecated;
+    replace with a reference to a local icon file.
+  - :variable:`CPACK_NUGET_PACKAGE_LICENSEURL` and
+    :variable:`CPACK_NUGET_<compName>_PACKAGE_LICENSEURL` have been deprecated;
+    replace with a reference to the project's license file or SPDX
+    license expression.
+
+Other Changes
+=============
+
+* Source file extensions must now be explicit.
+  See policy :policy:`CMP0115` for details.
+
+* The :prop_sf:`LANGUAGE` source file property now forces compilation
+  as the specified language.  See policy :policy:`CMP0119`.
+
+* On AIX, installation of XCOFF executables and shared libraries
+  no longer requires relinking to change the runtime search path
+  from the build-tree RPATH to the install-tree RPATH.  CMake now
+  edits the XCOFF binaries directly during installation, as has
+  long been done on ELF platforms.
+
+* With MSVC-like compilers the value of
+  :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` no longer contains
+  the ``/GR`` flag for runtime type information by default.
+  See policy :policy:`CMP0117`.
+
+* Ninja generators now transform the ``DEPFILE`` generated by an
+  :command:`add_custom_command`. See policy :policy:`CMP0116` for details.
+
+* The precompiled Linux binaries provided on
+  `cmake.org <https://cmake.org/download/>`_ have changed their naming pattern
+  to ``cmake-$ver-linux-$arch``, where ``$arch`` is either ``x86_64`` or
+  ``aarch64``.
+
+* The precompiled Windows binaries provided on
+  `cmake.org <https://cmake.org/download/>`_ have changed their naming pattern
+  to ``cmake-$ver-windows-$arch``, where ``$arch`` is either ``x86_64`` or
+  ``i386``.
index 6fb0f1a..95b41fb 100644 (file)
@@ -13,6 +13,7 @@ Releases
 .. toctree::
    :maxdepth: 1
 
+   3.20 <3.20>
    3.19 <3.19>
    3.18 <3.18>
    3.17 <3.17>
diff --git a/Help/variable/CMAKE_ANDROID_EXCEPTIONS.rst b/Help/variable/CMAKE_ANDROID_EXCEPTIONS.rst
new file mode 100644 (file)
index 0000000..6dd44f8
--- /dev/null
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_EXCEPTIONS
+------------------------
+
+.. versionadded:: 3.20
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable may be set
+to specify whether exceptions are enabled.
diff --git a/Help/variable/CMAKE_ANDROID_NDK_VERSION.rst b/Help/variable/CMAKE_ANDROID_NDK_VERSION.rst
new file mode 100644 (file)
index 0000000..5428d52
--- /dev/null
@@ -0,0 +1,8 @@
+CMAKE_ANDROID_NDK_VERSION
+-------------------------
+
+.. versionadded:: 3.20
+
+When :ref:`Cross Compiling for Android with the NDK` and using an
+Android NDK version 11 or higher, this variable is provided by
+CMake to report the NDK version number.
diff --git a/Help/variable/CMAKE_ANDROID_RTTI.rst b/Help/variable/CMAKE_ANDROID_RTTI.rst
new file mode 100644 (file)
index 0000000..0e98206
--- /dev/null
@@ -0,0 +1,7 @@
+CMAKE_ANDROID_RTTI
+------------------
+
+.. versionadded:: 3.20
+
+When :ref:`Cross Compiling for Android with the NDK`, this variable may be set
+to specify whether RTTI is enabled.
index 0d5ccd1..ad297c3 100644 (file)
@@ -8,7 +8,8 @@ CMake what architecture to use for :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`.
 The value must be either ``arm64`` or ``x86_64``.
 
 The value of this variable should never be modified by project code.
-It is meant to be set as a cache entry provided by the user,
-e.g. via ``-DCMAKE_APPLE_SILICON_PROCESSOR=...``.
+It is meant to be set by a toolchain file specified by the
+:variable:`CMAKE_TOOLCHAIN_FILE` variable, or as a cache entry
+provided by the user, e.g. via ``-DCMAKE_APPLE_SILICON_PROCESSOR=...``.
 
 See also the :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment variable.
index 2d35635..405f7d5 100644 (file)
@@ -18,3 +18,8 @@ in a build tree configured to build type ``Debug``, CMake will see to
 having :variable:`CMAKE_C_FLAGS_DEBUG <CMAKE_<LANG>_FLAGS_DEBUG>` settings get
 added to the :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` settings.  See
 also :variable:`CMAKE_CONFIGURATION_TYPES`.
+
+Note that configuration names are case-insensitive.  The value of this
+variable will be the same as it is specified when invoking CMake.
+For instance, if ``-DCMAKE_BUILD_TYPE=ReLeAsE`` is specified, then the
+value of ``CMAKE_BUILD_TYPE`` will be ``ReLeAsE``.
index 985040d..d885516 100644 (file)
@@ -5,7 +5,8 @@ CMAKE_CUDA_ARCHITECTURES
 
 Default value for :prop_tgt:`CUDA_ARCHITECTURES` property of targets.
 
-This is initialized as follows depending on :variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>`:
+Initialized by the :envvar:`CUDAARCHS` environment variable if set.
+Otherwise as follows depending on :variable:`CMAKE_CUDA_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>`:
 
 - For ``Clang``: the oldest architecture that works.
 
@@ -17,3 +18,18 @@ and compiler versions.
 
 This variable is used to initialize the :prop_tgt:`CUDA_ARCHITECTURES` property
 on all targets. See the target property for additional information.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+  cmake_minimum_required(VERSION)
+
+  if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
+    set(CMAKE_CUDA_ARCHITECTURES 75)
+  endif()
+
+  project(example LANGUAGES CUDA)
+
+``CMAKE_CUDA_ARCHITECTURES`` will default to ``75`` unless overridden by the user.
diff --git a/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst b/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
new file mode 100644 (file)
index 0000000..bdad59e
--- /dev/null
@@ -0,0 +1,9 @@
+CMAKE_DEPENDS_USE_COMPILER
+--------------------------
+
+.. versionadded:: 3.20
+
+For the :ref:`Makefile Generators`, source dependencies are now, for a
+selection of compilers, generated by the compiler itself. By defining this
+variable with value ``FALSE``, you can restore the legacy behavior (i.e. using
+``CMake`` for dependencies discovery).
index 724f309..53a19dc 100644 (file)
@@ -28,7 +28,8 @@ form.  The format of the JSON file looks like:
   ]
 
 This is initialized by the :envvar:`CMAKE_EXPORT_COMPILE_COMMANDS` environment
-variable.
+variable, and initializes the :prop_tgt:`EXPORT_COMPILE_COMMANDS` target
+property for all targets.
 
 .. note::
   This option is implemented only by :ref:`Makefile Generators`
diff --git a/Help/variable/CMAKE_LANG_BYTE_ORDER.rst b/Help/variable/CMAKE_LANG_BYTE_ORDER.rst
new file mode 100644 (file)
index 0000000..78f0ae6
--- /dev/null
@@ -0,0 +1,20 @@
+CMAKE_<LANG>_BYTE_ORDER
+-----------------------
+
+.. versionadded:: 3.20
+
+Byte order of ``<LANG>`` compiler target architecture, if known.
+If defined and not empty, the value is one of:
+
+``BIG_ENDIAN``
+  The target architecture is Big Endian.
+
+``LITTLE_ENDIAN``
+  The target architecture is Little Endian.
+
+This is defined for languages ``C``, ``CXX``, ``OBJC``, ``OBJCXX``,
+and ``CUDA``.
+
+If :variable:`CMAKE_OSX_ARCHITECTURES` specifies multiple architectures, the
+value of ``CMAKE_<LANG>_BYTE_ORDER`` is non-empty only if all architectures
+share the same byte order.
index 78f0f6a..32e27b0 100644 (file)
@@ -4,7 +4,7 @@ CMAKE_<LANG>_CLANG_TIDY
 .. versionadded:: 3.6
 
 Default value for :prop_tgt:`<LANG>_CLANG_TIDY` target property
-when ``<LANG>`` is ``C`` or ``CXX``.
+when ``<LANG>`` is ``C``, ``CXX``, ``OBJC`` or ``OBJCXX``.
 
 This variable is used to initialize the property on each target as it is
 created.  For example:
index 8eb4fb6..89d9e27 100644 (file)
@@ -25,7 +25,9 @@ include:
   HP = Hewlett-Packard Compiler (hp.com)
   IAR = IAR Systems (iar.com)
   Intel = Intel Compiler (intel.com)
+  IntelLLVM = Intel LLVM-Based Compiler (intel.com)
   MSVC = Microsoft Visual Studio (microsoft.com)
+  NVHPC = NVIDIA HPC SDK Compiler (nvidia.com)
   NVIDIA = NVIDIA CUDA Compiler (nvidia.com)
   OpenWatcom = Open Watcom (openwatcom.org)
   PGI = The Portland Group (pgroup.com)
index f4ccc04..e86f639 100644 (file)
@@ -15,7 +15,7 @@ back to its starting type.  This property switches the final linker
 search type to ``-Bstatic`` regardless of how it started.
 
 This variable is used to initialize the target property
-:prop_tgt:`LINK_SEARCH_END_STATIC` for all targets. If set, it's
+:prop_tgt:`LINK_SEARCH_END_STATIC` for all targets. If set, its
 value is also used by the :command:`try_compile` command.
 
 See also :variable:`CMAKE_LINK_SEARCH_START_STATIC`.
index 2025c72..ab1837c 100644 (file)
@@ -16,7 +16,7 @@ when linking an executable statically (e.g.  with the GNU ``-static``
 option).
 
 This variable is used to initialize the target property
-:prop_tgt:`LINK_SEARCH_START_STATIC` for all targets.  If set, it's
+:prop_tgt:`LINK_SEARCH_START_STATIC` for all targets.  If set, its
 value is also used by the :command:`try_compile` command.
 
 See also :variable:`CMAKE_LINK_SEARCH_END_STATIC`.
index 189f59f..b9b045e 100644 (file)
@@ -1,10 +1,17 @@
 CMAKE_NO_BUILTIN_CHRPATH
 ------------------------
 
-Do not use the builtin ELF editor to fix RPATHs on installation.
+Do not use the builtin binary editor to fix runtime library search
+paths on installation.
 
-When an ELF binary needs to have a different RPATH after installation
-than it does in the build tree, CMake uses a builtin editor to change
-the RPATH in the installed copy.  If this variable is set to true then
-CMake will relink the binary before installation instead of using its
-builtin editor.
+When an ELF or XCOFF binary needs to have a different runtime library
+search path after installation than it does in the build tree, CMake uses
+a builtin editor to change the runtime search path in the installed copy.
+If this variable is set to true then CMake will relink the binary before
+installation instead of using its builtin editor.
+
+.. versionadded:: 3.20
+
+  This variable also applies to XCOFF binaries' LIBPATH.  Prior to the
+  addition of the XCOFF editor in CMake 3.20, this variable applied only
+  to ELF binaries' RPATH/RUNPATH.
index d35595a..9f68741 100644 (file)
@@ -27,6 +27,8 @@ warn by default:
   policy :policy:`CMP0102`.
 * ``CMAKE_POLICY_WARNING_CMP0112`` controls the warning for
   policy :policy:`CMP0112`.
+* ``CMAKE_POLICY_WARNING_CMP0116`` controls the warning for
+  policy :policy:`CMP0116`.
 
 This variable should not be set by a project in CMake code.  Project
 developers running CMake may set this variable in their cache to
index 43b1397..b010317 100644 (file)
@@ -5,5 +5,5 @@ Default value for :prop_tgt:`POSITION_INDEPENDENT_CODE` of targets.
 
 This variable is used to initialize the
 :prop_tgt:`POSITION_INDEPENDENT_CODE` property on all the targets.
-See that target property for additional information.  If set, it's
+See that target property for additional information.  If set, its
 value is also used by the :command:`try_compile` command.
index 8ad89f1..ce16215 100644 (file)
@@ -1,8 +1,13 @@
 CMAKE_SYSTEM_PROCESSOR
 ----------------------
 
-The name of the CPU CMake is building for.
+When not cross-compiling, this variable has the same value as the
+:variable:`CMAKE_HOST_SYSTEM_PROCESSOR` variable.  In many cases,
+this will correspond to the target architecture for the build, but
+this is not guaranteed.  (E.g. on Windows, the host may be ``AMD64``
+even when using a MSVC ``cl`` compiler with a 32-bit target.)
 
-This variable is the same as :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` if
-you build for the host system instead of the target system when
-cross compiling.
+When cross-compiling, a :variable:`CMAKE_TOOLCHAIN_FILE` should set
+the ``CMAKE_SYSTEM_PROCESSOR`` variable to match target architecture
+that it specifies (via :variable:`CMAKE_<LANG>_COMPILER` and perhaps
+:variable:`CMAKE_<LANG>_COMPILER_TARGET`).
diff --git a/Help/variable/CMAKE_UNITY_BUILD_UNIQUE_ID.rst b/Help/variable/CMAKE_UNITY_BUILD_UNIQUE_ID.rst
new file mode 100644 (file)
index 0000000..64ef18a
--- /dev/null
@@ -0,0 +1,8 @@
+CMAKE_UNITY_BUILD_UNIQUE_ID
+---------------------------
+
+.. versionadded:: 3.20
+
+This variable is used to initialize the :prop_tgt:`UNITY_BUILD_UNIQUE_ID`
+property of targets when they are created.  It specifies the name of the
+unique identifier generated per file in a unity build.
index 90e4c0e..ffa0a4c 100644 (file)
@@ -5,8 +5,14 @@ CMAKE_XCODE_ATTRIBUTE_<an-attribute>
 
 Set Xcode target attributes directly.
 
-Tell the :generator:`Xcode` generator to set '<an-attribute>' to a given value
-in the generated Xcode project.  Ignored on other generators.
+Tell the :generator:`Xcode` generator to set ``<an-attribute>`` to a given
+value in the generated Xcode project.  Ignored on other generators.
+
+This offers low-level control over the generated Xcode project file.
+It is meant as a last resort for specifying settings that CMake does
+not otherwise have a way to control.  Although this can override a
+setting CMake normally produces on its own, doing so bypasses CMake's
+model of the project and can break things.
 
 See the :prop_tgt:`XCODE_ATTRIBUTE_<an-attribute>` target property
 to set attributes on a specific target.
index 6cd51fa..b6fee2e 100644 (file)
@@ -5,3 +5,8 @@ CTEST_MEMORYCHECK_SANITIZER_OPTIONS
 
 Specify the CTest ``MemoryCheckSanitizerOptions`` setting
 in a :manual:`ctest(1)` dashboard client script.
+
+CTest prepends correct sanitizer options ``*_OPTIONS``
+environment variable to executed command. CTests adds
+its own ``log_path`` to sanitizer options, don't provide your
+own ``log_path``.
index ca8775c..a2dbc2e 100644 (file)
@@ -1,8 +1,7 @@
 MSVC
 ----
 
-Set to ``true`` when the compiler is some version of Microsoft Visual
-C++ or another compiler simulating Visual C++.  Any compiler defining
-``_MSC_VER`` is considered simulating Visual C++.
+Set to ``true`` when the compiler is some version of Microsoft Visual C++
+or another compiler simulating the Visual C++ ``cl`` command-line syntax.
 
 See also the :variable:`MSVC_VERSION` variable.
index 027d1bc..18e9983 100644 (file)
@@ -5,3 +5,10 @@ MSVC_IDE
 
 Set to ``true`` when the target platform is the Microsoft Visual C++ IDE, as
 opposed to the command line compiler.
+
+.. note::
+
+  This variable is only available after compiler detection has been performed,
+  so it is not available to toolchain files or before the first
+  :command:`project` or :command:`enable_language` call which uses an
+  MSVC-like compiler.
index 598a52f..13b2600 100644 (file)
@@ -5,24 +5,29 @@
 AddFileDependencies
 -------------------
 
+.. deprecated:: 3.20
+
 Add dependencies to a source file.
 
 .. code-block:: cmake
 
-  ADD_FILE_DEPENDENCIES(<source> <files>)
+  add_file_dependencies(<source> <files>...)
 
 Adds the given ``<files>`` to the dependencies of file ``<source>``.
-#]=======================================================================]
 
-macro(ADD_FILE_DEPENDENCIES _file)
+Do not use this command in new code.  It is just a wrapper around:
+
+.. code-block:: cmake
+
+  set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+
+Instead use the :command:`set_property` command to append to the
+:prop_sf:`OBJECT_DEPENDS` source file property directly.
+
+#]=======================================================================]
 
-  get_source_file_property(_deps ${_file} OBJECT_DEPENDS)
-  if (_deps)
-    set(_deps ${_deps} ${ARGN})
-  else ()
-    set(_deps ${ARGN})
-  endif ()
+function(add_file_dependencies _file)
 
-  set_source_files_properties(${_file} PROPERTIES OBJECT_DEPENDS "${_deps}")
+  set_property(SOURCE "${_file}" APPEND PROPERTY OBJECT_DEPENDS "${ARGN}")
 
-endmacro()
+endfunction()
index f521d22..0beff04 100644 (file)
@@ -59,9 +59,10 @@ fix each one up according to its own list of prerequisites.
 Then clear all the keys and call ``verify_app`` on the final bundle to
 ensure that it is truly standalone.
 
-As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
-which are then ignored
-(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``).
+.. versionadded:: 3.6
+  As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+  which are then ignored
+  (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``).
 
 .. code-block:: cmake
 
@@ -78,9 +79,10 @@ Verifies that an application ``<app>`` appears valid based on running
 analysis tools on it.  Calls :command:`message(FATAL_ERROR)` if the application
 is not verified.
 
-As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
-which are then ignored
-(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
+.. versionadded:: 3.6
+  As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+  which are then ignored
+  (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
 
 .. code-block:: cmake
 
@@ -155,9 +157,10 @@ them.  Set values associated with each key such that we can loop over
 all of them and copy prerequisite libs into the bundle and then do
 appropriate ``install_name_tool`` fixups.
 
-As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
-which are then ignored
-(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
+.. versionadded:: 3.6
+  As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+  which are then ignored
+  (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
 
 .. code-block:: cmake
 
@@ -215,9 +218,10 @@ Verifies that the sum of all prerequisites of all files inside the
 bundle are contained within the bundle or are ``system`` libraries,
 presumed to exist everywhere.
 
-As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
-which are then ignored
-(e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
+.. versionadded:: 3.6
+  As an optional parameter (``IGNORE_ITEM``) a list of file names can be passed,
+  which are then ignored
+  (e.g. ``IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe"``)
 
 .. code-block:: cmake
 
index eea3f5d..7f73891 100644 (file)
@@ -48,6 +48,7 @@ set(CMAKE_C_LINKER_PREFERENCE 10)
 # Save compiler ABI information.
 set(CMAKE_C_SIZEOF_DATA_PTR "@CMAKE_C_SIZEOF_DATA_PTR@")
 set(CMAKE_C_COMPILER_ABI "@CMAKE_C_COMPILER_ABI@")
+set(CMAKE_C_BYTE_ORDER "@CMAKE_C_BYTE_ORDER@")
 set(CMAKE_C_LIBRARY_ARCHITECTURE "@CMAKE_C_LIBRARY_ARCHITECTURE@")
 
 if(CMAKE_C_SIZEOF_DATA_PTR)
index 08cf39b..f0ee21a 100644 (file)
@@ -17,6 +17,8 @@ int main(int argc, char* argv[])
 {
   int require = 0;
   require += info_sizeof_dptr[argc];
+  require += info_byte_order_big_endian[argc];
+  require += info_byte_order_little_endian[argc];
 #if defined(ABI_ID)
   require += info_abi[argc];
 #endif
index 871e18e..56ae732 100644 (file)
@@ -12,6 +12,7 @@ set(CMAKE_CUDA11_COMPILE_FEATURES "@CMAKE_CUDA11_COMPILE_FEATURES@")
 set(CMAKE_CUDA14_COMPILE_FEATURES "@CMAKE_CUDA14_COMPILE_FEATURES@")
 set(CMAKE_CUDA17_COMPILE_FEATURES "@CMAKE_CUDA17_COMPILE_FEATURES@")
 set(CMAKE_CUDA20_COMPILE_FEATURES "@CMAKE_CUDA20_COMPILE_FEATURES@")
+set(CMAKE_CUDA23_COMPILE_FEATURES "@CMAKE_CUDA23_COMPILE_FEATURES@")
 
 set(CMAKE_CUDA_PLATFORM_ID "@CMAKE_CUDA_PLATFORM_ID@")
 set(CMAKE_CUDA_SIMULATE_ID "@CMAKE_CUDA_SIMULATE_ID@")
@@ -31,6 +32,7 @@ set(CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES 1)
 
 set(CMAKE_CUDA_SIZEOF_DATA_PTR "@CMAKE_CUDA_SIZEOF_DATA_PTR@")
 set(CMAKE_CUDA_COMPILER_ABI "@CMAKE_CUDA_COMPILER_ABI@")
+set(CMAKE_CUDA_BYTE_ORDER "@CMAKE_CUDA_BYTE_ORDER@")
 set(CMAKE_CUDA_LIBRARY_ARCHITECTURE "@CMAKE_CUDA_LIBRARY_ARCHITECTURE@")
 
 if(CMAKE_CUDA_SIZEOF_DATA_PTR)
index 702a7c5..449a079 100644 (file)
@@ -8,6 +8,8 @@ int main(int argc, char* argv[])
 {
   int require = 0;
   require += info_sizeof_dptr[argc];
+  require += info_byte_order_big_endian[argc];
+  require += info_byte_order_little_endian[argc];
 #if defined(ABI_ID)
   require += info_abi[argc];
 #endif
index 2055de2..91039e5 100644 (file)
@@ -17,7 +17,9 @@ char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";
 @CMAKE_CUDA_COMPILER_ID_ERROR_FOR_TEST@
 
 const char* info_language_dialect_default = "INFO" ":" "dialect_default["
-#if __cplusplus > 201703L
+#if __cplusplus > 202002L
+  "23"
+#elif __cplusplus > 201703L
   "20"
 #elif __cplusplus >= 201703L
   "17"
index 58e6e29..cb03ef4 100644 (file)
@@ -154,21 +154,6 @@ if(NOT CMAKE_CUDA_COMPILE_WHOLE_COMPILATION)
     "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -c <SOURCE> -o <OBJECT>")
 endif()
 
-if(CMAKE_GENERATOR STREQUAL "Ninja" AND NOT CMAKE_DEPFILE_FLAGS_CUDA)
-  set(CMAKE_CUDA_COMPILE_DEPENDENCY_DETECTION
-    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -M <SOURCE> -MT <OBJECT> -o $DEP_FILE")
-  #The Ninja generator uses the make file dependency files to determine what
-  #files need to be recompiled. Unfortunately, nvcc < 10.2 doesn't support building
-  #a source file and generating the dependencies of said file in a single
-  #invocation. Instead we have to state that you need to chain two commands.
-  #
-  #The makefile generators uses the custom CMake dependency scanner, and thus
-  #it is exempt from this logic.
-  list(APPEND CMAKE_CUDA_COMPILE_PTX_COMPILATION "${CMAKE_CUDA_COMPILE_DEPENDENCY_DETECTION}")
-  list(APPEND CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION "${CMAKE_CUDA_COMPILE_DEPENDENCY_DETECTION}")
-  list(APPEND CMAKE_CUDA_COMPILE_WHOLE_COMPILATION "${CMAKE_CUDA_COMPILE_DEPENDENCY_DETECTION}")
-endif()
-
 # compile a cu file into an executable
 if(NOT CMAKE_CUDA_LINK_EXECUTABLE)
   set(CMAKE_CUDA_LINK_EXECUTABLE
index 09bdc23..45acfe7 100644 (file)
@@ -11,6 +11,7 @@ set(CMAKE_CXX11_COMPILE_FEATURES "@CMAKE_CXX11_COMPILE_FEATURES@")
 set(CMAKE_CXX14_COMPILE_FEATURES "@CMAKE_CXX14_COMPILE_FEATURES@")
 set(CMAKE_CXX17_COMPILE_FEATURES "@CMAKE_CXX17_COMPILE_FEATURES@")
 set(CMAKE_CXX20_COMPILE_FEATURES "@CMAKE_CXX20_COMPILE_FEATURES@")
+set(CMAKE_CXX23_COMPILE_FEATURES "@CMAKE_CXX23_COMPILE_FEATURES@")
 
 set(CMAKE_CXX_PLATFORM_ID "@CMAKE_CXX_PLATFORM_ID@")
 set(CMAKE_CXX_SIMULATE_ID "@CMAKE_CXX_SIMULATE_ID@")
@@ -43,7 +44,7 @@ if(CMAKE_COMPILER_IS_MINGW)
   set(MINGW 1)
 endif()
 set(CMAKE_CXX_COMPILER_ID_RUN 1)
-set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;CPP)
+set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP)
 set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
 
 foreach (lang C OBJC OBJCXX)
@@ -60,6 +61,7 @@ set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1)
 # Save compiler ABI information.
 set(CMAKE_CXX_SIZEOF_DATA_PTR "@CMAKE_CXX_SIZEOF_DATA_PTR@")
 set(CMAKE_CXX_COMPILER_ABI "@CMAKE_CXX_COMPILER_ABI@")
+set(CMAKE_CXX_BYTE_ORDER "@CMAKE_CXX_BYTE_ORDER@")
 set(CMAKE_CXX_LIBRARY_ARCHITECTURE "@CMAKE_CXX_LIBRARY_ARCHITECTURE@")
 
 if(CMAKE_CXX_SIZEOF_DATA_PTR)
index 2360534..036b96e 100644 (file)
@@ -8,6 +8,8 @@ int main(int argc, char* argv[])
 {
   int require = 0;
   require += info_sizeof_dptr[argc];
+  require += info_byte_order_big_endian[argc];
+  require += info_byte_order_little_endian[argc];
 #if defined(ABI_ID)
   require += info_abi[argc];
 #endif
index d55d8b1..a67caba 100644 (file)
@@ -44,7 +44,9 @@ char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";
 #endif
 
 const char* info_language_dialect_default = "INFO" ":" "dialect_default["
-#if CXX_STD > 201703L
+#if CXX_STD > 202002L
+  "23"
+#elif CXX_STD > 201703L
   "20"
 #elif CXX_STD >= 201703L
   "17"
index 45532af..c5ce4dd 100644 (file)
@@ -9,6 +9,18 @@ const char info_sizeof_dptr[] = {
   /* clang-format on */
 };
 
+/* Byte order.  Only one of these will have bytes in the right order.  */
+static unsigned short const info_byte_order_big_endian[] = {
+  /* INFO:byte_order string for BIG_ENDIAN */
+  0x494E, 0x464F, 0x3A62, 0x7974, 0x655F, 0x6F72, 0x6465, 0x725B,
+  0x4249, 0x475F, 0x454E, 0x4449, 0x414E, 0x5D00, 0x0000
+};
+static unsigned short const info_byte_order_little_endian[] = {
+  /* INFO:byte_order string for LITTLE_ENDIAN */
+  0x4E49, 0x4F46, 0x623A, 0x7479, 0x5F65, 0x726F, 0x6564, 0x5B72,
+  0x494C, 0x5454, 0x454C, 0x455F, 0x444E, 0x4149, 0x5D4E, 0x0000
+};
+
 /* Application Binary Interface.  */
 
 /* Check for (some) ARM ABIs.
index a0f0dfa..214d58a 100644 (file)
@@ -49,6 +49,7 @@ function(compiler_id_detection outvar lang)
     endif()
     list(APPEND ordered_compilers
       Intel
+      IntelLLVM
       PathScale
       Embarcadero
       Borland
@@ -61,6 +62,7 @@ function(compiler_id_detection outvar lang)
       XLClang
       XL
       VisualAge
+      NVHPC
       PGI
       Cray
       TI
index a3e5a12..e8b9db7 100644 (file)
@@ -78,6 +78,10 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
   set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_Intel "--version")
   set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_Intel "(ICC)")
 
+  list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS IntelLLVM )
+  set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_IntelLLVM "--version")
+  set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_IntelLLVM "(Intel[^\n]+oneAPI)")
+
   list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS SunPro )
   set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_SunPro "-V")
   set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_SunPro "Sun C")
index ae3abe9..cd07ba9 100644 (file)
@@ -59,7 +59,7 @@ else()
 
     # finally list compilers to try
     if(NOT CMAKE_C_COMPILER_INIT)
-      set(CMAKE_C_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}cc ${_CMAKE_TOOLCHAIN_PREFIX}gcc cl bcc xlc clang)
+      set(CMAKE_C_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}cc ${_CMAKE_TOOLCHAIN_PREFIX}gcc cl bcc xlc icx clang)
     endif()
 
     _cmake_find_compiler(C)
@@ -134,7 +134,8 @@ else()
     # variable but are not aware of CMAKE_C_COMPILER_FRONTEND_VARIANT.
     # They pre-date our support for the GNU-like variant targeting the
     # MSVC ABI so we do not consider that here.
-    if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+    if(CMAKE_C_COMPILER_ID STREQUAL "Clang"
+      OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xIntelLLVM")
       if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
         set(CMAKE_C_COMPILER_FRONTEND_VARIANT "MSVC")
       else()
@@ -161,9 +162,10 @@ if (NOT _CMAKE_TOOLCHAIN_PREFIX)
 
   if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|QCC")
     get_filename_component(COMPILER_BASENAME "${CMAKE_C_COMPILER}" NAME)
-    if (COMPILER_BASENAME MATCHES "^(.+-)(clang|g?cc)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
+    if (COMPILER_BASENAME MATCHES "^(.+-)?(clang|g?cc)(-cl)?(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
       set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
-      set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
+      set(_CMAKE_TOOLCHAIN_SUFFIX ${CMAKE_MATCH_4})
+      set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_6})
     elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
       if(CMAKE_C_COMPILER_TARGET)
         set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_C_COMPILER_TARGET}-)
index 972adef..1ba537a 100644 (file)
@@ -47,6 +47,10 @@ if(NOT $ENV{CUDAHOSTCXX} STREQUAL "")
   endif()
 endif()
 
+if(NOT "$ENV{CUDAARCHS}" STREQUAL "")
+  set(CMAKE_CUDA_ARCHITECTURES "$ENV{CUDAARCHS}" CACHE STRING "CUDA architectures")
+endif()
+
 # Build a small source file to identify the compiler.
 if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
   set(CMAKE_CUDA_COMPILER_ID_RUN 1)
@@ -65,6 +69,10 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
     set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)")
     CMAKE_DETERMINE_COMPILER_ID_VENDOR(CUDA "--version")
 
+    if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang" AND WIN32)
+      message(FATAL_ERROR "Clang with CUDA is not yet supported on Windows. See CMake issue #20776.")
+    endif()
+
     # Find the CUDA toolkit. We store the CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT
     # in CMakeCUDACompiler.cmake, so FindCUDAToolkit can avoid searching on future runs and the toolkit stays the same.
     # This is very similar to FindCUDAToolkit, but somewhat simplified since we can issue fatal errors
@@ -163,15 +171,27 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
         unset(search_paths)
 
         if(NOT _CUDA_NVCC_EXECUTABLE)
-          message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.")
+          message(FATAL_ERROR "Failed to find nvcc.\nCompiler ${CMAKE_CUDA_COMPILER_ID} requires the CUDA toolkit. Please set the CUDAToolkit_ROOT variable.")
         endif()
       endif()
     endif()
 
-    get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY)
-    set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvlink${CMAKE_EXECUTABLE_SUFFIX}")
-    set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/fatbinary${CMAKE_EXECUTABLE_SUFFIX}")
-    get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY)
+    # Given that NVCC can be provided by multiple different sources (NVIDIA HPC SDK, CUDA Toolkit, distro)
+    # each of which has a different layout, we need to extract the CUDA toolkit root from the compiler
+    # itself, allowing us to support numerous different scattered toolkit layouts
+    execute_process(COMMAND ${_CUDA_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda"
+      OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT)
+    if(_CUDA_NVCC_OUT MATCHES "TOP=([^\r\n]*)")
+      get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_MATCH_1}" ABSOLUTE)
+    else()
+      get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY)
+      get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY)
+    endif()
+    unset(_CUDA_NVCC_OUT)
+
+    set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/nvlink${CMAKE_EXECUTABLE_SUFFIX}")
+    set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/fatbinary${CMAKE_EXECUTABLE_SUFFIX}")
+
 
     # In a non-scattered installation the following are equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT.
     # We first check for a non-scattered installation to prefer it over a scattered installation.
@@ -209,10 +229,6 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
       set(CMAKE_CUDA_COMPILER_ID_REQUIRE_SUCCESS ON)
     endif()
   elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
-    if(WIN32)
-      message(FATAL_ERROR "Clang with CUDA is not yet supported on Windows. See CMake issue #20776.")
-    endif()
-
     set(clang_test_flags "--cuda-path=\"${CMAKE_CUDA_COMPILER_LIBRARY_ROOT}\"")
     if(CMAKE_CROSSCOMPILING)
       # Need to pass the host target and include directories if we're crosscompiling.
index 905eb25..fd07a5c 100644 (file)
@@ -58,7 +58,7 @@ else()
 
     # finally list compilers to try
     if(NOT CMAKE_CXX_COMPILER_INIT)
-      set(CMAKE_CXX_COMPILER_LIST CC ${_CMAKE_TOOLCHAIN_PREFIX}c++ ${_CMAKE_TOOLCHAIN_PREFIX}g++ aCC cl bcc xlC clang++)
+      set(CMAKE_CXX_COMPILER_LIST CC ${_CMAKE_TOOLCHAIN_PREFIX}c++ ${_CMAKE_TOOLCHAIN_PREFIX}g++ aCC cl bcc xlC icpx icx clang++)
     endif()
 
     _cmake_find_compiler(CXX)
@@ -131,7 +131,8 @@ else()
     # variable but are not aware of CMAKE_CXX_COMPILER_FRONTEND_VARIANT.
     # They pre-date our support for the GNU-like variant targeting the
     # MSVC ABI so we do not consider that here.
-    if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+    if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
+      OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntelLLVM")
       if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
         set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "MSVC")
       else()
@@ -160,8 +161,9 @@ if (NOT _CMAKE_TOOLCHAIN_PREFIX)
 
   if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|QCC")
     get_filename_component(COMPILER_BASENAME "${CMAKE_CXX_COMPILER}" NAME)
-    if (COMPILER_BASENAME MATCHES "^(.+-)(clan)?[gc]\\+\\+(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
+    if (COMPILER_BASENAME MATCHES "^(.+-)?(clang\\+\\+|g\\+\\+|clang-cl)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$")
       set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1})
+      set(_CMAKE_TOOLCHAIN_SUFFIX ${CMAKE_MATCH_3})
       set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5})
     elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
       if(CMAKE_CXX_COMPILER_TARGET)
index b50e5f1..c03a85f 100644 (file)
@@ -50,6 +50,7 @@ function(cmake_determine_compile_features lang)
     set(CMAKE_CXX14_COMPILE_FEATURES)
     set(CMAKE_CXX17_COMPILE_FEATURES)
     set(CMAKE_CXX20_COMPILE_FEATURES)
+    set(CMAKE_CXX23_COMPILE_FEATURES)
 
     include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
 
@@ -60,6 +61,9 @@ function(cmake_determine_compile_features lang)
       return()
     endif()
 
+    if (CMAKE_CXX20_COMPILE_FEATURES AND CMAKE_CXX23_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_CXX23_COMPILE_FEATURES ${CMAKE_CXX20_COMPILE_FEATURES})
+    endif()
     if (CMAKE_CXX17_COMPILE_FEATURES AND CMAKE_CXX20_COMPILE_FEATURES)
       list(REMOVE_ITEM CMAKE_CXX20_COMPILE_FEATURES ${CMAKE_CXX17_COMPILE_FEATURES})
     endif()
@@ -80,6 +84,7 @@ function(cmake_determine_compile_features lang)
         ${CMAKE_CXX14_COMPILE_FEATURES}
         ${CMAKE_CXX17_COMPILE_FEATURES}
         ${CMAKE_CXX20_COMPILE_FEATURES}
+        ${CMAKE_CXX23_COMPILE_FEATURES}
       )
     endif()
 
@@ -89,6 +94,7 @@ function(cmake_determine_compile_features lang)
     set(CMAKE_CXX14_COMPILE_FEATURES ${CMAKE_CXX14_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CXX17_COMPILE_FEATURES ${CMAKE_CXX17_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CXX20_COMPILE_FEATURES ${CMAKE_CXX20_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CXX23_COMPILE_FEATURES ${CMAKE_CXX23_COMPILE_FEATURES} PARENT_SCOPE)
 
     message(CHECK_PASS "done")
 
@@ -100,6 +106,7 @@ function(cmake_determine_compile_features lang)
     set(CMAKE_CUDA14_COMPILE_FEATURES)
     set(CMAKE_CUDA17_COMPILE_FEATURES)
     set(CMAKE_CUDA20_COMPILE_FEATURES)
+    set(CMAKE_CUDA23_COMPILE_FEATURES)
 
     include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
 
@@ -110,7 +117,10 @@ function(cmake_determine_compile_features lang)
       return()
     endif()
 
-  if (CMAKE_CUDA17_COMPILE_FEATURES AND CMAKE_CUDA20_COMPILE_FEATURES)
+    if (CMAKE_CUDA20_COMPILE_FEATURES AND CMAKE_CUDA23_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_CUDA23_COMPILE_FEATURES ${CMAKE_CUDA20_COMPILE_FEATURES})
+    endif()
+    if (CMAKE_CUDA17_COMPILE_FEATURES AND CMAKE_CUDA20_COMPILE_FEATURES)
       list(REMOVE_ITEM CMAKE_CUDA20_COMPILE_FEATURES ${CMAKE_CUDA17_COMPILE_FEATURES})
     endif()
     if (CMAKE_CUDA14_COMPILE_FEATURES AND CMAKE_CUDA17_COMPILE_FEATURES)
@@ -130,6 +140,7 @@ function(cmake_determine_compile_features lang)
         ${CMAKE_CUDA14_COMPILE_FEATURES}
         ${CMAKE_CUDA17_COMPILE_FEATURES}
         ${CMAKE_CUDA20_COMPILE_FEATURES}
+        ${CMAKE_CUDA23_COMPILE_FEATURES}
       )
     endif()
 
@@ -139,6 +150,7 @@ function(cmake_determine_compile_features lang)
     set(CMAKE_CUDA14_COMPILE_FEATURES ${CMAKE_CUDA14_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CUDA17_COMPILE_FEATURES ${CMAKE_CUDA17_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CUDA20_COMPILE_FEATURES ${CMAKE_CUDA20_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CUDA23_COMPILE_FEATURES ${CMAKE_CUDA23_COMPILE_FEATURES} PARENT_SCOPE)
 
     message(CHECK_PASS "done")
 
index 7e5b375..cf028f1 100644 (file)
@@ -8,6 +8,7 @@
 
 include(${CMAKE_ROOT}/Modules/CMakeParseImplicitIncludeInfo.cmake)
 include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
+include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake)
 include(CMakeTestCompilerCommon)
 
 function(CMAKE_DETERMINE_COMPILER_ABI lang src)
@@ -75,12 +76,25 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
       message(CHECK_PASS "done")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Detecting ${lang} compiler ABI info compiled with the following output:\n${OUTPUT}\n\n")
-      file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 2 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
+      file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 32 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
+      set(ABI_SIZEOF_DPTR "NOTFOUND")
+      set(ABI_BYTE_ORDER "NOTFOUND")
+      set(ABI_NAME "NOTFOUND")
       foreach(info ${ABI_STRINGS})
-        if("${info}" MATCHES "INFO:sizeof_dptr\\[0*([^]]*)\\]")
+        if("${info}" MATCHES "INFO:sizeof_dptr\\[0*([^]]*)\\]" AND NOT ABI_SIZEOF_DPTR)
           set(ABI_SIZEOF_DPTR "${CMAKE_MATCH_1}")
         endif()
-        if("${info}" MATCHES "INFO:abi\\[([^]]*)\\]")
+        if("${info}" MATCHES "INFO:byte_order\\[(BIG_ENDIAN|LITTLE_ENDIAN)\\]")
+          set(byte_order "${CMAKE_MATCH_1}")
+          if(ABI_BYTE_ORDER STREQUAL "NOTFOUND")
+            # Tentatively use the value because this is the first occurrence.
+            set(ABI_BYTE_ORDER "${byte_order}")
+          elseif(NOT ABI_BYTE_ORDER STREQUAL "${byte_order}")
+            # Drop value because multiple occurrences do not match.
+            set(ABI_BYTE_ORDER "")
+          endif()
+        endif()
+        if("${info}" MATCHES "INFO:abi\\[([^]]*)\\]" AND NOT ABI_NAME)
           set(ABI_NAME "${CMAKE_MATCH_1}")
         endif()
       endforeach()
@@ -91,6 +105,10 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
         set(CMAKE_${lang}_SIZEOF_DATA_PTR "${CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT}" PARENT_SCOPE)
       endif()
 
+      if(ABI_BYTE_ORDER)
+        set(CMAKE_${lang}_BYTE_ORDER "${ABI_BYTE_ORDER}" PARENT_SCOPE)
+      endif()
+
       if(ABI_NAME)
         set(CMAKE_${lang}_COMPILER_ABI "${ABI_NAME}" PARENT_SCOPE)
       endif()
@@ -158,27 +176,9 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
       set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE)
       set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE)
 
-      # Detect library architecture directory name.
-      if(CMAKE_LIBRARY_ARCHITECTURE_REGEX)
-        foreach(dir ${implicit_dirs})
-          if("${dir}" MATCHES "/lib/${CMAKE_LIBRARY_ARCHITECTURE_REGEX}$")
-            get_filename_component(arch "${dir}" NAME)
-            set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${arch}" PARENT_SCOPE)
-            break()
-          endif()
-        endforeach()
-      elseif(CMAKE_CXX_COMPILER_ID STREQUAL QCC)
-        foreach(dir ${implicit_dirs})
-          if (dir MATCHES "/lib$")
-            get_filename_component(assumedArchDir "${dir}" DIRECTORY)
-            get_filename_component(archParentDir "${assumedArchDir}" DIRECTORY)
-            if (archParentDir STREQUAL CMAKE_SYSROOT)
-              get_filename_component(archDirName "${assumedArchDir}" NAME)
-              set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${archDirName}" PARENT_SCOPE)
-              break()
-            endif()
-          endif()
-        endforeach()
+      cmake_parse_library_architecture("${implicit_dirs}" architecture_flag)
+      if(architecture_flag)
+        set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${architecture_flag}" PARENT_SCOPE)
       endif()
 
     else()
index 937a120..1595cfd 100644 (file)
@@ -1,6 +1,17 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
+macro(__determine_compiler_id_test testflags_in userflags)
+  separate_arguments(testflags UNIX_COMMAND "${testflags_in}")
+  CMAKE_DETERMINE_COMPILER_ID_BUILD("${lang}" "${testflags}" "${userflags}" "${src}")
+  CMAKE_DETERMINE_COMPILER_ID_MATCH_VENDOR("${lang}" "${COMPILER_${lang}_PRODUCED_OUTPUT}")
+
+  if(NOT CMAKE_${lang}_COMPILER_ID)
+    foreach(file ${COMPILER_${lang}_PRODUCED_FILES})
+      CMAKE_DETERMINE_COMPILER_ID_CHECK("${lang}" "${CMAKE_${lang}_COMPILER_ID_DIR}/${file}" "${src}")
+    endforeach()
+  endif()
+endmacro()
 
 # Function to compile a source file to identify the compiler.  This is
 # used internally by CMake and should not be included by user code.
@@ -24,29 +35,36 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
   # Compute the directory in which to run the test.
   set(CMAKE_${lang}_COMPILER_ID_DIR ${CMAKE_PLATFORM_INFO_DIR}/CompilerId${lang})
 
-  # Try building with no extra flags and then try each set
-  # of helper flags.  Stop when the compiler is identified.
-  foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
-    foreach(testflags ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS_FIRST}
-                      ""
-                      ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS})
-      separate_arguments(testflags UNIX_COMMAND "${testflags}")
-      CMAKE_DETERMINE_COMPILER_ID_BUILD("${lang}" "${testflags}" "${userflags}" "${src}")
-      CMAKE_DETERMINE_COMPILER_ID_MATCH_VENDOR("${lang}" "${COMPILER_${lang}_PRODUCED_OUTPUT}")
+  # If we REQUIRE_SUCCESS, i.e. TEST_FLAGS_FIRST has the correct flags, we still need to
+  # try two combinations: with COMPILER_ID_FLAGS (from user) and without (see issue #21869).
+  if(CMAKE_${lang}_COMPILER_ID_REQUIRE_SUCCESS)
+    # If there COMPILER_ID_FLAGS is empty we can error for the first invocation.
+    if("${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" STREQUAL "")
+      set(__compiler_id_require_success TRUE)
+    endif()
+
+    foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
+      __determine_compiler_id_test("${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS_FIRST}" "${userflags}")
       if(CMAKE_${lang}_COMPILER_ID)
         break()
       endif()
-      foreach(file ${COMPILER_${lang}_PRODUCED_FILES})
-        CMAKE_DETERMINE_COMPILER_ID_CHECK("${lang}" "${CMAKE_${lang}_COMPILER_ID_DIR}/${file}" "${src}")
+      set(__compiler_id_require_success TRUE)
+    endforeach()
+  else()
+    # Try building with no extra flags and then try each set
+    # of helper flags.  Stop when the compiler is identified.
+    foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
+      foreach(testflags ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS_FIRST} "" ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS})
+        __determine_compiler_id_test("${testflags}" "${userflags}")
+        if(CMAKE_${lang}_COMPILER_ID)
+          break()
+        endif()
       endforeach()
       if(CMAKE_${lang}_COMPILER_ID)
         break()
       endif()
     endforeach()
-    if(CMAKE_${lang}_COMPILER_ID)
-      break()
-    endif()
-  endforeach()
+  endif()
 
   # Check if compiler id detection gave us the compiler tool.
   if(CMAKE_${lang}_COMPILER_ID_TOOL)
@@ -152,7 +170,10 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
     set(CMAKE_EXECUTABLE_FORMAT "Unknown" CACHE INTERNAL "Executable file format")
   endif()
 
-  if(CMAKE_GENERATOR MATCHES "^Ninja" AND MSVC_${lang}_ARCHITECTURE_ID)
+  if((CMAKE_GENERATOR MATCHES "^Ninja"
+        OR ((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+          AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"))
+      AND MSVC_${lang}_ARCHITECTURE_ID)
     foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
       CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX(${lang} "${userflags}")
     endforeach()
@@ -161,7 +182,8 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
   endif()
 
   set(_variant "")
-  if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang")
+  if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang"
+    OR "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xIntelLLVM")
     if("x${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "xMSVC")
       if(CMAKE_GENERATOR MATCHES "Visual Studio")
         set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC")
@@ -276,6 +298,16 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
       set(id_cl "$(CLToolExe)")
     elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
       set(id_cl clang.exe)
+    # Executable names have choosen according documentation
+    # URL: (https://software.intel.com/content/www/us/en/develop/documentation/get-started-with-dpcpp-compiler/top.html#top_GUID-A9B4C91D-97AC-450D-9742-9D895BC8AEE1)
+    elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "Intel")
+      if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "DPC\\+\\+ Compiler")
+        set(id_cl dpcpp.exe)
+      elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler 2021")
+        set(id_cl icx.exe)
+      elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "C\\+\\+ Compiler")
+        set(id_cl icl.exe)
+      endif()
     else()
       set(id_cl cl.exe)
     endif()
@@ -310,9 +342,6 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
         set(id_toolset "<NdkToolchainVersion>${CMAKE_VS_PLATFORM_TOOLSET}</NdkToolchainVersion>")
       else()
         set(id_toolset "<PlatformToolset>${CMAKE_VS_PLATFORM_TOOLSET}</PlatformToolset>")
-        if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "Intel")
-          set(id_cl icl.exe)
-        endif()
         if(CMAKE_VS_PLATFORM_TOOLSET_VERSION)
           set(id_sep "\\")
           if(CMAKE_VS_PLATFORM_TOOLSET_VERSION VERSION_GREATER_EQUAL "14.20")
@@ -642,7 +671,7 @@ ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
 
     # Some languages may know the correct/desired set of flags and want to fail right away if they don't work.
     # This is currently only used by CUDA.
-    if(CMAKE_${lang}_COMPILER_ID_REQUIRE_SUCCESS)
+    if(__compiler_id_require_success)
       message(FATAL_ERROR "${MSG}")
     endif()
 
@@ -901,12 +930,17 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
 
 #    # COFF (.exe) files start with "MZ"
 #    if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "4d5a....")
-#      set(CMAKE_EXECUTABLE_FORMAT "COFF" CACHE STRING "Executable file format")
+#      set(CMAKE_EXECUTABLE_FORMAT "COFF" CACHE INTERNAL "Executable file format")
 #    endif()
 #
     # Mach-O files start with MH_MAGIC or MH_CIGAM
     if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface|cefaedfe|feedfacf|cffaedfe")
-      set(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE STRING "Executable file format")
+      set(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE INTERNAL "Executable file format")
+    endif()
+
+    # XCOFF files start with 0x01 followed by 0xDF (32-bit) or 0xF7 (64-bit).
+    if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "^01(df|f7)")
+      set(CMAKE_EXECUTABLE_FORMAT "XCOFF" CACHE INTERNAL "Executable file format")
     endif()
 
   endif()
index 8a57408..d7d032c 100644 (file)
@@ -59,6 +59,8 @@ else()
       #  af77: Apogee F77 compiler for Intergraph hardware running CLIX
       #  epcf90: "Edinburgh Portable Compiler" F90
       #  fort: Compaq (now HP) Fortran 90/95 compiler for Tru64 and Linux/Alpha
+      #  ifx: Intel Fortran LLVM-based compiler
+      #  ifort: Intel Classic Fortran compiler
       #  ifc: Intel Fortran 95 compiler for Linux/x86
       #  efc: Intel Fortran 95 compiler for IA64
       #  nagfor: NAG Fortran compiler
@@ -68,14 +70,14 @@ else()
       #  so if you paid for a compiler it is picked by default.
       if(CMAKE_HOST_WIN32)
         set(CMAKE_Fortran_COMPILER_LIST
-          ifort pgf95 pgfortran lf95 fort
+          ifort ifx pgf95 pgfortran lf95 fort
           flang gfortran gfortran-4 g95 f90 pgf90
           pgf77 g77 f77 nag
           )
       else()
         set(CMAKE_Fortran_COMPILER_LIST
           ftn
-          ifort ifc efc pgf95 pgfortran lf95 xlf95 fort
+          ifort ifc ifx efc pgf95 pgfortran lf95 xlf95 fort
           flang gfortran gfortran-4 g95 f90 pgf90
           frt pgf77 xlf g77 f77 nag
           )
@@ -83,7 +85,7 @@ else()
 
       # Vendor-specific compiler names.
       set(_Fortran_COMPILER_NAMES_GNU       gfortran gfortran-4 g95 g77)
-      set(_Fortran_COMPILER_NAMES_Intel     ifort ifc efc)
+      set(_Fortran_COMPILER_NAMES_Intel     ifort ifc efc ifx)
       set(_Fortran_COMPILER_NAMES_Absoft    af95 af90 af77)
       set(_Fortran_COMPILER_NAMES_PGI       pgf95 pgfortran pgf90 pgf77)
       set(_Fortran_COMPILER_NAMES_Flang     flang)
index 11f4a29..f90301b 100644 (file)
@@ -88,7 +88,7 @@ set(ENV{LANG}        C)
 
 # Now check for C, works for gcc and Intel compiler at least
 if (NOT CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS)
-  if (CMAKE_C_COMPILER_ID MATCHES GNU  OR  CMAKE_C_COMPILER_ID MATCHES Intel  OR  CMAKE_C_COMPILER_ID MATCHES Clang)
+  if (CMAKE_C_COMPILER_ID MATCHES GNU  OR  CMAKE_C_COMPILER_ID MATCHES "Intel"  OR  CMAKE_C_COMPILER_ID MATCHES Clang)
     _DETERMINE_GCC_SYSTEM_INCLUDE_DIRS(c _dirs _defines)
     set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS "${_dirs}" CACHE INTERNAL "C compiler system include directories")
     set(CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS "${_defines}" CACHE INTERNAL "C compiler system defined macros")
@@ -99,7 +99,7 @@ endif ()
 
 # And now the same for C++
 if (NOT CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS)
-  if ("${CMAKE_CXX_COMPILER_ID}" MATCHES GNU  OR  "${CMAKE_CXX_COMPILER_ID}" MATCHES Intel  OR  "${CMAKE_CXX_COMPILER_ID}" MATCHES Clang)
+  if ("${CMAKE_CXX_COMPILER_ID}" MATCHES GNU  OR  "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel"  OR  "${CMAKE_CXX_COMPILER_ID}" MATCHES Clang)
     _DETERMINE_GCC_SYSTEM_INCLUDE_DIRS(c++ _dirs _defines)
     set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS "${_dirs}" CACHE INTERNAL "CXX compiler system include directories")
     set(CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS "${_defines}" CACHE INTERNAL "CXX compiler system defined macros")
index d81fd11..ff178f6 100644 (file)
@@ -70,17 +70,18 @@ if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND
    OR (CMAKE_GENERATOR MATCHES "Visual Studio"
        AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android"))
 
+  set(_CMAKE_LINKER_NAMES "link")
+  set(_CMAKE_AR_NAMES "lib")
+  set(_CMAKE_MT_NAMES "mt")
   if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang")
-    find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm llvm-nm HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-    set(_CMAKE_ADDITIONAL_LINKER_NAMES "lld-link")
-    set(_CMAKE_ADDITIONAL_AR_NAMES "llvm-lib")
+    set(_CMAKE_NM_NAMES "llvm-nm" "nm")
+    list(APPEND _CMAKE_AR_NAMES "lib" "llvm-lib")
+    list(APPEND _CMAKE_MT_NAMES "mt" "llvm-mt")
+    list(APPEND _CMAKE_LINKER_NAMES "lld-link")
+    list(APPEND _CMAKE_TOOL_VARS NM)
   endif()
 
-  find_program(CMAKE_LINKER NAMES ${_CMAKE_ADDITIONAL_LINKER_NAMES} link HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_AR     NAMES ${_CMAKE_ADDITIONAL_AR_NAMES}     lib  HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_MT     NAMES mt   HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-
-  list(APPEND _CMAKE_TOOL_VARS LINKER MT)
+  list(APPEND _CMAKE_TOOL_VARS LINKER MT AR)
 
 # in all other cases search for ar, ranlib, etc.
 else()
@@ -92,55 +93,54 @@ else()
   endif()
 
   if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang)
-    set(_CMAKE_ADDITIONAL_AR_NAMES "llvm-ar")
-    set(_CMAKE_ADDITIONAL_RANLIB_NAMES "llvm-ranlib")
-    set(_CMAKE_ADDITIONAL_STRIP_NAMES "llvm-strip")
     if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC")
-      set(_CMAKE_ADDITIONAL_LINKER_NAMES "lld-link")
+      set(_CMAKE_LINKER_NAMES "lld-link")
     else()
-      set(_CMAKE_ADDITIONAL_LINKER_NAMES "ld.lld")
+      set(_CMAKE_LINKER_NAMES "ld.lld")
     endif()
-    set(_CMAKE_ADDITIONAL_NM_NAMES "llvm-nm")
-    set(_CMAKE_ADDITIONAL_OBJDUMP_NAMES "llvm-objdump")
-    set(_CMAKE_ADDITIONAL_OBJCOPY_NAMES "llvm-objcopy")
-    set(_CMAKE_ADDITIONAL_READELF_NAMES "llvm-readelf")
-    set(_CMAKE_ADDITIONAL_DLLTOOL_NAMES "llvm-dlltool")
-    set(_CMAKE_ADDITIONAL_ADDR2LINE_NAMES "llvm-addr2line")
+    list(APPEND _CMAKE_AR_NAMES "llvm-ar")
+    list(APPEND _CMAKE_NM_NAMES "llvm-nm")
+    list(APPEND _CMAKE_OBJDUMP_NAMES "llvm-objdump")
+    list(APPEND _CMAKE_OBJCOPY_NAMES "llvm-objcopy")
+    list(APPEND _CMAKE_READELF_NAMES "llvm-readelf")
+    list(APPEND _CMAKE_DLLTOOL_NAMES "llvm-dlltool")
+    list(APPEND _CMAKE_ADDR2LINE_NAMES "llvm-addr2line")
   endif()
 
-  if(NOT CMAKE_CROSSCOMPILING AND NOT "${_CMAKE_TOOLCHAIN_PREFIX}" STREQUAL "")
-    list(APPEND _CMAKE_ADDITIONAL_AR_NAMES "ar")
-    list(APPEND _CMAKE_ADDITIONAL_RANLIB_NAMES "ranlib")
-    list(APPEND _CMAKE_ADDITIONAL_STRIP_NAMES "strip")
-    list(APPEND _CMAKE_ADDITIONAL_LINKER_NAMES "ld")
-    list(APPEND _CMAKE_ADDITIONAL_NM_NAMES "nm")
-    list(APPEND _CMAKE_ADDITIONAL_OBJDUMP_NAMES "objdump")
-    list(APPEND _CMAKE_ADDITIONAL_OBJCOPY_NAMES "objcopy")
-    list(APPEND _CMAKE_ADDITIONAL_READELF_NAMES "readelf")
-    list(APPEND _CMAKE_ADDITIONAL_DLLTOOL_NAMES "dlltool")
-    list(APPEND _CMAKE_ADDITIONAL_ADDR2LINE_NAMES "addr2line")
-  endif()
+    list(APPEND _CMAKE_AR_NAMES "ar")
+    list(APPEND _CMAKE_RANLIB_NAMES "ranlib")
+    list(APPEND _CMAKE_STRIP_NAMES "strip")
+    list(APPEND _CMAKE_LINKER_NAMES "ld")
+    list(APPEND _CMAKE_NM_NAMES "nm")
+    list(APPEND _CMAKE_OBJDUMP_NAMES "objdump")
+    list(APPEND _CMAKE_OBJCOPY_NAMES "objcopy")
+    list(APPEND _CMAKE_READELF_NAMES "readelf")
+    list(APPEND _CMAKE_DLLTOOL_NAMES "dlltool")
+    list(APPEND _CMAKE_ADDR2LINE_NAMES "addr2line")
+
+    list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE)
+endif()
 
-  find_program(CMAKE_AR NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ar${_CMAKE_TOOLCHAIN_SUFFIX} ${_CMAKE_ADDITIONAL_AR_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+foreach(TOOL IN LISTS _CMAKE_TOOL_VARS)
+  foreach(NAME IN LISTS _CMAKE_${TOOL}_NAMES)
+    if(NOT _CMAKE_TOOLCHAIN_PREFIX STREQUAL "")
+      if(NOT _CMAKE_TOOLCHAIN_SUFFIX STREQUAL "")
+        list(PREPEND _CMAKE_${TOOL}_NAMES ${NAME}${_CMAKE_TOOLCHAIN_SUFFIX})
+      endif()
+      list(PREPEND _CMAKE_${TOOL}_NAMES ${_CMAKE_TOOLCHAIN_PREFIX}${NAME})
+    endif()
+    if(NOT _CMAKE_TOOLCHAIN_SUFFIX STREQUAL "")
+      list(PREPEND _CMAKE_${TOOL}_NAMES ${_CMAKE_TOOLCHAIN_PREFIX}${NAME}${_CMAKE_TOOLCHAIN_SUFFIX})
+    endif()
+  endforeach()
+  find_program(CMAKE_${TOOL} NAMES ${_CMAKE_${TOOL}_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
+endforeach()
 
-  find_program(CMAKE_RANLIB NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ranlib ${_CMAKE_ADDITIONAL_RANLIB_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  if(NOT CMAKE_RANLIB)
+if(NOT CMAKE_RANLIB)
     set(CMAKE_RANLIB : CACHE INTERNAL "noop for ranlib")
-  endif()
-
-
-  find_program(CMAKE_STRIP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}strip${_CMAKE_TOOLCHAIN_SUFFIX} ${_CMAKE_ADDITIONAL_STRIP_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_LINKER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ld ${_CMAKE_ADDITIONAL_LINKER_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm ${_CMAKE_ADDITIONAL_NM_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_OBJDUMP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objdump ${_CMAKE_ADDITIONAL_OBJDUMP_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_OBJCOPY NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objcopy ${_CMAKE_ADDITIONAL_OBJCOPY_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_READELF NAMES ${_CMAKE_TOOLCHAIN_PREFIX}readelf ${_CMAKE_ADDITIONAL_READELF_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_DLLTOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}dlltool ${_CMAKE_ADDITIONAL_DLLTOOL_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-  find_program(CMAKE_ADDR2LINE NAMES ${_CMAKE_TOOLCHAIN_PREFIX}addr2line ${_CMAKE_ADDITIONAL_ADDR2LINE_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
-
-  list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE)
 endif()
 
+
 if(CMAKE_PLATFORM_HAS_INSTALLNAME)
   find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
 
@@ -157,7 +157,7 @@ foreach(var IN LISTS _CMAKE_TOOL_VARS)
   if(_CMAKE_TOOL_CACHED)
     mark_as_advanced(CMAKE_${var})
   endif()
-  unset(_CMAKE_ADDITIONAL_${var}_NAMES)
+  unset(_CMAKE_${var}_NAMES)
 endforeach()
 unset(_CMAKE_TOOL_VARS)
 unset(_CMAKE_TOOL_CACHED)
index 6b51e38..0a3db4c 100644 (file)
        PRINT *, 'INFO:simulate_version[013.00]'
 # endif
 #endif
-#if defined(__INTEL_COMPILER) || defined(__ICC)
+#if defined(__INTEL_LLVM_COMPILER)
+        PRINT *, 'INFO:compiler[IntelLLVM]'
+! __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
+! later.  Look for 6 digit vs. 8 digit version number to decide encoding.
+! VVVV is no smaller than the current year when a versio is released.
+# if __INTEL_LLVM_COMPILER < 1000000
+#  define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)
+#  define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)
+#  define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER    % 10)
+# else
+#  define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)
+#  define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)
+#  define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER     % 100)
+# endif
+#elif defined(__INTEL_COMPILER) || defined(__ICC)
         PRINT *, 'INFO:compiler[Intel]'
 # define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)
 # define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)
 #  define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10)
 #  define COMPILER_VERSION_PATCH DEC(__IBMC__    % 10)
 # endif
+#elif defined(__NVCOMPILER) || defined(__NVCOMPILER_LLVM__)
+        PRINT *, 'INFO:compiler[NVHPC]'
+# if defined(__NVCOMPILER_MAJOR__)
+#  define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)
+# else
+#  define COMPILER_VERSION_MAJOR DEC(__PGIC__)
+# endif
+# if defined(__NVCOMPILER_MINOR__)
+#  define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)
+# else
+#  define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)
+# endif
+# if defined(__NVCOMPILER_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)
+# elif defined(__PGIC_PATCHLEVEL__)
+#  define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)
+# endif
 #elif defined(__PGI)
         PRINT *, 'INFO:compiler[PGI]'
 # define COMPILER_VERSION_MAJOR DEC(__PGIC__)
index be4a3be..7086722 100644 (file)
@@ -29,8 +29,9 @@ Graphviz package:
 
   dot -Tpng -o foo.png foo.dot
 
-The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE``
-are represented as solid, dashed and dotted edges.
+.. versionadded:: 3.10
+  The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE``
+  are represented as solid, dashed and dotted edges.
 
 Variables specific to the Graphviz support
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 1555517..608adce 100644 (file)
@@ -45,6 +45,7 @@ endforeach()
 # Save compiler ABI information.
 set(CMAKE_OBJC_SIZEOF_DATA_PTR "@CMAKE_OBJC_SIZEOF_DATA_PTR@")
 set(CMAKE_OBJC_COMPILER_ABI "@CMAKE_OBJC_COMPILER_ABI@")
+set(CMAKE_OBJC_BYTE_ORDER "@CMAKE_OBJC_BYTE_ORDER@")
 set(CMAKE_OBJC_LIBRARY_ARCHITECTURE "@CMAKE_OBJC_LIBRARY_ARCHITECTURE@")
 
 if(CMAKE_OBJC_SIZEOF_DATA_PTR)
index 8fa8511..0726cd3 100644 (file)
@@ -12,6 +12,8 @@ int main(int argc, char *argv[])
 {
   int require = 0;
   require += info_sizeof_dptr[argc];
+  require += info_byte_order_big_endian[argc];
+  require += info_byte_order_little_endian[argc];
 #if defined(ABI_ID)
   require += info_abi[argc];
 #endif
index b6452c4..a24582b 100644 (file)
@@ -11,6 +11,7 @@ set(CMAKE_OBJCXX11_COMPILE_FEATURES "@CMAKE_OBJCXX11_COMPILE_FEATURES@")
 set(CMAKE_OBJCXX14_COMPILE_FEATURES "@CMAKE_OBJCXX14_COMPILE_FEATURES@")
 set(CMAKE_OBJCXX17_COMPILE_FEATURES "@CMAKE_OBJCXX17_COMPILE_FEATURES@")
 set(CMAKE_OBJCXX20_COMPILE_FEATURES "@CMAKE_OBJCXX20_COMPILE_FEATURES@")
+set(CMAKE_OBJCXX23_COMPILE_FEATURES "@CMAKE_OBJCXX23_COMPILE_FEATURES@")
 
 set(CMAKE_OBJCXX_PLATFORM_ID "@CMAKE_OBJCXX_PLATFORM_ID@")
 set(CMAKE_OBJCXX_SIMULATE_ID "@CMAKE_OBJCXX_SIMULATE_ID@")
@@ -55,6 +56,7 @@ set(CMAKE_OBJCXX_LINKER_PREFERENCE_PROPAGATES 1)
 # Save compiler ABI information.
 set(CMAKE_OBJCXX_SIZEOF_DATA_PTR "@CMAKE_OBJCXX_SIZEOF_DATA_PTR@")
 set(CMAKE_OBJCXX_COMPILER_ABI "@CMAKE_OBJCXX_COMPILER_ABI@")
+set(CMAKE_OBJCXX_BYTE_ORDER "@CMAKE_OBJCXX_BYTE_ORDER@")
 set(CMAKE_OBJCXX_LIBRARY_ARCHITECTURE "@CMAKE_OBJCXX_LIBRARY_ARCHITECTURE@")
 
 if(CMAKE_OBJCXX_SIZEOF_DATA_PTR)
index 288a58c..7b9fefc 100644 (file)
@@ -12,6 +12,8 @@ int main(int argc, char *argv[])
 {
   int require = 0;
   require += info_sizeof_dptr[argc];
+  require += info_byte_order_big_endian[argc];
+  require += info_byte_order_little_endian[argc];
 #if defined(ABI_ID)
   require += info_abi[argc];
 #endif
index fe04de1..e2ac35d 100644 (file)
@@ -30,7 +30,9 @@ char const* qnxnto = "INFO" ":" "qnxnto[]";
 #endif
 
 const char* info_language_dialect_default = "INFO" ":" "dialect_default["
-#if CXX_STD > 201703L
+#if CXX_STD > 202002L
+  "23"
+#elfif CXX_STD > 201703L
   "20"
 #elif CXX_STD >= 201703L
   "17"
index 36f2f7f..ad719ef 100644 (file)
@@ -81,13 +81,14 @@ always relative to the installed location of the package.  This works both for
 relative and also for absolute locations.  For absolute locations it works
 only if the absolute location is a subdirectory of ``INSTALL_PREFIX``.
 
-If the ``INSTALL_PREFIX`` argument is passed, this is used as base path to
-calculate all the relative paths.  The ``<path>`` argument must be an absolute
-path.  If this argument is not passed, the :variable:`CMAKE_INSTALL_PREFIX`
-variable will be used instead.  The default value is good when generating a
-FooConfig.cmake file to use your package from the install tree.  When
-generating a FooConfig.cmake file to use your package from the build tree this
-option should be used.
+.. versionadded:: 3.1
+  If the ``INSTALL_PREFIX`` argument is passed, this is used as base path to
+  calculate all the relative paths.  The ``<path>`` argument must be an absolute
+  path.  If this argument is not passed, the :variable:`CMAKE_INSTALL_PREFIX`
+  variable will be used instead.  The default value is good when generating a
+  FooConfig.cmake file to use your package from the install tree.  When
+  generating a FooConfig.cmake file to use your package from the build tree this
+  option should be used.
 
 By default ``configure_package_config_file`` also generates two helper macros,
 ``set_and_check()`` and ``check_required_components()`` into the
@@ -159,23 +160,28 @@ If your project has more elaborated version matching rules, you will need to
 write your own custom ``ConfigVersion.cmake`` file instead of using this
 macro.
 
-.. note:: ``COMPATIBILITY_MODE`` ``AnyNewerVersion``, ``SameMajorVersion`` and
-  ``SameMinorVersion`` handle the version range if any is specified (see
-  :command:`find_package` command for the details). ``ExactVersion`` is
-  incompatible with version ranges and will display an author warning if one is
-  specified.
-
-If ``ARCH_INDEPENDENT`` is given, the installed package version will be
-considered compatible even if it was built for a different architecture than
-the requested architecture.  Otherwise, an architecture check will be performed,
-and the package will be considered compatible only if the architecture matches
-exactly.  For example, if the package is built for a 32-bit architecture, the
-package is only considered compatible if it is used on a 32-bit architecture,
-unless ``ARCH_INDEPENDENT`` is given, in which case the package is considered
-compatible on any architecture.
+.. versionadded:: 3.11
+  The ``SameMinorVersion`` compatibility mode.
+
+.. versionadded:: 3.14
+  If ``ARCH_INDEPENDENT`` is given, the installed package version will be
+  considered compatible even if it was built for a different architecture than
+  the requested architecture.  Otherwise, an architecture check will be performed,
+  and the package will be considered compatible only if the architecture matches
+  exactly.  For example, if the package is built for a 32-bit architecture, the
+  package is only considered compatible if it is used on a 32-bit architecture,
+  unless ``ARCH_INDEPENDENT`` is given, in which case the package is considered
+  compatible on any architecture.
 
 .. note:: ``ARCH_INDEPENDENT`` is intended for header-only libraries or similar
-   packages with no binaries.
+  packages with no binaries.
+
+.. versionadded:: 3.19
+  ``COMPATIBILITY_MODE`` ``AnyNewerVersion``, ``SameMajorVersion`` and
+  ``SameMinorVersion`` handle the version range if any is specified
+  (see :command:`find_package` command for the details).
+  ``ExactVersion`` mode is incompatible with version ranges and will display an
+  author warning if one is specified.
 
 Internally, this macro executes :command:`configure_file()` to create the
 resulting version file.  Depending on the ``COMPATIBILITY``, the corresponding
diff --git a/Modules/CMakeParseLibraryArchitecture.cmake b/Modules/CMakeParseLibraryArchitecture.cmake
new file mode 100644 (file)
index 0000000..aa6fd74
--- /dev/null
@@ -0,0 +1,56 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0053 NEW)
+cmake_policy(SET CMP0054 NEW)
+
+# Function parse implicit linker options.
+# This is used internally by CMake and should not be included by user
+# code.
+
+function(cmake_parse_library_architecture implicit_dirs output_var)
+  unset(library_arch)
+  # Detect library architecture directory name.
+  if(CMAKE_LIBRARY_ARCHITECTURE_REGEX)
+    foreach(dir ${implicit_dirs})
+      if("${dir}" MATCHES "/lib/${CMAKE_LIBRARY_ARCHITECTURE_REGEX}$")
+        get_filename_component(arch "${dir}" NAME)
+        set(library_arch "${arch}")
+        break()
+      endif()
+    endforeach()
+  endif()
+
+  if(CMAKE_LIBRARY_ARCHITECTURE_REGEX_VERSIONED AND NOT library_arch)
+    foreach(dir ${implicit_dirs})
+      if("${dir}" MATCHES "/${CMAKE_LIBRARY_ARCHITECTURE_REGEX_VERSIONED}$")
+        get_filename_component(arch "${dir}" DIRECTORY)
+        get_filename_component(arch "${arch}" NAME)
+        set(library_arch "${arch}")
+        break()
+      endif()
+    endforeach()
+  endif()
+
+  if(CMAKE_CXX_COMPILER_ID STREQUAL QCC)
+    foreach(dir ${implicit_dirs})
+      if (dir MATCHES "/lib$")
+        get_filename_component(assumedArchDir "${dir}" DIRECTORY)
+        get_filename_component(archParentDir "${assumedArchDir}" DIRECTORY)
+        if (archParentDir STREQUAL CMAKE_SYSROOT)
+          get_filename_component(archDirName "${assumedArchDir}" NAME)
+          set(library_arch "${archDirName}")
+          break()
+        endif()
+      endif()
+    endforeach()
+  endif()
+
+  # Return results.
+  if(library_arch)
+    set(${output_var} "${library_arch}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+cmake_policy(POP)
index 0b81c88..1dc12c0 100644 (file)
 # if defined(_M_IA64)
 #  define ARCHITECTURE_ID "IA64"
 
+# elif defined(_M_ARM64EC)
+#  define ARCHITECTURE_ID "ARM64EC"
+
 # elif defined(_M_X64) || defined(_M_AMD64)
 #  define ARCHITECTURE_ID "x64"
 
 # elif defined(__ICC8051__)
 #  define ARCHITECTURE_ID "8051"
 
+# elif defined(__ICCSTM8__)
+#  define ARCHITECTURE_ID "STM8"
+
 # else /* unknown architecture */
 #  define ARCHITECTURE_ID ""
 # endif
index 933e5a2..7dcafde 100644 (file)
@@ -1,4 +1,5 @@
-#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+#if defined(__GNUC__) &&                                                      \
+  !(defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER))
 void THIS_IS_GNU();
 #endif
 #ifdef __MINGW32__
index 7529a1f..ef5a7d5 100644 (file)
@@ -194,6 +194,8 @@ installers.  The most commonly-used variables are:
 
 .. variable:: CPACK_PACKAGE_CHECKSUM
 
+  .. versionadded:: 3.7
+
   An algorithm that will be used to generate an additional file with the
   checksum of the package.  The output file name will be::
 
@@ -271,6 +273,8 @@ installers.  The most commonly-used variables are:
 
 .. variable:: CPACK_VERBATIM_VARIABLES
 
+  .. versionadded:: 3.4
+
   If set to ``TRUE``, values of variables prefixed with ``CPACK_`` will be
   escaped before being written to the configuration files, so that the cpack
   program receives them exactly as they were specified.  If not, characters
@@ -278,6 +282,28 @@ installers.  The most commonly-used variables are:
   received by the cpack program.  Defaults to ``FALSE`` for backwards
   compatibility.
 
+.. variable:: CPACK_THREADS
+
+  .. versionadded:: 3.20
+
+  Number of threads to use when performing parallelized operations, such
+  as compressing the installer package.
+
+  Some compression methods used by CPack generators such as Debian or Archive
+  may take advantage of multiple CPU cores to speed up compression.
+  ``CPACK_THREADS`` can be set to positive integer to specify how many threads
+  will be used for compression. If it is set to 0, CPack will set it so that
+  all available CPU cores are used.
+  By default ``CPACK_THREADS`` is set to ``1``.
+
+  Currently only ``xz`` compression *may* take advantage of multiple cores. Other
+  compression methods ignore this value and use only one thread.
+
+  .. note::
+
+     Official CMake binaries available on ``cmake.org`` ship with a ``liblzma``
+     that does not support parallel compression.
+
 Variables for Source Package Generators
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -356,6 +382,8 @@ The following variables are for advanced uses of CPack:
 
 .. variable:: CPACK_INSTALL_SCRIPTS
 
+  .. versionadded:: 3.16
+
   Extra CMake scripts executed by CPack during its local staging
   installation.  They are executed before installing the files to be packaged.
   The scripts are not called by a standalone install (e.g.: ``make install``).
@@ -372,6 +400,8 @@ The following variables are for advanced uses of CPack:
 
 .. variable:: CPACK_PRE_BUILD_SCRIPTS
 
+  .. versionadded:: 3.19
+
   List of CMake scripts to execute after CPack has installed the files to
   be packaged into a staging directory and before producing the package(s)
   from those files. See also :variable:`CPACK_INSTALL_SCRIPTS` and
@@ -379,6 +409,8 @@ The following variables are for advanced uses of CPack:
 
 .. variable:: CPACK_POST_BUILD_SCRIPTS
 
+  .. versionadded:: 3.19
+
   List of CMake scripts to execute after CPack has produced the resultant
   packages and before copying them back to the build directory.
   See also :variable:`CPACK_INSTALL_SCRIPTS`,
@@ -386,6 +418,8 @@ The following variables are for advanced uses of CPack:
 
 .. variable:: CPACK_PACKAGE_FILES
 
+  .. versionadded:: 3.19
+
   List of package files created in the staging directory, with each file
   provided as a full absolute path.  This variable is populated by CPack
   just before invoking the post-build scripts listed in
@@ -734,6 +768,7 @@ _cpack_set_default(CPACK_INSTALL_CMAKE_PROJECTS
   "${CMAKE_BINARY_DIR};${CMAKE_PROJECT_NAME};ALL;/")
 _cpack_set_default(CPACK_CMAKE_GENERATOR "${CMAKE_GENERATOR}")
 _cpack_set_default(CPACK_TOPLEVEL_TAG "${CPACK_SYSTEM_NAME}")
+_cpack_set_default(CPACK_THREADS 1)
 # if the user has set CPACK_NSIS_DISPLAY_NAME remember it
 if(DEFINED CPACK_NSIS_DISPLAY_NAME)
   set(CPACK_NSIS_DISPLAY_NAME_SET TRUE)
index 6ce0bfc..d57cf18 100644 (file)
@@ -51,20 +51,28 @@ The module defines the following commands:
     of a group to which it belongs.
 
   ``ESSENTIAL``
+    .. versionadded:: 3.6
+
     if set, then the package manager stays disabled until that
     component is updated.
 
   ``VIRTUAL``
+    .. versionadded:: 3.8
+
     if set, then the component will be hidden from the installer.
     It is a equivalent of the ``HIDDEN`` option from the
     :command:`cpack_add_component` command.
 
   ``FORCED_INSTALLATION``
+    .. versionadded:: 3.8
+
     if set, then the component must always be installed.
     It is a equivalent of the ``REQUIRED`` option from the
     :command:`cpack_add_component` command.
 
   ``REQUIRES_ADMIN_RIGHTS``
+    .. versionadded:: 3.8
+
     set it if the component needs to be installed with elevated permissions.
 
   ``NAME``
@@ -72,14 +80,20 @@ The module defines the following commands:
     By default used origin component name.
 
   ``DISPLAY_NAME``
+    .. versionadded:: 3.8
+
     set to rewrite original name configured by
     :command:`cpack_add_component` command.
 
   ``DESCRIPTION``
+    .. versionadded:: 3.8
+
     set to rewrite original description configured by
     :command:`cpack_add_component` command.
 
   ``UPDATE_TEXT``
+    .. versionadded:: 3.8
+
     will be added to the component description if this is an update to
     the component.
 
@@ -88,22 +102,32 @@ The module defines the following commands:
     By default used :variable:`CPACK_PACKAGE_VERSION`.
 
   ``RELEASE_DATE``
+    .. versionadded:: 3.8
+
     keep empty to auto generate.
 
   ``SCRIPT``
     is a relative or absolute path to operations script
     for this component.
 
-  ``PRIORITY`` | ``SORTING_PRIORITY``
+  ``SORTING_PRIORITY``
+    .. versionadded:: 3.8
+
     is priority of the component in the tree.
-    The ``PRIORITY`` option is deprecated and will be removed in a future
-    version of CMake. Please use ``SORTING_PRIORITY`` option instead.
 
-  ``DEPENDS`` | ``DEPENDENCIES``
+  ``PRIORITY``
+    .. deprecated:: 3.8
+      Old name for ``SORTING_PRIORITY``.
+
+  ``DEPENDS``, ``DEPENDENCIES``
+    .. versionadded:: 3.8
+
     list of dependency component or component group identifiers in
     QtIFW style.
 
   ``AUTO_DEPEND_ON``
+    .. versionadded:: 3.8
+
     list of identifiers of component or component group in QtIFW style
     that this component has an automatic dependency on.
 
@@ -112,21 +136,31 @@ The module defines the following commands:
     component. You can specify more then one license.
 
   ``DEFAULT``
+    .. versionadded:: 3.8
+
     Possible values are: TRUE, FALSE, and SCRIPT.
     Set to FALSE to disable the component in the installer or to SCRIPT
     to resolved during runtime (don't forget add the file of the script
     as a value of the ``SCRIPT`` option).
 
   ``USER_INTERFACES``
+    .. versionadded:: 3.7
+
     is a list of <file_path> ('.ui' files) representing pages to load.
 
   ``TRANSLATIONS``
+    .. versionadded:: 3.8
+
     is a list of <file_path> ('.qm' files) representing translations to load.
 
   ``REPLACES``
+    .. versionadded:: 3.10
+
     list of identifiers of component or component group to replace.
 
   ``CHECKABLE``
+    .. versionadded:: 3.10
+
     Possible values are: TRUE, FALSE.
     Set to FALSE if you want to hide the checkbox for an item.
     This is useful when only a few subcomponents should be selected
@@ -162,13 +196,19 @@ The module defines the following commands:
   command.
 
   ``VIRTUAL``
+    .. versionadded:: 3.8
+
     if set, then the group will be hidden from the installer.
     Note that setting this on a root component does not work.
 
   ``FORCED_INSTALLATION``
+    .. versionadded:: 3.8
+
     if set, then the group must always be installed.
 
   ``REQUIRES_ADMIN_RIGHTS``
+    .. versionadded:: 3.8
+
     set it if the component group needs to be installed with elevated
     permissions.
 
@@ -177,14 +217,20 @@ The module defines the following commands:
     By default used origin component group name.
 
   ``DISPLAY_NAME``
+    .. versionadded:: 3.8
+
     set to rewrite original name configured by
     :command:`cpack_add_component_group` command.
 
   ``DESCRIPTION``
+    .. versionadded:: 3.8
+
     set to rewrite original description configured by
     :command:`cpack_add_component_group` command.
 
   ``UPDATE_TEXT``
+    .. versionadded:: 3.8
+
     will be added to the component group description if this is an update to
     the component group.
 
@@ -193,22 +239,30 @@ The module defines the following commands:
     By default used :variable:`CPACK_PACKAGE_VERSION`.
 
   ``RELEASE_DATE``
+    .. versionadded:: 3.8
+
     keep empty to auto generate.
 
   ``SCRIPT``
     is a relative or absolute path to operations script
     for this component group.
 
-  ``PRIORITY`` | ``SORTING_PRIORITY``
+  ``SORTING_PRIORITY``
     is priority of the component group in the tree.
-    The ``PRIORITY`` option is deprecated and will be removed in a future
-    version of CMake. Please use ``SORTING_PRIORITY`` option instead.
 
-  ``DEPENDS`` | ``DEPENDENCIES``
+  ``PRIORITY``
+    .. deprecated:: 3.8
+      Old name for ``SORTING_PRIORITY``.
+
+  ``DEPENDS``, ``DEPENDENCIES``
+    .. versionadded:: 3.8
+
     list of dependency component or component group identifiers in
     QtIFW style.
 
   ``AUTO_DEPEND_ON``
+    .. versionadded:: 3.8
+
     list of identifiers of component or component group in QtIFW style
     that this component group has an automatic dependency on.
 
@@ -217,6 +271,8 @@ The module defines the following commands:
     component group. You can specify more then one license.
 
   ``DEFAULT``
+    .. versionadded:: 3.8
+
     Possible values are: TRUE, FALSE, and SCRIPT.
     Set to TRUE to preselect the group in the installer
     (this takes effect only on groups that have no visible child components)
@@ -224,15 +280,23 @@ The module defines the following commands:
     the script as a value of the ``SCRIPT`` option).
 
   ``USER_INTERFACES``
+    .. versionadded:: 3.7
+
     is a list of <file_path> ('.ui' files) representing pages to load.
 
   ``TRANSLATIONS``
+    .. versionadded:: 3.8
+
     is a list of <file_path> ('.qm' files) representing translations to load.
 
   ``REPLACES``
+    .. versionadded:: 3.10
+
     list of identifiers of component or component group to replace.
 
   ``CHECKABLE``
+    .. versionadded:: 3.10
+
     Possible values are: TRUE, FALSE.
     Set to FALSE if you want to hide the checkbox for an item.
     This is useful when only a few subcomponents should be selected
@@ -272,6 +336,8 @@ The module defines the following commands:
 
 .. command:: cpack_ifw_update_repository
 
+  .. versionadded:: 3.6
+
   Update QtIFW specific repository from remote repository.
 
   ::
@@ -307,6 +373,8 @@ The module defines the following commands:
 
 .. command:: cpack_ifw_add_package_resources
 
+  .. versionadded:: 3.7
+
   Add additional resources in the installer binary.
 
   ::
index 8265bd2..8f8ebb4 100644 (file)
@@ -121,15 +121,6 @@ if(BUILD_TESTING)
     string(APPEND SUBMIT_URL "${DROP_SITE}${DROP_LOCATION}")
   endif()
 
-  find_program(CVSCOMMAND cvs )
-  set(CVS_UPDATE_OPTIONS "-d -A -P" CACHE STRING
-    "Options passed to the cvs update command.")
-  find_program(SVNCOMMAND svn)
-  find_program(BZRCOMMAND bzr)
-  find_program(HGCOMMAND hg)
-  find_program(GITCOMMAND git)
-  find_program(P4COMMAND p4)
-
   if(NOT UPDATE_TYPE)
     if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CVS")
       set(UPDATE_TYPE cvs)
@@ -146,21 +137,29 @@ if(BUILD_TESTING)
 
   string(TOLOWER "${UPDATE_TYPE}" _update_type)
   if("${_update_type}" STREQUAL "cvs")
+    find_program(CVSCOMMAND cvs )
+    set(CVS_UPDATE_OPTIONS "-d -A -P" CACHE STRING
+      "Options passed to the cvs update command.")
     set(UPDATE_COMMAND "${CVSCOMMAND}")
     set(UPDATE_OPTIONS "${CVS_UPDATE_OPTIONS}")
   elseif("${_update_type}" STREQUAL "svn")
+    find_program(SVNCOMMAND svn)
     set(UPDATE_COMMAND "${SVNCOMMAND}")
     set(UPDATE_OPTIONS "${SVN_UPDATE_OPTIONS}")
   elseif("${_update_type}" STREQUAL "bzr")
+    find_program(BZRCOMMAND bzr)
     set(UPDATE_COMMAND "${BZRCOMMAND}")
     set(UPDATE_OPTIONS "${BZR_UPDATE_OPTIONS}")
   elseif("${_update_type}" STREQUAL "hg")
+    find_program(HGCOMMAND hg)
     set(UPDATE_COMMAND "${HGCOMMAND}")
     set(UPDATE_OPTIONS "${HG_UPDATE_OPTIONS}")
   elseif("${_update_type}" STREQUAL "git")
+    find_program(GITCOMMAND git)
     set(UPDATE_COMMAND "${GITCOMMAND}")
     set(UPDATE_OPTIONS "${GIT_UPDATE_OPTIONS}")
   elseif("${_update_type}" STREQUAL "p4")
+    find_program(P4COMMAND p4)
     set(UPDATE_COMMAND "${P4COMMAND}")
     set(UPDATE_OPTIONS "${P4_UPDATE_OPTIONS}")
   endif()
@@ -179,12 +178,6 @@ if(BUILD_TESTING)
     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Rational Software\\Purify\\Setup;InstallFolder]"
     DOC "Path to the memory checking command, used for memory error detection."
     )
-  find_program(SLURM_SBATCH_COMMAND sbatch DOC
-    "Path to the SLURM sbatch executable"
-    )
-  find_program(SLURM_SRUN_COMMAND srun DOC
-    "Path to the SLURM srun executable"
-    )
   set(MEMORYCHECK_SUPPRESSIONS_FILE "" CACHE FILEPATH
     "File that contains suppressions for the memory checker")
   find_program(COVERAGE_COMMAND gcov DOC
@@ -194,7 +187,14 @@ if(BUILD_TESTING)
     "Extra command line flags to pass to the coverage tool")
 
   # set the site name
-  site_name(SITE)
+  if(COMMAND cmake_host_system_information)
+    cmake_host_system_information(RESULT _ctest_hostname QUERY HOSTNAME)
+    set(SITE "${_ctest_hostname}" CACHE STRING "Name of the computer/site where compile is being run")
+    unset(_ctest_hostname)
+  else()
+    # This code path is needed for CMake itself during bootstrap.
+    site_name(SITE)
+  endif()
   # set the build name
   if(NOT BUILDNAME)
     set(DART_COMPILER "${CMAKE_CXX_COMPILER}")
@@ -256,8 +256,6 @@ if(BUILD_TESTING)
     MAKECOMMAND
     MEMORYCHECK_COMMAND
     MEMORYCHECK_SUPPRESSIONS_FILE
-    SLURM_SBATCH_COMMAND
-    SLURM_SRUN_COMMAND
     SITE
     SVNCOMMAND
     )
index a01a2fe..a6fa3a4 100644 (file)
@@ -39,7 +39,10 @@ After generating this tar file, it can be sent to CDash for display with the
     upload to CDash.  Relative paths will be interpreted with respect
     to the top-level build directory.
 
-  ``TARBALL_COMPRESSION <option>`` Specify a compression algorithm for the
+  ``TARBALL_COMPRESSION <option>``
+    .. versionadded:: 3.18
+
+    Specify a compression algorithm for the
     ``TARBALL`` data file.  Using this option reduces the size of the data file
     before it is submitted to CDash.  ``<option>`` must be one of ``GZIP``,
     ``BZIP2``, ``XZ``, ``ZSTD``, ``FROM_EXT``, or an expression that CMake
@@ -68,15 +71,23 @@ After generating this tar file, it can be sent to CDash for display with the
     If not specified, the default option is just ``-b -x``.
 
   ``GLOB``
+    .. versionadded:: 3.6
+
     Recursively search for .gcda files in build_dir rather than
     determining search locations by reading TargetDirectories.txt.
 
   ``DELETE``
+    .. versionadded:: 3.6
+
     Delete coverage files after they've been packaged into the .tar.
 
   ``QUIET``
     Suppress non-error messages that otherwise would have been
     printed out by this function.
+
+  .. versionadded:: 3.3
+    Added support for the :variable:`CTEST_CUSTOM_COVERAGE_EXCLUDE` variable.
+
 #]=======================================================================]
 
 function(ctest_coverage_collect_gcov)
index 3dff926..23a206b 100644 (file)
@@ -24,9 +24,12 @@ long as your CMakeLists uses include(CTest) or
 include(CTestUseLaunchers), it will use the value of the ENV variable
 to initialize a CTEST_USE_LAUNCHERS cache variable.  This cache
 variable initialization only occurs if CTEST_USE_LAUNCHERS is not
-already defined. If CTEST_USE_LAUNCHERS is on in a ctest -S script
-the ctest_configure command will add -DCTEST_USE_LAUNCHERS:BOOL=TRUE
-to the cmake command used to configure the project.
+already defined.
+
+.. versionadded:: 3.8
+  If CTEST_USE_LAUNCHERS is on in a ctest -S script
+  the ctest_configure command will add -DCTEST_USE_LAUNCHERS:BOOL=TRUE
+  to the cmake command used to configure the project.
 #]=======================================================================]
 
 if(NOT DEFINED CTEST_USE_LAUNCHERS AND DEFINED ENV{CTEST_USE_LAUNCHERS_DEFAULT})
index 698a007..b24da49 100644 (file)
@@ -44,6 +44,8 @@ Check if given C source compiles and links into an executable.
     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).
 
@@ -54,6 +56,8 @@ Check if given C source compiles and links into an executable.
     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.
 
index a99e47e..a6081ff 100644 (file)
@@ -43,6 +43,8 @@ subsequently be run.
     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).
 
@@ -53,6 +55,8 @@ subsequently be run.
     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.
 
index dc209b2..502bfa7 100644 (file)
@@ -44,6 +44,8 @@ Check if given C++ source compiles and links into an executable.
     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).
 
@@ -54,6 +56,8 @@ Check if given C++ source compiles and links into an executable.
     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.
 
index c8ff3d7..af03453 100644 (file)
@@ -43,6 +43,8 @@ subsequently be run.
     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).
 
@@ -53,6 +55,8 @@ subsequently be run.
     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.
 
index 5c9079d..b4da4fa 100644 (file)
@@ -49,12 +49,14 @@ the way the check is run:
   a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
   the compiler.
 ``CMAKE_REQUIRED_LINK_OPTIONS``
-  a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+  .. 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``
-  execute quietly without messages.
+  .. versionadded:: 3.1
+    execute quietly without messages.
 
 For example:
 
index d06203f..ad72e2f 100644 (file)
@@ -24,8 +24,9 @@ The following variables may be set before calling this macro to modify
 the way the check is run:
 
 ``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).
+  .. 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
index 5ede284..e134329 100644 (file)
@@ -65,6 +65,8 @@ Check if given Fortran source compiles and links into an executable.
     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).
 
index 136da89..9efa132 100644 (file)
@@ -28,12 +28,14 @@ way the check is run:
   a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
   the compiler.
 ``CMAKE_REQUIRED_LINK_OPTIONS``
-  a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+  .. 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``
-  execute quietly without messages.
+  .. versionadded:: 3.1
+    execute quietly without messages.
 
 .. note::
 
index 1dd951d..0bc3c92 100644 (file)
@@ -33,6 +33,9 @@ property.
 It makes no sense to use this module when :policy:`CMP0069` is set to ``OLD`` so
 module will return error in this case. See policy :policy:`CMP0069` for details.
 
+.. versionadded:: 3.13
+  Add support for Visual Studio generators.
+
 Examples
 ^^^^^^^^
 
index 3a10473..71ddde7 100644 (file)
@@ -29,12 +29,14 @@ the way the check is run:
   a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
   the compiler.
 ``CMAKE_REQUIRED_LINK_OPTIONS``
-  a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+  .. 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``
-  execute quietly without messages.
+  .. versionadded:: 3.1
+    execute quietly without messages.
 
 See the :module:`CheckIncludeFiles` module to check for multiple headers
 at once.  See the :module:`CheckIncludeFileCXX` module to check for headers
index 496550f..953224e 100644 (file)
@@ -29,12 +29,14 @@ the way the check is run:
   a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
   the compiler.
 ``CMAKE_REQUIRED_LINK_OPTIONS``
-  a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+  .. 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``
-  execute quietly without messages.
+  .. versionadded:: 3.1
+    execute quietly without messages.
 
 See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFiles`
 to check for one or more ``C`` headers.
index 8e10cd6..1800ca8 100644 (file)
@@ -35,12 +35,14 @@ the way the check is run:
   a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
   the compiler.
 ``CMAKE_REQUIRED_LINK_OPTIONS``
-  a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+  .. 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``
-  execute quietly without messages.
+  .. versionadded:: 3.1
+    execute quietly without messages.
 
 See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFileCXX`
 to check for a single header file in ``C`` or ``CXX`` languages.
index 44387d4..928881c 100644 (file)
@@ -68,6 +68,11 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
     else()
       set(_D_CMAKE_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
     endif()
+    if(CMAKE_TOOLCHAIN_FILE)
+      set(_D_CMAKE_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}")
+    else()
+      set(_D_CMAKE_TOOLCHAIN_FILE "")
+    endif()
     execute_process(
       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}
       COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
@@ -75,6 +80,7 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
                                  -T "${CMAKE_GENERATOR_TOOLSET}"
                                  ${_D_CMAKE_GENERATOR_INSTANCE}
                                  ${_D_CMAKE_MAKE_PROGRAM}
+                                 ${_D_CMAKE_TOOLCHAIN_FILE}
       OUTPUT_VARIABLE _cl_output
       ERROR_VARIABLE _cl_output
       RESULT_VARIABLE _cl_result
index 6470dfd..804e0cb 100644 (file)
@@ -26,13 +26,18 @@ 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 = list of options to pass to link command
-  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-  CMAKE_REQUIRED_QUIET = execute quietly without messages
+``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_guard(GLOBAL)
index 8b06403..d29c5e8 100644 (file)
@@ -35,14 +35,20 @@ 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 = list of options to pass to link command
-  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-  CMAKE_REQUIRED_QUIET = execute quietly without messages
+``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.
 #]=======================================================================]
 
 #
index 842a8fd..8217c84 100644 (file)
@@ -23,18 +23,23 @@ Check if the given struct or class has the specified member variable
     <language> - the compiler to use (C or 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 = list of macros to define (-DFOO=bar)
-  CMAKE_REQUIRED_INCLUDES = list of include directories
-  CMAKE_REQUIRED_LINK_OPTIONS = list of options to pass to link command
-  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-  CMAKE_REQUIRED_QUIET = execute quietly without messages
+``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.
 
 
 Example:
index 4f202c4..f8ca584 100644 (file)
@@ -39,12 +39,14 @@ the way the check is run:
   a :ref:`;-list <CMake Language Lists>` of header search paths to pass to
   the compiler.
 ``CMAKE_REQUIRED_LINK_OPTIONS``
-  a :ref:`;-list <CMake Language Lists>` of options to add to the link command.
+  .. 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``
-  execute quietly without messages.
+  .. versionadded:: 3.1
+    execute quietly without messages.
 
 For example:
 
index 17beadc..69f68f9 100644 (file)
@@ -57,19 +57,25 @@ member you can do something like this:
   check_type_size("((struct something*)0)->member" SIZEOF_MEMBER)
 
 
-
 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  = list of options to pass to link command
-  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-  CMAKE_REQUIRED_QUIET = execute quietly without messages
-  CMAKE_EXTRA_INCLUDE_FILES = list of extra headers to include
+``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.
+``CMAKE_EXTRA_INCLUDE_FILES``
+  list of extra headers to include.
 #]=======================================================================]
 
 include(CheckIncludeFile)
index 8a93535..7420124 100644 (file)
@@ -26,13 +26,18 @@ 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 = list of options to pass to link command
-  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-  CMAKE_REQUIRED_QUIET = execute quietly without messages
+``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_guard(GLOBAL)
index f949568..f4f1854 100644 (file)
@@ -33,7 +33,7 @@ macro(__compiler_armcc lang)
   set(CMAKE_${lang}_LINK_EXECUTABLE      "<CMAKE_LINKER> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> --list <TARGET_BASE>.map")
   set(CMAKE_${lang}_CREATE_STATIC_LIBRARY  "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>")
 
-  set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEPFILE> --depend_single_line --no_depend_system_headers")
+  set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEP_FILE> --depend_single_line --no_depend_system_headers")
 
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
 endmacro()
index 2794f52..bd98193 100644 (file)
@@ -1,6 +1,19 @@
 include(Compiler/Clang)
 __compiler_clang(C)
 
+
+if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles"
+      AND CMAKE_DEPFILE_FLAGS_C)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_C_DEPFILE_FORMAT gcc)
+    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+  endif()
+endif()
+
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
 if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
index 15edc21..28be1df 100644 (file)
@@ -1,7 +1,17 @@
 include(Compiler/Clang)
 __compiler_clang(CXX)
 
+set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
 if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles"
+      AND CMAKE_DEPFILE_FLAGS_CXX)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+  endif()
+
   set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
 endif()
 
index d1f3706..d4eab4f 100644 (file)
@@ -1,5 +1,14 @@
 include(Compiler/Clang-OBJC)
 
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles"
+    AND CMAKE_DEPFILE_FLAGS_OBJC)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
 if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 4.0)
   set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90")
   set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90")
index 409bd4a..172a343 100644 (file)
@@ -1,5 +1,15 @@
 include(Compiler/Clang-OBJCXX)
 
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles"
+    AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
 set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
 
 if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.0)
index 409b65a..cd897c5 100644 (file)
@@ -93,21 +93,14 @@ endmacro()
 # Define to allow compile features to be automatically determined
 macro(cmake_record_cxx_compile_features)
   set(_result 0)
+  if(_result EQUAL 0 AND DEFINED CMAKE_CXX23_STANDARD_COMPILE_OPTION)
+    _has_compiler_features_cxx(23)
+  endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX20_STANDARD_COMPILE_OPTION)
-    if(CMAKE_CXX20_STANDARD__HAS_FULL_SUPPORT)
-      _has_compiler_features_cxx(20)
-    else()
-      _record_compiler_features_cxx(20)
-    endif()
-    unset(CMAKE_CXX20_STANDARD__HAS_FULL_SUPPORT)
+    _has_compiler_features_cxx(20)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX17_STANDARD_COMPILE_OPTION)
-    if(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT)
-      _has_compiler_features_cxx(17)
-    else()
-      _record_compiler_features_cxx(17)
-    endif()
-    unset(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT)
+    _has_compiler_features_cxx(17)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CXX14_STANDARD_COMPILE_OPTION)
     if(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT)
@@ -137,21 +130,14 @@ endmacro()
 
 macro(cmake_record_cuda_compile_features)
   set(_result 0)
+  if(_result EQUAL 0 AND DEFINED CMAKE_CUDA23_STANDARD_COMPILE_OPTION)
+    _has_compiler_features_cuda(23)
+  endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CUDA20_STANDARD_COMPILE_OPTION)
-    if(CMAKE_CUDA20_STANDARD__HAS_FULL_SUPPORT)
-      _has_compiler_features_cuda(20)
-    else()
-      _record_compiler_features_cuda(20)
-    endif()
-    unset(CMAKE_CUDA20_STANDARD__HAS_FULL_SUPPORT)
+    _has_compiler_features_cuda(20)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CUDA17_STANDARD_COMPILE_OPTION)
-    if(CMAKE_CUDA17_STANDARD__HAS_FULL_SUPPORT)
-      _has_compiler_features_cuda(17)
-    else()
-      _record_compiler_features_cuda(17)
-    endif()
-    unset(CMAKE_CUDA17_STANDARD__HAS_FULL_SUPPORT)
+    _has_compiler_features_cuda(17)
   endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_CUDA14_STANDARD_COMPILE_OPTION)
     if(CMAKE_CUDA14_STANDARD__HAS_FULL_SUPPORT)
index 7c4a263..5609abf 100644 (file)
@@ -7,7 +7,22 @@ if(APPLE AND NOT appleClangPolicy STREQUAL NEW)
 endif()
 
 if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+  set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
   set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_C)
+    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+  endif()
+elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+  set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_C)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_C_DEPFILE_FORMAT gcc)
+    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+  endif()
 endif()
 
 if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
index fd8c2b7..cafc7dd 100644 (file)
@@ -2,7 +2,13 @@ include(Compiler/Clang)
 __compiler_clang(CUDA)
 
 # Set explicitly, because __compiler_clang() doesn't set this if we're simulating MSVC.
-set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <OBJECT> -MF <DEPFILE>")
+set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  # dependencies are computed by the compiler itself
+  set(CMAKE_CUDA_DEPFILE_FORMAT gcc)
+  set(CMAKE_CUDA_DEPENDS_USE_COMPILER TRUE)
+endif()
 
 # C++03 isn't supported for CXX, but is for CUDA, so we need to set these manually.
 # Do this before __compiler_clang_cxx_standards() since that adds the feature.
index 789e991..98828e0 100644 (file)
@@ -3,6 +3,15 @@ __compiler_clang(CXX)
 __compiler_clang_cxx_standards(CXX)
 
 if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_CXX)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+  endif()
+
+  set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
   set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
 endif()
 
@@ -13,4 +22,9 @@ endif()
 
 if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
   set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles"
+      AND CMAKE_DEPFILE_FLAGS_CXX)
+    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+  endif()
 endif()
index b852660..e6c469a 100644 (file)
@@ -2,6 +2,12 @@ if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL
   message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set")
 endif()
 
+# Ubuntu:
+# * /usr/bin/llvm-ar-9
+# * /usr/bin/llvm-ranlib-9
+string(REGEX MATCH "^([0-9]+)" __version_x
+    "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_VERSION}")
+
 # Debian:
 # * /usr/bin/llvm-ar-4.0
 # * /usr/bin/llvm-ranlib-4.0
@@ -19,6 +25,7 @@ set(__clang_hints ${__clang_hint_1} ${__clang_hint_2})
 # http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ar.1.html
 find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR NAMES
     "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar-${__version_x_y}"
+    "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar-${__version_x}"
     "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar"
     HINTS ${__clang_hints}
     DOC "LLVM archiver"
@@ -28,6 +35,7 @@ mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR)
 # http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ranlib.1.html
 find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
     "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib-${__version_x_y}"
+    "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib-${__version_x}"
     "${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib"
     HINTS ${__clang_hints}
     DOC "Generate index for LLVM archive"
index c61c497..19179e3 100644 (file)
@@ -1,6 +1,15 @@
 include(Compiler/Clang)
 __compiler_clang(OBJC)
 
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_OBJC)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
 if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 3.4)
   set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90")
   set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90")
index 453b5fd..9bdff66 100644 (file)
@@ -1,3 +1,11 @@
 include(Compiler/Clang)
 __compiler_clang(OBJCXX)
 __compiler_clang_cxx_standards(OBJCXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
index c43265d..9f93d41 100644 (file)
@@ -77,7 +77,7 @@ else()
       set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto")
     endif()
 
-    if(ANDROID)
+    if(ANDROID AND NOT CMAKE_ANDROID_NDK_VERSION VERSION_GREATER_EQUAL "22")
       # https://github.com/android-ndk/ndk/issues/242
       set(CMAKE_${lang}_LINK_OPTIONS_IPO "-fuse-ld=gold")
     endif()
@@ -154,10 +154,6 @@ macro(__compiler_clang_cxx_standards lang)
       set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
     endif()
 
-    if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 6.0)
-      set(CMAKE_${lang}17_STANDARD__HAS_FULL_SUPPORT ON)
-    endif()
-
     if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 11.0)
       set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "-std=c++20")
       set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
@@ -168,6 +164,11 @@ macro(__compiler_clang_cxx_standards lang)
 
     unset(_clang_version_std17)
 
+    if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)
+      set(CMAKE_${lang}23_STANDARD_COMPILE_OPTION "-std=c++2b")
+      set(CMAKE_${lang}23_EXTENSION_COMPILE_OPTION "-std=gnu++2b")
+    endif()
+
     if("x${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "xMSVC")
       # The MSVC standard library requires C++14, and MSVC itself has no
       # notion of operating in a mode not aware of at least that standard.
@@ -179,8 +180,6 @@ macro(__compiler_clang_cxx_standards lang)
       # This clang++ is missing some features because of MSVC compatibility.
       unset(CMAKE_${lang}11_STANDARD__HAS_FULL_SUPPORT)
       unset(CMAKE_${lang}14_STANDARD__HAS_FULL_SUPPORT)
-      unset(CMAKE_${lang}17_STANDARD__HAS_FULL_SUPPORT)
-      unset(CMAKE_${lang}20_STANDARD__HAS_FULL_SUPPORT)
     endif()
 
     __compiler_check_default_language_standard(${lang} 2.1 98)
@@ -220,6 +219,8 @@ macro(__compiler_clang_cxx_standards lang)
     set(CMAKE_${lang}17_EXTENSION_COMPILE_OPTION "")
     set(CMAKE_${lang}20_STANDARD_COMPILE_OPTION "")
     set(CMAKE_${lang}20_EXTENSION_COMPILE_OPTION "")
+    set(CMAKE_${lang}23_STANDARD_COMPILE_OPTION "")
+    set(CMAKE_${lang}23_EXTENSION_COMPILE_OPTION "")
 
     # There is no meaningful default for this
     set(CMAKE_${lang}_STANDARD_DEFAULT "")
@@ -235,6 +236,7 @@ macro(__compiler_clang_cxx_standards lang)
         cxx_std_14
         cxx_std_17
         cxx_std_20
+        cxx_std_23
         )
       _record_compiler_features(${lang} "" CMAKE_${lang}_COMPILE_FEATURES)
     endmacro()
index 696ae76..0d5e1c7 100644 (file)
@@ -19,3 +19,7 @@ else()
   set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-eZ")
   set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-dZ")
 endif()
+
+if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 11.0)
+  set(CMAKE_Fortran_PREPROCESS_SOURCE "<CMAKE_Fortran_COMPILER> -o <PREPROCESSED_SOURCE> <DEFINES> <INCLUDES> <FLAGS> -eP <SOURCE>")
+endif()
index 94af401..a935416 100644 (file)
@@ -6,7 +6,7 @@ set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S;asm)
 __compiler_gnu(ASM)
 
 if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH STREQUAL "GNU assembler")
-  set(CMAKE_DEPFILE_FLAGS_ASM${ASM_DIALECT} "--MD <DEPFILE>")
+  set(CMAKE_DEPFILE_FLAGS_ASM${ASM_DIALECT} "--MD <DEP_FILE>")
   set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE
     "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
   set(CMAKE_ASM_DEFINE_FLAG "--defsym ")
index ca286b3..86b4d83 100644 (file)
@@ -1,6 +1,17 @@
 include(Compiler/GNU)
 __compiler_gnu(C)
 
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_C)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_C_DEPFILE_FORMAT gcc)
+  set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
 if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
index fcaaeab..758d3c7 100644 (file)
@@ -1,6 +1,17 @@
 include(Compiler/GNU)
 __compiler_gnu(CXX)
 
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_CXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
 if (WIN32)
   if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
     set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fno-keep-inline-dllexport")
index fb9b0b2..7eeed83 100644 (file)
@@ -1,2 +1,11 @@
 include(Compiler/GNU)
 __compiler_gnu(OBJC)
+
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_OBJC)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
+endif()
index 06f0244..1047b5d 100644 (file)
@@ -1,6 +1,15 @@
 include(Compiler/GNU)
 __compiler_gnu(OBJCXX)
 
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+
 if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.2)
   set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
 endif()
index 81ab3a2..928e726 100644 (file)
@@ -48,7 +48,7 @@ macro(__compiler_gnu lang)
     # distcc does not transform -o to -MT when invoking the preprocessor
     # internally, as it ought to.  Work around this bug by setting -MT here
     # even though it isn't strictly necessary.
-    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>")
+    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
   endif()
 
   # Initial configuration flags.
index 936d4ae..e3ca16e 100644 (file)
@@ -47,6 +47,11 @@ elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
   __compiler_iar_xlink(ASM)
   set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s51;asm;msa)
 
+elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
+  set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>")
+  __compiler_iar_ilink(ASM)
+  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa)
+
 else()
   message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
 endif()
index e27fdfc..054ee74 100644 (file)
@@ -70,6 +70,10 @@ elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
   __compiler_check_default_language_standard(C 6.10 90 8.10 99)
   set(CMAKE_C_OUTPUT_EXTENSION ".r51")
 
+elseif("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
+  __compiler_iar_ilink(C)
+  __compiler_check_default_language_standard(C 3.11 90 3.11 99)
+
 else()
   message(FATAL_ERROR "CMAKE_C_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.")
 endif()
index eca89c5..d93b272 100644 (file)
@@ -78,6 +78,10 @@ elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051")
   __compiler_check_default_language_standard(CXX 6.10 98)
   set(CMAKE_C_OUTPUT_EXTENSION ".r51")
 
+elseif("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
+  __compiler_iar_ilink(CXX)
+  __compiler_check_default_language_standard(CXX 3.11 98)
+
 else()
   message(FATAL_ERROR "CMAKE_CXX_COMPILER_ARCHITECTURE_ID not detected. This should be automatic." )
 endif()
index 0a026b2..443b09c 100644 (file)
@@ -31,7 +31,7 @@ set(_compiler_id_version_compute "
 #  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(((__VER__) / 1000) % 1000)
 #  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@((__VER__) % 1000)
 #  define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__IAR_SYSTEMS_ICC__)
-# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__))
+# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))
 #  define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@((__VER__) / 100)
 #  define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@((__VER__) - (((__VER__) / 100)*100))
 #  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__SUBVERSION__)
index 6ef3759..6c67d34 100644 (file)
@@ -14,7 +14,8 @@ if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "A
    "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX" OR
    "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850" OR
    "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78" OR
-   "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV")
+   "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RISCV" OR
+   "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8")
 
   string(TOLOWER "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ARCHITECTURE_ID}" _archid_lower)
 
index f3938a9..b8c0770 100644 (file)
@@ -49,7 +49,7 @@ macro(__compiler_iar_ilink lang)
     set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy")
 
     set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ")
-    set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEPFILE>")
+    set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>")
 
     string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
     string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r")
@@ -85,7 +85,7 @@ macro(__compiler_iar_xlink lang)
     set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> ${CMAKE_IAR_${lang}_FLAG} --silent <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -lAH <ASSEMBLY_SOURCE> -o <OBJECT>.dummy")
 
     set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ")
-    set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEPFILE>")
+    set(CMAKE_DEPFILE_FLAGS_${lang} "--dependencies=ns <DEP_FILE>")
 
     string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
     string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -r")
index ec3bfd8..ead9069 100644 (file)
@@ -5,10 +5,17 @@ string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
 
-set(CMAKE_DEPFILE_FLAGS_C "-MD -MT <OBJECT> -MF <DEPFILE>")
+set(CMAKE_DEPFILE_FLAGS_C "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  # dependencies are computed by the compiler itself
+  set(CMAKE_C_DEPFILE_FORMAT gcc)
+  set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
 
 if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
 
+  set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
   set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
 
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16.0.0)
@@ -28,6 +35,8 @@ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
 
 else()
 
+  set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
index b71b946..37f339a 100644 (file)
@@ -5,7 +5,13 @@ string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
 string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
 string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
 
-set(CMAKE_DEPFILE_FLAGS_CXX "-MD -MT <OBJECT> -MF <DEPFILE>")
+set(CMAKE_DEPFILE_FLAGS_CXX "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  # dependencies are computed by the compiler itself
+  set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
 
 if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
 
@@ -42,6 +48,8 @@ if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
 
 else()
 
+  set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.0)
     set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++20")
     set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
index aa9ecea..be64cf7 100644 (file)
@@ -3,7 +3,13 @@ include(Compiler/CMakeCommonCompilerMacros)
 # Not aware of any verbose flag for ISPC
 #set(CMAKE_ISPC_VERBOSE_FLAG )
 
-set(CMAKE_DEPFILE_FLAGS_ISPC "-M -MT <OBJECT> -MF <DEPFILE>")
+set(CMAKE_DEPFILE_FLAGS_ISPC "-M -MT <DEP_TARGET> -MF <DEP_FILE>")
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  # dependencies are computed by the compiler itself
+  set(CMAKE_ISPC_DEPFILE_FORMAT gcc)
+  set(CMAKE_ISPC_DEPENDS_USE_COMPILER TRUE)
+endif()
 
 string(APPEND CMAKE_ISPC_FLAGS_INIT " ")
 string(APPEND CMAKE_ISPC_FLAGS_DEBUG_INIT "-O0 -g")
diff --git a/Modules/Compiler/IntelLLVM-ASM.cmake b/Modules/Compiler/IntelLLVM-ASM.cmake
new file mode 100644 (file)
index 0000000..c258a0a
--- /dev/null
@@ -0,0 +1,12 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(ASM)
+
+string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG")
+string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+
+if(UNIX)
+  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;S)
+else()
+  set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS asm)
+endif()
diff --git a/Modules/Compiler/IntelLLVM-C.cmake b/Modules/Compiler/IntelLLVM-C.cmake
new file mode 100644 (file)
index 0000000..fce2971
--- /dev/null
@@ -0,0 +1,58 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(C)
+
+if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+  set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
+  set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_C)
+    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+  endif()
+else()
+  set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_C)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_C_DEPFILE_FORMAT gcc)
+    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+  endif()
+
+  string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+  string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
+  string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+endif()
+
+set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+
+if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+  set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+
+  set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
+  set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
+
+  set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+  set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+else()
+  # clang-cl doesn't have any of these
+  set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+
+  set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
+
+  set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
+endif()
+
+if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+  # FIXME: The compiler actually defaults to C17, but
+  # CMake does not yet model or detect that standard.
+  __compiler_check_default_language_standard(C 2020 11)
+else()
+  set(CMAKE_C_STANDARD_DEFAULT "")
+endif()
diff --git a/Modules/Compiler/IntelLLVM-CXX.cmake b/Modules/Compiler/IntelLLVM-CXX.cmake
new file mode 100644 (file)
index 0000000..4c0c26e
--- /dev/null
@@ -0,0 +1,69 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(CXX)
+
+if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+  set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TP)
+  set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_CXX)
+    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+  endif()
+else()
+  set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_CXX)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+  endif()
+
+  set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+
+  string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
+  string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -DNDEBUG")
+  string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -DNDEBUG")
+endif()
+
+set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+
+if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION  "-std=c++98")
+  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  "-std=c++11")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+
+  set(CMAKE_CXX14_STANDARD_COMPILE_OPTION  "-std=c++14")
+  set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+
+  set(CMAKE_CXX17_STANDARD_COMPILE_OPTION  "-std=c++17")
+  set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+
+  set(CMAKE_CXX20_STANDARD_COMPILE_OPTION  "-std=c++20")
+  set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
+else()
+  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION  "")
+  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  "-Qstd=c++11")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-Qstd=c++11")
+
+  set(CMAKE_CXX14_STANDARD_COMPILE_OPTION  "-Qstd=c++14")
+  set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-Qstd=c++14")
+
+  set(CMAKE_CXX17_STANDARD_COMPILE_OPTION  "-Qstd=c++17")
+  set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-Qstd=c++17")
+
+  set(CMAKE_CXX20_STANDARD_COMPILE_OPTION  "-Qstd=c++20")
+  set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-Qstd=c++20")
+endif()
+
+if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+  __compiler_check_default_language_standard(CXX 2020 14)
+else()
+  set(CMAKE_CXX_STANDARD_DEFAULT "")
+endif()
diff --git a/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake b/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake
new file mode 100644 (file)
index 0000000..124dafe
--- /dev/null
@@ -0,0 +1,41 @@
+
+set(_compiler_id_pp_test "(defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)")
+
+set(_compiler_id_version_compute "
+/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and
+ * later.  Look for 6 digit vs. 8 digit version number to decide encoding.
+ * VVVV is no smaller than the current year when a versio is released.
+ */
+#if __INTEL_LLVM_COMPILER < 1000000L
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__INTEL_LLVM_COMPILER    % 10)
+#else
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/10000)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__INTEL_LLVM_COMPILER/100 % 100)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__INTEL_LLVM_COMPILER     % 100)
+#endif
+#if defined(_MSC_VER)
+  /* _MSC_VER = VVRR */
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(_MSC_VER / 100)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(_MSC_VER % 100)
+#endif
+#if defined(__GNUC__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
+#elif defined(__GNUG__)
+# define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUG__)
+#endif
+#if defined(__GNUC_MINOR__)
+# define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
+#endif
+#if defined(__GNUC_PATCHLEVEL__)
+# define @PREFIX@SIMULATE_VERSION_PATCH @MACRO_DEC@(__GNUC_PATCHLEVEL__)
+#endif")
+
+set(_compiler_id_simulate "
+#if defined(_MSC_VER)
+# define @PREFIX@SIMULATE_ID \"MSVC\"
+#endif
+#if defined(__GNUC__)
+# define @PREFIX@SIMULATE_ID \"GNU\"
+#endif")
diff --git a/Modules/Compiler/IntelLLVM-Fortran.cmake b/Modules/Compiler/IntelLLVM-Fortran.cmake
new file mode 100644 (file)
index 0000000..710803f
--- /dev/null
@@ -0,0 +1,27 @@
+include(Compiler/IntelLLVM)
+__compiler_intel_llvm(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP "@")
+set(CMAKE_Fortran_SUBMODULE_EXT ".smod")
+
+set(CMAKE_Fortran_MODDIR_FLAG "-module ")
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
+
+set(CMAKE_Fortran_COMPILE_WITH_DEFINES 1)
+
+set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+if(CMAKE_HOST_WIN32)
+  # MSVC-like
+  set(CMAKE_Fortran_PREPROCESS_SOURCE
+    "<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -P <SOURCE> -Fi<PREPROCESSED_SOURCE>")
+else()
+  # GNU-like
+  set(CMAKE_Fortran_PREPROCESS_SOURCE
+    "<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -P <SOURCE> -o <PREPROCESSED_SOURCE>")
+endif()
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-fpp")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nofpp")
diff --git a/Modules/Compiler/IntelLLVM.cmake b/Modules/Compiler/IntelLLVM.cmake
new file mode 100644 (file)
index 0000000..14b7ad8
--- /dev/null
@@ -0,0 +1,92 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_LLVM_INTEL)
+  return()
+endif()
+set(__COMPILER_LLVM_INTEL 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+set(__pch_header_C "c-header")
+set(__pch_header_CXX "c++-header")
+set(__pch_header_OBJC "objective-c-header")
+set(__pch_header_OBJCXX "objective-c++-header")
+
+if(CMAKE_HOST_WIN32)
+  # MSVC-like
+  macro(__compiler_intel_llvm lang)
+    if(NOT "x${lang}" STREQUAL "xFortran")
+      set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+    endif()
+  endmacro()
+else()
+  # GNU-like
+  macro(__compiler_intel_llvm lang)
+    set(CMAKE_${lang}_VERBOSE_FLAG "-v")
+
+    string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+    string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
+    string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os")
+    string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3")
+    string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+
+    set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+    set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} "-pie")
+    set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "-no-pie")
+
+    set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+    set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+
+    set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+    set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+    # distcc does not transform -o to -MT when invoking the preprocessor
+    # internally, as it ought to.  Work around this bug by setting -MT here
+    # even though it isn't strictly necessary.
+    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+
+    set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "--target=")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "--sysroot=")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "--gcc-toolchain=")
+    set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+    set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
+
+    set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+    set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin")
+    set(CMAKE_${lang}_ARCHIVE_CREATE_IPO "\"${CMAKE_${lang}_COMPILER_AR}\" cr <TARGET> <LINK_FLAGS> <OBJECTS>")
+    set(CMAKE_${lang}_ARCHIVE_APPEND_IPO "\"${CMAKE_${lang}_COMPILER_AR}\" r <TARGET> <LINK_FLAGS> <OBJECTS>")
+    set(CMAKE_${lang}_ARCHIVE_FINISH_IPO "\"${CMAKE_${lang}_COMPILER_RANLIB}\" <TARGET>")
+
+    set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+    set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+    set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}")
+    if(CMAKE_${lang}_COMPILER_ARG1)
+      separate_arguments(_COMPILER_ARGS NATIVE_COMMAND "${CMAKE_${lang}_COMPILER_ARG1}")
+      list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND ${_COMPILER_ARGS})
+      unset(_COMPILER_ARGS)
+    endif()
+    list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
+    if(CMAKE_${lang}_COMPILER_TARGET)
+      list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
+    endif()
+
+    if(NOT "x${lang}" STREQUAL "xFortran")
+      # Precompile Headers
+      set(CMAKE_PCH_EXTENSION .pch)
+      set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
+      set(CMAKE_${lang}_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH -fpch-instantiate-templates)
+      set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+      set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
+      set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER> -x ${__pch_header_${lang}})
+    endif()
+  endmacro()
+endif()
index 31ae7fd..9a5104b 100644 (file)
@@ -27,6 +27,7 @@ else()
   set(CMAKE_C_STANDARD_DEFAULT "")
 endif()
 
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
 set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
 
 # There are no C compiler modes so we hard-code the known compiler supported
index ffce97e..a65fd2c 100644 (file)
@@ -31,6 +31,7 @@ endif()
 set(CMAKE_Fortran_SUBMODULE_SEP ".")
 set(CMAKE_Fortran_SUBMODULE_EXT ".sub")
 set(CMAKE_Fortran_MODDIR_FLAG "-mdir ")
+set(CMAKE_Fortran_MODDIR_INCLUDE_FLAG "-I") # -mdir does not affect search path
 set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-PIC")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
 set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
diff --git a/Modules/Compiler/NVHPC-C.cmake b/Modules/Compiler/NVHPC-C.cmake
new file mode 100644 (file)
index 0000000..d16c72b
--- /dev/null
@@ -0,0 +1,3 @@
+include(Compiler/PGI-C)
+include(Compiler/NVHPC)
+__compiler_nvhpc(C)
diff --git a/Modules/Compiler/NVHPC-CXX.cmake b/Modules/Compiler/NVHPC-CXX.cmake
new file mode 100644 (file)
index 0000000..18ace8b
--- /dev/null
@@ -0,0 +1,3 @@
+include(Compiler/PGI-CXX)
+include(Compiler/NVHPC)
+__compiler_nvhpc(CXX)
diff --git a/Modules/Compiler/NVHPC-DetermineCompiler.cmake b/Modules/Compiler/NVHPC-DetermineCompiler.cmake
new file mode 100644 (file)
index 0000000..45b69e1
--- /dev/null
@@ -0,0 +1,9 @@
+
+set(_compiler_id_pp_test "defined(__NVCOMPILER)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__NVCOMPILER_MAJOR__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__NVCOMPILER_MINOR__)
+# if defined(__NVCOMPILER_PATCHLEVEL__)
+#  define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__NVCOMPILER_PATCHLEVEL__)
+# endif")
diff --git a/Modules/Compiler/NVHPC-Fortran.cmake b/Modules/Compiler/NVHPC-Fortran.cmake
new file mode 100644 (file)
index 0000000..59755b3
--- /dev/null
@@ -0,0 +1,3 @@
+include(Compiler/PGI-Fortran)
+include(Compiler/NVHPC)
+__compiler_nvhpc(Fortran)
diff --git a/Modules/Compiler/NVHPC.cmake b/Modules/Compiler/NVHPC.cmake
new file mode 100644 (file)
index 0000000..7048670
--- /dev/null
@@ -0,0 +1,15 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_NVHPC)
+  return()
+endif()
+set(__COMPILER_NVHPC 1)
+
+include(Compiler/PGI)
+
+macro(__compiler_nvhpc lang)
+  # Logic specific to NVHPC.
+endmacro()
index 95a51f6..eb80675 100644 (file)
@@ -28,7 +28,14 @@ if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89)
   # The -MD flag was only added to nvcc in 10.2 so
   # before that we had to invoke the compiler twice
   # to get header dependency information
-  set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <OBJECT> -MF <DEPFILE>")
+  set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
+else()
+  set(CMAKE_CUDA_DEPENDS_EXTRA_COMMANDS "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -M <SOURCE> -MT <OBJECT> -o <DEP_FILE>")
+endif()
+set(CMAKE_CUDA_DEPFILE_FORMAT gcc)
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  set(CMAKE_CUDA_DEPENDS_USE_COMPILER TRUE)
 endif()
 
 if(NOT "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
index 2d7a303..1279c19 100644 (file)
@@ -8,6 +8,8 @@ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION --gnu_extensions)
   set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.10)
+    set(CMAKE_CXX98_STANDARD_COMPILE_OPTION --c++03)
+    set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION --c++03 --gnu_extensions)
     set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  --c++11)
     set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION --c++11 --gnu_extensions)
     set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
@@ -18,7 +20,6 @@ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.10)
       if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.1)
         set(CMAKE_CXX17_STANDARD_COMPILE_OPTION  --c++17)
         set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION --c++17 --gnu_extensions)
-        set(CMAKE_CXX17_STANDARD__HAS_FULL_SUPPORT ON)
       endif()
     endif()
   endif()
index 10e1389..7fbfd10 100644 (file)
@@ -14,7 +14,7 @@ macro(__compiler_qcc lang)
 
   set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "-Wc,-isysroot,")
   set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,")
-  set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEPFILE> -Wp,-MT,<OBJECT> -Wp,-MF,<DEPFILE>")
+  set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEP_FILE> -Wp,-MT,<DEP_TARGET> -Wp,-MF,<DEP_FILE>")
 
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
index 7e962b8..c98656f 100644 (file)
@@ -22,7 +22,7 @@ string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
 
-set(CMAKE_DEPFILE_FLAGS_C "-xMD -xMF <DEPFILE>")
+set(CMAKE_DEPFILE_FLAGS_C "-xMD -xMF <DEP_FILE>")
 
 # Initialize C link type selection flags.  These flags are used when
 # building a shared library, shared module, or executable that links
index c946c64..aa8a9c5 100644 (file)
@@ -22,7 +22,7 @@ string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -xO2 -xspace -DNDEBUG")
 string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -xO3 -DNDEBUG")
 string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
 
-set(CMAKE_DEPFILE_FLAGS_CXX "-xMD -xMF <DEPFILE>")
+set(CMAKE_DEPFILE_FLAGS_CXX "-xMD -xMF <DEP_FILE>")
 
 # Initialize C link type selection flags.  These flags are used when
 # building a shared library, shared module, or executable that links
index f631688..c8c1635 100644 (file)
@@ -18,7 +18,7 @@ macro(__compiler_ti lang)
   set(CMAKE_${lang}_RESPONSE_FILE_FLAG "--cmd_file=")
 
   set(CMAKE_INCLUDE_FLAG_${lang} "--include_path=")
-  set(CMAKE_DEPFILE_FLAGS_${lang} "--preproc_with_compile --preproc_dependency=<DEPFILE>")
+  set(CMAKE_DEPFILE_FLAGS_${lang} "--preproc_with_compile --preproc_dependency=<DEP_FILE>")
 
   set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> --preproc_only ${__COMPILER_TI_SOURCE_FLAG_${lang}}=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<PREPROCESSED_SOURCE>")
   set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> --compile_only --skip_assembler ${__COMPILER_TI_SOURCE_FLAG_${lang}}=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<ASSEMBLY_SOURCE>")
index fc71ab4..8b9d4a9 100644 (file)
@@ -30,5 +30,5 @@ macro(__compiler_xl lang)
   set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
   set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 
-  set(CMAKE_DEPFILE_FLAGS_${lang} "-MF <DEPFILE> -qmakedep=gcc")
+  set(CMAKE_DEPFILE_FLAGS_${lang} "-MF <DEP_FILE> -qmakedep=gcc")
 endmacro()
index 54c18a6..1668a4d 100644 (file)
@@ -1,6 +1,8 @@
 include(Compiler/XLClang)
 __compiler_xlclang(C)
 
+set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
+
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION  "-std=c89")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")
index 9ea3d7c..02638c7 100644 (file)
@@ -1,6 +1,8 @@
 include(Compiler/XLClang)
 __compiler_xlclang(CXX)
 
+set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
+
 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION  "")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
index 90a56e2..e5b1e5d 100644 (file)
@@ -83,10 +83,6 @@ MemoryCheckSuppressionFile: @MEMORYCHECK_SUPPRESSIONS_FILE@
 CoverageCommand: @COVERAGE_COMMAND@
 CoverageExtraFlags: @COVERAGE_EXTRA_FLAGS@
 
-# Cluster commands
-SlurmBatchCommand: @SLURM_SBATCH_COMMAND@
-SlurmRunCommand: @SLURM_SRUN_COMMAND@
-
 # Testing options
 # TimeOut is the amount of time in seconds to wait for processes
 # to complete during testing.  After TimeOut seconds, the
index c297231..2430f85 100644 (file)
@@ -5,6 +5,9 @@
 Documentation
 -------------
 
+.. deprecated:: 3.18
+  This module does nothing, unless policy :policy:`CMP0106` is set to ``OLD``.
+
 This module provides support for the VTK documentation framework.  It
 relies on several tools (Doxygen, Perl, etc).
 #]=======================================================================]
index 6fe8685..d6fbae9 100644 (file)
@@ -78,7 +78,8 @@ Module Functions
   manage local instances of data files stored externally::
 
     ExternalData_Add_Target(
-      <target>   # Name of data management target
+      <target>                  # Name of data management target
+      [SHOW_PROGRESS <ON|OFF>]  # Show progress during the download
       )
 
   It creates custom commands in the target as necessary to make data
@@ -89,6 +90,12 @@ Module Functions
   in one of the paths specified in the ``ExternalData_OBJECT_STORES``
   variable.
 
+  .. versionadded:: 3.20
+    The ``SHOW_PROGRESS`` argument may be passed to suppress progress information
+    during the download of objects. If not provided, it defaults to ``OFF`` for
+    :generator:`Ninja` and :generator:`Ninja Multi-Config` generators and ``ON``
+    otherwise.
+
   Typically only one target is needed to manage all external data within
   a project.  Call this function once at the end of configuration after
   all data references have been processed.
@@ -108,6 +115,8 @@ calling any of the functions provided by this module.
 
 .. variable:: ExternalData_CUSTOM_SCRIPT_<key>
 
+  .. versionadded:: 3.2
+
   Specify a full path to a ``.cmake`` custom fetch script identified by
   ``<key>`` in entries of the ``ExternalData_URL_TEMPLATES`` list.
   See `Custom Fetch Scripts`_.
@@ -126,6 +135,8 @@ calling any of the functions provided by this module.
 
 .. variable:: ExternalData_NO_SYMLINKS
 
+  .. versionadded:: 3.3
+
   The real data files named by expanded ``DATA{}`` references may be made
   available under ``ExternalData_BINARY_ROOT`` using symbolic links on
   some platforms.  The ``ExternalData_NO_SYMLINKS`` variable may be set
@@ -171,6 +182,8 @@ calling any of the functions provided by this module.
 
 .. variable:: ExternalData_URL_ALGO_<algo>_<key>
 
+  .. versionadded:: 3.3
+
   Specify a custom URL component to be substituted for URL template
   placeholders of the form ``%(algo:<key>)``, where ``<key>`` is a
   valid C identifier, when fetching an object referenced via hash
@@ -201,10 +214,11 @@ For example, the argument ``DATA{img.png}`` may be satisfied by either a
 real ``img.png`` file in the current source directory or a ``img.png.md5``
 file containing its MD5 sum.
 
-Multiple content links of the same name with different hash algorithms
-are supported (e.g. ``img.png.sha256`` and ``img.png.sha1``) so long as
-they all correspond to the same real file.  This allows objects to be
-fetched from sources indexed by different hash algorithms.
+.. versionadded:: 3.8
+  Multiple content links of the same name with different hash algorithms
+  are supported (e.g. ``img.png.sha256`` and ``img.png.sha1``) so long as
+  they all correspond to the same real file.  This allows objects to be
+  fetched from sources indexed by different hash algorithms.
 
 Referencing File Series
 """""""""""""""""""""""
@@ -263,8 +277,11 @@ associated file options.  For example, the argument
 ``DATA{MyDataDir/,REGEX:.*}`` will pass the full path to a ``MyDataDir``
 directory on the command line and ensure that the directory contains
 files corresponding to every file or content link in the ``MyDataDir``
-source directory.  In order to match associated files in subdirectories,
-specify a ``RECURSE:`` option, e.g. ``DATA{MyDataDir/,RECURSE:,REGEX:.*}``.
+source directory.
+
+.. versionadded:: 3.3
+  In order to match associated files in subdirectories,
+  specify a ``RECURSE:`` option, e.g. ``DATA{MyDataDir/,RECURSE:,REGEX:.*}``.
 
 Hash Algorithms
 ^^^^^^^^^^^^^^^
@@ -284,6 +301,9 @@ The following hash algorithms are supported::
  SHA3_384    .sha3-384 Keccak SHA-3
  SHA3_512    .sha3-512 Keccak SHA-3
 
+.. versionadded:: 3.8
+  Added the ``SHA3_*`` hash algorithms.
+
 Note that the hashes are used only for unique data identification and
 download verification.
 
@@ -292,6 +312,8 @@ download verification.
 Custom Fetch Scripts
 ^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.2
+
 When a data file must be fetched from one of the URL templates
 specified in the ``ExternalData_URL_TEMPLATES`` variable, it is
 normally downloaded using the :command:`file(DOWNLOAD)` command.
@@ -344,6 +366,30 @@ function(ExternalData_add_target target)
   endif()
   set(_ExternalData_CONFIG_CODE "")
 
+  cmake_parse_arguments(PARSE_ARGV 1 _ExternalData_add_target
+    ""
+    "SHOW_PROGRESS"
+    "")
+  if (_ExternalData_add_target_UNPARSED_ARGUMENTS)
+    message(AUTHOR_WARNING
+      "Ignoring unrecognized arguments passed to ExternalData_add_target: "
+      "`${_ExternalData_add_target_UNPARSED_ARGUMENTS}`")
+  endif ()
+
+  # Turn `SHOW_PROGRESS` into a boolean
+  if (NOT DEFINED _ExternalData_add_target_SHOW_PROGRESS)
+    # The default setting
+    if (CMAKE_GENERATOR MATCHES "Ninja")
+      set(_ExternalData_add_target_SHOW_PROGRESS OFF)
+    else ()
+      set(_ExternalData_add_target_SHOW_PROGRESS ON)
+    endif ()
+  elseif (_ExternalData_add_target_SHOW_PROGRESS)
+    set(_ExternalData_add_target_SHOW_PROGRESS ON)
+  else ()
+    set(_ExternalData_add_target_SHOW_PROGRESS OFF)
+  endif ()
+
   # Store custom script configuration.
   foreach(url_template IN LISTS ExternalData_URL_TEMPLATES)
     if("${url_template}" MATCHES "^ExternalDataCustomScript://([^/]*)/(.*)$")
@@ -423,6 +469,7 @@ function(ExternalData_add_target target)
           COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
                                    -Dfile=${file} -Dname=${name}
                                    -DExternalData_ACTION=local
+                                   -DExternalData_SHOW_PROGRESS=${_ExternalData_add_target_SHOW_PROGRESS}
                                    -DExternalData_CONFIG=${config}
                                    -P ${_ExternalData_SELF}
           MAIN_DEPENDENCY "${name}"
@@ -459,6 +506,7 @@ function(ExternalData_add_target target)
           COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
                                    -Dfile=${file} -Dname=${name} -Dexts=${exts}
                                    -DExternalData_ACTION=fetch
+                                   -DExternalData_SHOW_PROGRESS=${_ExternalData_add_target_SHOW_PROGRESS}
                                    -DExternalData_CONFIG=${config}
                                    -P ${_ExternalData_SELF}
           # Update whenever the object hash changes.
@@ -925,7 +973,11 @@ function(_ExternalData_download_file url file err_var msg_var)
     else()
       set(absolute_timeout "")
     endif()
-    file(DOWNLOAD "${url}" "${file}" STATUS status LOG log ${inactivity_timeout} ${absolute_timeout} SHOW_PROGRESS)
+    set(show_progress_args)
+    if (ExternalData_SHOW_PROGRESS)
+      list(APPEND show_progress_args SHOW_PROGRESS)
+    endif ()
+    file(DOWNLOAD "${url}" "${file}" STATUS status LOG log ${inactivity_timeout} ${absolute_timeout} ${show_progress_args})
     list(GET status 0 err)
     list(GET status 1 msg)
     if(err)
index eff39c1..7033918 100644 (file)
 
 cmake_minimum_required(VERSION 3.5)
 
-execute_process(
-  COMMAND "@git_EXECUTABLE@" rev-list --max-count=1 HEAD
-  WORKING_DIRECTORY "@work_dir@"
-  RESULT_VARIABLE error_code
-  OUTPUT_VARIABLE head_sha
-  OUTPUT_STRIP_TRAILING_WHITESPACE
+function(get_hash_for_ref ref out_var err_var)
+  execute_process(
+    COMMAND "@git_EXECUTABLE@" rev-parse "${ref}"
+    WORKING_DIRECTORY "@work_dir@"
+    RESULT_VARIABLE error_code
+    OUTPUT_VARIABLE ref_hash
+    ERROR_VARIABLE error_msg
+    OUTPUT_STRIP_TRAILING_WHITESPACE
   )
-if(error_code)
-  message(FATAL_ERROR "Failed to get the hash for HEAD")
+  if(error_code)
+    set(${out_var} "" PARENT_SCOPE)
+  else()
+    set(${out_var} "${ref_hash}" PARENT_SCOPE)
+  endif()
+  set(${err_var} "${error_msg}" PARENT_SCOPE)
+endfunction()
+
+get_hash_for_ref(HEAD head_sha error_msg)
+if(head_sha STREQUAL "")
+  message(FATAL_ERROR "Failed to get the hash for HEAD:\n${error_msg}")
 endif()
 
+
 execute_process(
   COMMAND "@git_EXECUTABLE@" show-ref "@git_tag@"
   WORKING_DIRECTORY "@work_dir@"
   OUTPUT_VARIABLE show_ref_output
-  )
-# If a remote ref is asked for, which can possibly move around,
-# we must always do a fetch and checkout.
-if("${show_ref_output}" MATCHES "remotes")
-  set(is_remote_ref 1)
-else()
-  set(is_remote_ref 0)
-endif()
+)
+if(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/remotes/")
+  # Given a full remote/branch-name and we know about it already. Since
+  # branches can move around, we always have to fetch.
+  set(fetch_required YES)
+  set(checkout_name "@git_tag@")
+
+elseif(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/tags/")
+  # Given a tag name that we already know about. We don't know if the tag we
+  # have matches the remote though (tags can move), so we should fetch.
+  set(fetch_required YES)
+  set(checkout_name "@git_tag@")
+
+  # Special case to preserve backward compatibility: if we are already at the
+  # same commit as the tag we hold locally, don't do a fetch and assume the tag
+  # hasn't moved on the remote.
+  # FIXME: We should provide an option to always fetch for this case
+  get_hash_for_ref("@git_tag@" tag_sha error_msg)
+  if(tag_sha STREQUAL head_sha)
+    message(VERBOSE "Already at requested tag: ${tag_sha}")
+    return()
+  endif()
+
+elseif(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/heads/")
+  # Given a branch name without any remote and we already have a branch by that
+  # name. We might already have that branch checked out or it might be a
+  # different branch. It isn't safe to use a bare branch name without the
+  # remote, so do a fetch and replace the ref with one that includes the remote.
+  set(fetch_required YES)
+  set(checkout_name "@git_remote_name@/@git_tag@")
 
-# Tag is in the form <remote>/<tag> (i.e. origin/master) we must strip
-# the remote from the tag.
-if("${show_ref_output}" MATCHES "refs/remotes/@git_tag@")
-  string(REGEX MATCH "^([^/]+)/(.+)$" _unused "@git_tag@")
-  set(git_remote "${CMAKE_MATCH_1}")
-  set(git_tag "${CMAKE_MATCH_2}")
 else()
-  set(git_remote "@git_remote_name@")
-  set(git_tag "@git_tag@")
+  get_hash_for_ref("@git_tag@" tag_sha error_msg)
+  if(tag_sha STREQUAL head_sha)
+    # Have the right commit checked out already
+    message(VERBOSE "Already at requested ref: ${tag_sha}")
+    return()
+
+  elseif(tag_sha STREQUAL "")
+    # We don't know about this ref yet, so we have no choice but to fetch.
+    # We deliberately swallow any error message at the default log level
+    # because it can be confusing for users to see a failed git command.
+    # That failure is being handled here, so it isn't an error.
+    set(fetch_required YES)
+    set(checkout_name "@git_tag@")
+    if(NOT error_msg STREQUAL "")
+      message(VERBOSE "${error_msg}")
+    endif()
+
+  else()
+    # We have the commit, so we know we were asked to find a commit hash
+    # (otherwise it would have been handled further above), but we don't
+    # have that commit checked out yet
+    set(fetch_required NO)
+    set(checkout_name "@git_tag@")
+    if(NOT error_msg STREQUAL "")
+      message(WARNING "${error_msg}")
+    endif()
+
+  endif()
 endif()
 
-# This will fail if the tag does not exist (it probably has not been fetched
-# yet).
-execute_process(
-  COMMAND "@git_EXECUTABLE@" rev-list --max-count=1 "${git_tag}"
-  WORKING_DIRECTORY "@work_dir@"
-  RESULT_VARIABLE error_code
-  OUTPUT_VARIABLE tag_sha
-  OUTPUT_STRIP_TRAILING_WHITESPACE
+if(fetch_required)
+  message(VERBOSE "Fetching latest from the remote @git_remote_name@")
+  execute_process(
+    COMMAND "@git_EXECUTABLE@" fetch --tags --force "@git_remote_name@"
+    WORKING_DIRECTORY "@work_dir@"
+    COMMAND_ERROR_IS_FATAL ANY
   )
+endif()
 
-# Is the hash checkout out that we want?
-if(error_code OR is_remote_ref OR NOT ("${tag_sha}" STREQUAL "${head_sha}"))
+set(git_update_strategy "@git_update_strategy@")
+if(git_update_strategy STREQUAL "")
+  # Backward compatibility requires REBASE as the default behavior
+  set(git_update_strategy REBASE)
+endif()
+
+if(git_update_strategy MATCHES "^REBASE(_CHECKOUT)?$")
+  # Asked to potentially try to rebase first, maybe with fallback to checkout.
+  # We can't if we aren't already on a branch and we shouldn't if that local
+  # branch isn't tracking the one we want to checkout.
   execute_process(
-    COMMAND "@git_EXECUTABLE@" fetch
+    COMMAND "@git_EXECUTABLE@" symbolic-ref -q HEAD
     WORKING_DIRECTORY "@work_dir@"
-    RESULT_VARIABLE error_code
-    )
-  if(error_code)
-    message(FATAL_ERROR "Failed to fetch repository '@git_repository@'")
-  endif()
+    OUTPUT_VARIABLE current_branch
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    # Don't test for an error. If this isn't a branch, we get a non-zero error
+    # code but empty output.
+  )
 
-  if(is_remote_ref)
-    # Check if stash is needed
+  if(current_branch STREQUAL "")
+    # Not on a branch, checkout is the only sensible option since any rebase
+    # would always fail (and backward compatibility requires us to checkout in
+    # this situation)
+    set(git_update_strategy CHECKOUT)
+
+  else()
     execute_process(
-      COMMAND "@git_EXECUTABLE@" status --porcelain
+      COMMAND "@git_EXECUTABLE@" for-each-ref "--format='%(upstream:short)'" "${current_branch}"
       WORKING_DIRECTORY "@work_dir@"
-      RESULT_VARIABLE error_code
-      OUTPUT_VARIABLE repo_status
-      )
-    if(error_code)
-      message(FATAL_ERROR "Failed to get the status")
+      OUTPUT_VARIABLE upstream_branch
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY  # There is no error if no upstream is set
+    )
+    if(NOT upstream_branch STREQUAL checkout_name)
+      # Not safe to rebase when asked to checkout a different branch to the one
+      # we are tracking. If we did rebase, we could end up with arbitrary
+      # commits added to the ref we were asked to checkout if the current local
+      # branch happens to be able to rebase onto the target branch. There would
+      # be no error message and the user wouldn't know this was occurring.
+      set(git_update_strategy CHECKOUT)
     endif()
-    string(LENGTH "${repo_status}" need_stash)
 
-    # If not in clean state, stash changes in order to be able to perform a
-    # rebase or checkout without losing those changes permanently
-    if(need_stash)
-      execute_process(
-        COMMAND "@git_EXECUTABLE@" stash save @git_stash_save_options@
-        WORKING_DIRECTORY "@work_dir@"
-        RESULT_VARIABLE error_code
-        )
-      if(error_code)
-        message(FATAL_ERROR "Failed to stash changes")
-      endif()
-    endif()
+  endif()
+elseif(NOT git_update_strategy STREQUAL "CHECKOUT")
+  message(FATAL_ERROR "Unsupported git update strategy: ${git_update_strategy}")
+endif()
 
-    if("@git_update_strategy@" STREQUAL "CHECKOUT")
-      execute_process(
-        COMMAND "@git_EXECUTABLE@" checkout "${git_remote}/${git_tag}"
-        WORKING_DIRECTORY "@work_dir@"
-        RESULT_VARIABLE error_code
-        )
-      if(error_code)
-        message(FATAL_ERROR "Failed to checkout tag: '${git_remote}/${git_tag}'")
-      endif()
-    else()
-      # Pull changes from the remote branch
-      execute_process(
-        COMMAND "@git_EXECUTABLE@" rebase "${git_remote}/${git_tag}"
-        WORKING_DIRECTORY "@work_dir@"
-        RESULT_VARIABLE error_code
-        OUTPUT_VARIABLE rebase_output
-        ERROR_VARIABLE  rebase_output
-        )
-      if(error_code)
-        # Rebase failed, undo the rebase attempt before continuing
-        execute_process(
-          COMMAND "@git_EXECUTABLE@" rebase --abort
-          WORKING_DIRECTORY "@work_dir@"
-        )
-
-        if(NOT "@git_update_strategy@" STREQUAL "REBASE_CHECKOUT")
-          # Not allowed to do a checkout as a fallback, so cannot proceed
-          if(need_stash)
-            execute_process(
-              COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
-              WORKING_DIRECTORY "@work_dir@"
-              )
-          endif()
-          message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'."
-                              "\nOutput from the attempted rebase follows:"
-                              "\n${rebase_output}"
-                              "\n\nYou will have to resolve the conflicts manually")
-        endif()
-
-        # Fall back to checkout. We create an annotated tag so that the user
-        # can manually inspect the situation and revert if required.
-        # We can't log the failed rebase output because MSVC sees it and
-        # intervenes, causing the build to fail even though it completes.
-        # Write it to a file instead.
-        string(TIMESTAMP tag_timestamp "%Y%m%dT%H%M%S" UTC)
-        set(tag_name _cmake_ExternalProject_moved_from_here_${tag_timestamp}Z)
-        set(error_log_file ${CMAKE_CURRENT_LIST_DIR}/rebase_error_${tag_timestamp}Z.log)
-        file(WRITE ${error_log_file} "${rebase_output}")
-        message(WARNING "Rebase failed, output has been saved to ${error_log_file}"
-                        "\nFalling back to checkout, previous commit tagged as ${tag_name}")
-        execute_process(
-          COMMAND "@git_EXECUTABLE@" tag -a
-                  -m "ExternalProject attempting to move from here to ${git_remote}/${git_tag}"
-                  ${tag_name}
-          WORKING_DIRECTORY "@work_dir@"
-          RESULT_VARIABLE error_code
-        )
-        if(error_code)
-          message(FATAL_ERROR "Failed to add marker tag")
-        endif()
 
-        execute_process(
-          COMMAND "@git_EXECUTABLE@" checkout "${git_remote}/${git_tag}"
-          WORKING_DIRECTORY "@work_dir@"
-          RESULT_VARIABLE error_code
-        )
-        if(error_code)
-          message(FATAL_ERROR "Failed to checkout : '${git_remote}/${git_tag}'")
-        endif()
+# Check if stash is needed
+execute_process(
+  COMMAND "@git_EXECUTABLE@" status --porcelain
+  WORKING_DIRECTORY "@work_dir@"
+  RESULT_VARIABLE error_code
+  OUTPUT_VARIABLE repo_status
+)
+if(error_code)
+  message(FATAL_ERROR "Failed to get the status")
+endif()
+string(LENGTH "${repo_status}" need_stash)
 
-      endif()
-    endif()
+# If not in clean state, stash changes in order to be able to perform a
+# rebase or checkout without losing those changes permanently
+if(need_stash)
+  execute_process(
+    COMMAND "@git_EXECUTABLE@" stash save @git_stash_save_options@
+    WORKING_DIRECTORY "@work_dir@"
+    COMMAND_ERROR_IS_FATAL ANY
+  )
+endif()
 
-    if(need_stash)
-      execute_process(
-        COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
-        WORKING_DIRECTORY "@work_dir@"
-        RESULT_VARIABLE error_code
-        )
-      if(error_code)
-        # Stash pop --index failed: Try again dropping the index
-        execute_process(
-          COMMAND "@git_EXECUTABLE@" reset --hard --quiet
-          WORKING_DIRECTORY "@work_dir@"
-          RESULT_VARIABLE error_code
-          )
+if(git_update_strategy STREQUAL "CHECKOUT")
+  execute_process(
+    COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}"
+    WORKING_DIRECTORY "@work_dir@"
+    COMMAND_ERROR_IS_FATAL ANY
+  )
+else()
+  execute_process(
+    COMMAND "@git_EXECUTABLE@" rebase "${checkout_name}"
+    WORKING_DIRECTORY "@work_dir@"
+    RESULT_VARIABLE error_code
+    OUTPUT_VARIABLE rebase_output
+    ERROR_VARIABLE  rebase_output
+  )
+  if(error_code)
+    # Rebase failed, undo the rebase attempt before continuing
+    execute_process(
+      COMMAND "@git_EXECUTABLE@" rebase --abort
+      WORKING_DIRECTORY "@work_dir@"
+    )
+
+    if(NOT git_update_strategy STREQUAL "REBASE_CHECKOUT")
+      # Not allowed to do a checkout as a fallback, so cannot proceed
+      if(need_stash)
         execute_process(
-          COMMAND "@git_EXECUTABLE@" stash pop --quiet
+          COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
           WORKING_DIRECTORY "@work_dir@"
-          RESULT_VARIABLE error_code
-          )
-        if(error_code)
-          # Stash pop failed: Restore previous state.
-          execute_process(
-            COMMAND "@git_EXECUTABLE@" reset --hard --quiet ${head_sha}
-            WORKING_DIRECTORY "@work_dir@"
-          )
-          execute_process(
-            COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
-            WORKING_DIRECTORY "@work_dir@"
           )
-          message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'."
-                              "\nYou will have to resolve the conflicts manually")
-        endif()
       endif()
+      message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'."
+                          "\nOutput from the attempted rebase follows:"
+                          "\n${rebase_output}"
+                          "\n\nYou will have to resolve the conflicts manually")
     endif()
-  else()
+
+    # Fall back to checkout. We create an annotated tag so that the user
+    # can manually inspect the situation and revert if required.
+    # We can't log the failed rebase output because MSVC sees it and
+    # intervenes, causing the build to fail even though it completes.
+    # Write it to a file instead.
+    string(TIMESTAMP tag_timestamp "%Y%m%dT%H%M%S" UTC)
+    set(tag_name _cmake_ExternalProject_moved_from_here_${tag_timestamp}Z)
+    set(error_log_file ${CMAKE_CURRENT_LIST_DIR}/rebase_error_${tag_timestamp}Z.log)
+    file(WRITE ${error_log_file} "${rebase_output}")
+    message(WARNING "Rebase failed, output has been saved to ${error_log_file}"
+                    "\nFalling back to checkout, previous commit tagged as ${tag_name}")
     execute_process(
-      COMMAND "@git_EXECUTABLE@" checkout "${git_tag}"
+      COMMAND "@git_EXECUTABLE@" tag -a
+              -m "ExternalProject attempting to move from here to ${checkout_name}"
+              ${tag_name}
       WORKING_DIRECTORY "@work_dir@"
-      RESULT_VARIABLE error_code
-      )
-    if(error_code)
-      message(FATAL_ERROR "Failed to checkout tag: '${git_tag}'")
-    endif()
+      COMMAND_ERROR_IS_FATAL ANY
+    )
+
+    execute_process(
+      COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}"
+      WORKING_DIRECTORY "@work_dir@"
+      COMMAND_ERROR_IS_FATAL ANY
+    )
   endif()
+endif()
 
-  set(init_submodules "@init_submodules@")
-  if(init_submodules)
+if(need_stash)
+  # Put back the stashed changes
+  execute_process(
+    COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
+    WORKING_DIRECTORY "@work_dir@"
+    RESULT_VARIABLE error_code
+    )
+  if(error_code)
+    # Stash pop --index failed: Try again dropping the index
+    execute_process(
+      COMMAND "@git_EXECUTABLE@" reset --hard --quiet
+      WORKING_DIRECTORY "@work_dir@"
+    )
     execute_process(
-      COMMAND "@git_EXECUTABLE@" submodule update @git_submodules_recurse@ --init @git_submodules@
+      COMMAND "@git_EXECUTABLE@" stash pop --quiet
       WORKING_DIRECTORY "@work_dir@"
       RESULT_VARIABLE error_code
+    )
+    if(error_code)
+      # Stash pop failed: Restore previous state.
+      execute_process(
+        COMMAND "@git_EXECUTABLE@" reset --hard --quiet ${head_sha}
+        WORKING_DIRECTORY "@work_dir@"
       )
+      execute_process(
+        COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
+        WORKING_DIRECTORY "@work_dir@"
+      )
+      message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'."
+                          "\nYou will have to resolve the conflicts manually")
+    endif()
   endif()
-  if(error_code)
-    message(FATAL_ERROR "Failed to update submodules in: '@work_dir@'")
-  endif()
+endif()
+
+set(init_submodules "@init_submodules@")
+if(init_submodules)
+  execute_process(
+    COMMAND "@git_EXECUTABLE@" submodule update @git_submodules_recurse@ --init @git_submodules@
+    WORKING_DIRECTORY "@work_dir@"
+    COMMAND_ERROR_IS_FATAL ANY
+  )
 endif()
index 8bbaf5a..5652508 100644 (file)
@@ -1,6 +1,8 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
+include_guard(GLOBAL)
+
 #[=======================================================================[.rst:
 ExternalProject
 ---------------
@@ -56,6 +58,8 @@ External Project Definition
       (see *Logging Options* below).
 
     ``LOG_DIR <dir>``
+      .. versionadded:: 3.14
+
       Directory in which to store the logs of each step.
 
     ``DOWNLOAD_DIR <dir>``
@@ -144,6 +148,9 @@ External Project Definition
         is determined by inspecting the actual content rather than using logic
         based on the file extension.
 
+        .. versionchanged:: 3.7
+          Multiple URLs are allowed.
+
       ``URL_HASH <algo>=<hashValue>``
         Hash of the archive file to be downloaded. The argument should be of
         the form ``<algo>=<hashValue>`` where ``algo`` can be any of the hashing
@@ -164,6 +171,8 @@ External Project Definition
         of code internal to the ``ExternalProject`` module.
 
       ``DOWNLOAD_NO_EXTRACT <bool>``
+        .. versionadded:: 3.6
+
         Allows the extraction part of the download step to be disabled by
         passing a boolean true value for this option. If this option is not
         given, the downloaded contents will be unpacked automatically if
@@ -180,15 +189,23 @@ External Project Definition
         Maximum time allowed for file download operations.
 
       ``INACTIVITY_TIMEOUT <seconds>``
+        .. versionadded:: 3.19
+
         Terminate the operation after a period of inactivity.
 
       ``HTTP_USERNAME <username>``
+        .. versionadded:: 3.7
+
         Username for the download operation if authentication is required.
 
       ``HTTP_PASSWORD <password>``
+        .. versionadded:: 3.7
+
         Password for the download operation if authentication is required.
 
       ``HTTP_HEADER <header1> [<header2>...]``
+        .. versionadded:: 3.7
+
         Provides an arbitrary list of HTTP headers for the download operation.
         This can be useful for accessing content in systems like AWS, etc.
 
@@ -201,6 +218,9 @@ External Project Definition
         cannot be provided, this option can be an alternative verification
         measure.
 
+        .. versionchanged:: 3.6
+          This option also applies to ``git clone`` invocations.
+
       ``TLS_CAINFO <file>``
         Specify a custom certificate authority file to use if ``TLS_VERIFY``
         is enabled. If this option is not specified, the value of the
@@ -208,6 +228,8 @@ External Project Definition
         :command:`file(DOWNLOAD)`)
 
       ``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 ``CMAKE_NETRC``
         variable will be used instead (see :command:`file(DOWNLOAD)`)
@@ -225,11 +247,16 @@ External Project Definition
           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 ``CMAKE_NETRC_FILE`` variable will
         be used instead (see :command:`file(DOWNLOAD)`)
 
+      .. versionadded:: 3.1
+        Added support for `tbz2`, `.tar.xz`, `.txz`, and `.7z` extensions.
+
     *Git*
       NOTE: A git version of 1.6.5 or later is required if this download method
       is used.
@@ -267,22 +294,30 @@ External Project Definition
 
       ``GIT_SUBMODULES <module>...``
         Specific git submodules that should also be updated. If this option is
-        not provided, all git submodules will be updated. When :policy:`CMP0097`
-        is set to ``NEW`` if this value is set to an empty string then no submodules
-        are initialized or updated.
+        not provided, all git submodules will be updated.
+
+        .. versionchanged:: 3.16
+          When :policy:`CMP0097` is set to ``NEW``, if this value is set
+          to an empty string then no submodules are initialized or updated.
 
       ``GIT_SUBMODULES_RECURSE <bool>``
+        .. versionadded:: 3.17
+
         Specify whether git submodules (if any) should update recursively by
         passing the ``--recursive`` flag to ``git submodule update``.
         If not specified, the default is on.
 
       ``GIT_SHALLOW <bool>``
+        .. versionadded:: 3.6
+
         When this option is enabled, the ``git clone`` operation will be given
         the ``--depth 1`` option. This performs a shallow clone, which avoids
         downloading the whole history and instead retrieves just the commit
         denoted by the ``GIT_TAG`` option.
 
       ``GIT_PROGRESS <bool>``
+        .. versionadded:: 3.8
+
         When enabled, this option instructs the ``git clone`` operation to
         report its progress by passing it the ``--progress`` option. Without
         this option, the clone step for large projects may appear to make the
@@ -292,12 +327,16 @@ External Project Definition
         overly noisy if lots of external projects are used.
 
       ``GIT_CONFIG <option1> [<option2>...]``
+        .. versionadded:: 3.8
+
         Specify a list of config options to pass to ``git clone``. Each option
         listed will be transformed into its own ``--config <option>`` on the
         ``git clone`` command line, with each option required to be in the
         form ``key=value``.
 
       ``GIT_REMOTE_UPDATE_STRATEGY <strategy>``
+        .. versionadded:: 3.18
+
         When ``GIT_TAG`` refers to a remote branch, this option can be used to
         specify how the update step behaves.  The ``<strategy>`` must be one of
         the following:
@@ -379,6 +418,8 @@ External Project Definition
       :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
     ``UPDATE_DISCONNECTED <bool>``
+      .. versionadded:: 3.2
+
       When enabled, this option causes the update step to be skipped. It does
       not, however, prevent the download step. The update step can still be
       added as a step target (see :command:`ExternalProject_Add_StepTargets`)
@@ -436,6 +477,8 @@ External Project Definition
       ``CONFIGURE_COMMAND`` option.
 
     ``CMAKE_GENERATOR_PLATFORM <platform>``
+      .. versionadded:: 3.1
+
       Pass a generator-specific platform name to the CMake command (see
       :variable:`CMAKE_GENERATOR_PLATFORM`). It is an error to provide this
       option without the ``CMAKE_GENERATOR`` option.
@@ -446,6 +489,8 @@ External Project Definition
       option without the ``CMAKE_GENERATOR`` option.
 
     ``CMAKE_GENERATOR_INSTANCE <instance>``
+      .. versionadded:: 3.11
+
       Pass a generator-specific instance selection to the CMake command (see
       :variable:`CMAKE_GENERATOR_INSTANCE`). It is an error to provide this
       option without the ``CMAKE_GENERATOR`` option.
@@ -454,8 +499,10 @@ External Project Definition
       The specified arguments are passed to the ``cmake`` command line. They
       can be any argument the ``cmake`` command understands, not just cache
       values defined by ``-D...`` arguments (see also
-      :manual:`CMake Options <cmake(1)>`). In addition, arguments may use
-      :manual:`generator expressions <cmake-generator-expressions(7)>`.
+      :manual:`CMake Options <cmake(1)>`).
+
+      .. versionadded:: 3.3
+        Arguments may use :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
     ``CMAKE_CACHE_ARGS <arg>...``
       This is an alternate way of specifying cache variables where command line
@@ -463,10 +510,14 @@ External Project Definition
       the form ``-Dvar:STRING=value``, which are then transformed into
       CMake :command:`set` commands with the ``FORCE`` option used. These
       ``set()`` commands are written to a pre-load script which is then applied
-      using the :manual:`cmake -C <cmake(1)>` command line option. Arguments
-      may use :manual:`generator expressions <cmake-generator-expressions(7)>`.
+      using the :manual:`cmake -C <cmake(1)>` command line option.
+
+      .. versionadded:: 3.3
+        Arguments may use :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
     ``CMAKE_CACHE_DEFAULT_ARGS <arg>...``
+      .. versionadded:: 3.2
+
       This is the same as the ``CMAKE_CACHE_ARGS`` option except the ``set()``
       commands do not include the ``FORCE`` keyword. This means the values act
       as initial defaults only and will not override any variables already set
@@ -474,20 +525,37 @@ External Project Definition
       different behavior depending on whether the build starts from a fresh
       build directory or re-uses previous build contents.
 
-      If the CMake generator is the ``Green Hills MULTI`` and not overridden then
-      the original project's settings for the GHS toolset and target system
-      customization cache variables are propagated into the external project.
+      .. versionadded:: 3.15
+        If the CMake generator is the ``Green Hills MULTI`` and not overridden then
+        the original project's settings for the GHS toolset and target system
+        customization cache variables are propagated into the external project.
 
     ``SOURCE_SUBDIR <dir>``
+      .. versionadded:: 3.7
+
       When no ``CONFIGURE_COMMAND`` option is specified, the configure step
       assumes the external project has a ``CMakeLists.txt`` file at the top of
       its source tree (i.e. in ``SOURCE_DIR``). The ``SOURCE_SUBDIR`` option
       can be used to point to an alternative directory within the source tree
       to use as the top of the CMake source tree instead. This must be a
       relative path and it will be interpreted as being relative to
-      ``SOURCE_DIR``.  When ``BUILD_IN_SOURCE 1`` is specified, the
-      ``BUILD_COMMAND`` is used to point to an alternative directory within the
-      source tree.
+      ``SOURCE_DIR``.
+
+      .. versionadded:: 3.14
+        When ``BUILD_IN_SOURCE`` option is enabled, the ``BUILD_COMMAND``
+        is used to point to an alternative directory within the source tree.
+
+    ``CONFIGURE_HANDLED_BY_BUILD <bool>``
+      .. versionadded:: 3.20
+
+      Enabling this option relaxes the dependencies of the configure step on
+      other external projects to order-only. This means the configure step will
+      be executed after its external project dependencies are built but it will
+      not be marked dirty when one of its external project dependencies is
+      rebuilt. This option can be enabled when the build step is smart enough
+      to figure out if the configure step needs to be rerun. CMake and Meson are
+      examples of build systems whose build step is smart enough to know if the
+      configure step needs to be rerun.
 
   **Build Step Options:**
     If the configure step assumed the external project uses CMake as its build
@@ -524,6 +592,8 @@ External Project Definition
       developers might modify the sources in ``SOURCE_DIR``).
 
     ``BUILD_BYPRODUCTS <file>...``
+      .. versionadded:: 3.2
+
       Specifies files that will be generated by the build command but which
       might or might not have their modification time updated by subsequent
       builds. These ultimately get passed through as ``BYPRODUCTS`` to the
@@ -578,6 +648,8 @@ External Project Definition
       ``TEST_AFTER_INSTALL`` are enabled, the latter is silently ignored.
 
     ``TEST_EXCLUDE_FROM_MAIN <bool>``
+      .. versionadded:: 3.2
+
       If enabled, the main build's default ALL target will not depend on the
       test step. This can be a useful way of ensuring the test step is defined
       but only gets invoked when manually requested.
@@ -597,6 +669,8 @@ External Project Definition
       When enabled, the output of the update step is logged to files.
 
     ``LOG_PATCH <bool>``
+      .. versionadded:: 3.14
+
       When enabled, the output of the patch step is logged to files.
 
     ``LOG_CONFIGURE <bool>``
@@ -612,10 +686,14 @@ External Project Definition
       When enabled, the output of the test step is logged to files.
 
     ``LOG_MERGED_STDOUTERR <bool>``
+      .. versionadded:: 3.14
+
       When enabled, stdout and stderr will be merged for any step whose
       output is being logged to files.
 
     ``LOG_OUTPUT_ON_FAILURE <bool>``
+      .. versionadded:: 3.14
+
       This option only has an effect if at least one of the other ``LOG_<step>``
       options is enabled.  If an error occurs for a step which has logging to
       file enabled, that step's output will be printed to the console if
@@ -624,6 +702,8 @@ External Project Definition
       console.
 
   **Terminal Access Options:**
+    .. versionadded:: 3.4
+
     Steps can be given direct access to the terminal in some cases. Giving a
     step access to the terminal may allow it to receive terminal input if
     required, such as for authentication details not provided by other options.
@@ -673,8 +753,9 @@ External Project Definition
       discussion of the effects of this option.
 
     ``INDEPENDENT_STEP_TARGETS <step-target>...``
-      Deprecated.  This is allowed only if policy :policy:`CMP0114` is not set
-      to ``NEW``.
+      .. deprecated:: 3.19
+        This is allowed only if policy :policy:`CMP0114` is not set to ``NEW``.
+
       Generates custom targets for the specified steps and prevent these targets
       from having the usual dependencies applied to them. If this option is not
       specified, the default value is taken from the
@@ -780,6 +861,8 @@ control needed to implement such step-level capabilities.
     Files on which this custom step depends.
 
   ``INDEPENDENT <bool>``
+    .. versionadded:: 3.19
+
     Specifies whether this step is independent of the external dependencies
     specified by the :command:`ExternalProject_Add`'s ``DEPENDS`` option.
     The default is ``FALSE``.  Steps marked as independent may depend only
@@ -795,6 +878,8 @@ control needed to implement such step-level capabilities.
     on the external targets, but may depend on targets for other steps.
 
   ``BYPRODUCTS <file>...``
+    .. versionadded:: 3.2
+
     Files that will be generated by this custom step but which might or might
     not have their modification time updated by subsequent builds. This list of
     files will ultimately be passed through as the ``BYPRODUCTS`` option to the
@@ -831,6 +916,12 @@ control needed to implement such step-level capabilities.
   corresponding property values defined in the original call to
   :command:`ExternalProject_Add`.
 
+  .. versionadded:: 3.3
+    Token replacement is extended to byproducts.
+
+  .. versionadded:: 3.11
+    The ``<DOWNLOAD_DIR>`` substitution token.
+
 .. command:: ExternalProject_Add_StepTargets
 
   The ``ExternalProject_Add_StepTargets()`` function generates targets for the
@@ -868,15 +959,16 @@ control needed to implement such step-level capabilities.
   can save having to repeatedly specify the same set of step targets when
   multiple external projects are being defined.
 
-  If :policy:`CMP0114` is set to ``NEW``, step targets are fully responsible
-  for holding the custom commands implementing their steps.  The primary target
-  created by ``ExternalProject_Add`` depends on the step targets, and the
-  step targets depend on each other.  The target-level dependencies match
-  the file-level dependencies used by the custom commands for each step.
-  The targets for steps created with :command:`ExternalProject_Add_Step`'s
-  ``INDEPENDENT`` option do not depend on the external targets specified
-  by :command:`ExternalProject_Add`'s ``DEPENDS`` option.  The predefined
-  steps ``mkdir``, ``download``, ``update``, and ``patch`` are independent.
+  .. versionadded:: 3.19
+    If :policy:`CMP0114` is set to ``NEW``, step targets are fully responsible
+    for holding the custom commands implementing their steps.  The primary target
+    created by ``ExternalProject_Add`` depends on the step targets, and the
+    step targets depend on each other.  The target-level dependencies match
+    the file-level dependencies used by the custom commands for each step.
+    The targets for steps created with :command:`ExternalProject_Add_Step`'s
+    ``INDEPENDENT`` option do not depend on the external targets specified
+    by :command:`ExternalProject_Add`'s ``DEPENDS`` option.  The predefined
+    steps ``mkdir``, ``download``, ``update``, and ``patch`` are independent.
 
   If :policy:`CMP0114` is not ``NEW``, the following deprecated behavior
   is available:
@@ -901,6 +993,8 @@ control needed to implement such step-level capabilities.
 
 .. command:: ExternalProject_Add_StepDependencies
 
+  .. versionadded:: 3.2
+
   The ``ExternalProject_Add_StepDependencies()`` function can be used to add
   dependencies to a step. The dependencies added must be targets CMake already
   knows about (these can be ordinary executable or library targets, custom
@@ -1019,60 +1113,37 @@ cmake_policy(PUSH)
 cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
 cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
 
-# Pre-compute a regex to match documented keywords for each command.
-math(EXPR _ep_documentation_line_count "${CMAKE_CURRENT_LIST_LINE} - 4")
-file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines
-     LIMIT_COUNT ${_ep_documentation_line_count}
-     REGEX "^\\.\\. command:: [A-Za-z0-9_]+|^ +``[A-Z0-9_]+ [^`]*``$")
-foreach(line IN LISTS lines)
-  if("${line}" MATCHES "^\\.\\. command:: ([A-Za-z0-9_]+)")
-    if(_ep_func)
-      string(APPEND _ep_keywords_${_ep_func} ")$")
-    endif()
-    set(_ep_func "${CMAKE_MATCH_1}")
-    #message("function [${_ep_func}]")
-    set(_ep_keywords_${_ep_func} "^(")
-    set(_ep_keyword_sep)
-  elseif("${line}" MATCHES "^ +``([A-Z0-9_]+) [^`]*``$")
-    set(_ep_key "${CMAKE_MATCH_1}")
-    # COMMAND should never be included as a keyword,
-    # for ExternalProject_Add(), as it is treated as a
-    # special case by argument parsing as an extension
-    # of a previous ..._COMMAND
-    if("x${_ep_key}x" STREQUAL "xCOMMANDx" AND
-       "x${_ep_func}x" STREQUAL "xExternalProject_Addx")
-      continue()
-    endif()
-    #message("  keyword [${_ep_key}]")
-    string(APPEND _ep_keywords_${_ep_func}
-      "${_ep_keyword_sep}${_ep_key}")
-    set(_ep_keyword_sep "|")
-  endif()
-endforeach()
-if(_ep_func)
-  string(APPEND _ep_keywords_${_ep_func} ")$")
-endif()
-
-# Save regex matching supported hash algorithm names.
-set(_ep_hash_algos "MD5|SHA1|SHA224|SHA256|SHA384|SHA512|SHA3_224|SHA3_256|SHA3_384|SHA3_512")
-set(_ep_hash_regex "^(${_ep_hash_algos})=([0-9A-Fa-f]+)$")
+macro(_ep_get_hash_algos out_var)
+  set(${out_var}
+    MD5
+    SHA1
+    SHA224
+    SHA256
+    SHA384
+    SHA512
+    SHA3_224
+    SHA3_256
+    SHA3_384
+    SHA3_512
+  )
+endmacro()
 
-set(_ExternalProject_SELF "${CMAKE_CURRENT_LIST_FILE}")
-get_filename_component(_ExternalProject_SELF_DIR "${_ExternalProject_SELF}" PATH)
+macro(_ep_get_hash_regex out_var)
+  _ep_get_hash_algos(${out_var})
+  list(JOIN ${out_var} "|" ${out_var})
+  set(${out_var} "^(${${out_var}})=([0-9A-Fa-f]+)$")
+endmacro()
 
-function(_ep_parse_arguments f name ns args)
+function(_ep_parse_arguments f keywords name ns args)
   # Transfer the arguments to this function into target properties for the
   # new custom target we just added so that we can set up all the build steps
   # correctly based on target properties.
   #
-  # We loop through ARGN and consider the namespace starting with an
+  # Because some keywords can be repeated, we can't use cmake_parse_arguments().
+  # Instead, we loop through ARGN and consider the namespace starting with an
   # upper-case letter followed by at least two more upper-case letters,
   # numbers or underscores to be keywords.
 
-  if(NOT DEFINED _ExternalProject_SELF)
-    message(FATAL_ERROR "error: ExternalProject module must be explicitly included before using ${f} function")
-  endif()
-
   set(key)
 
   foreach(arg IN LISTS args)
@@ -1081,7 +1152,7 @@ function(_ep_parse_arguments f name ns args)
     if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
         NOT (("x${arg}x" STREQUAL "x${key}x") AND ("x${key}x" STREQUAL "xCOMMANDx")) AND
         NOT arg MATCHES "^(TRUE|FALSE)$")
-      if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
+      if(arg IN_LIST keywords)
         set(is_value 0)
       endif()
     endif()
@@ -1106,9 +1177,6 @@ function(_ep_parse_arguments f name ns args)
       endif()
     else()
       set(key "${arg}")
-      if(key MATCHES GIT)
-       get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
-      endif()
     endif()
   endforeach()
 endfunction()
@@ -1330,14 +1398,17 @@ function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_r
   if("${git_tag}" STREQUAL "")
     message(FATAL_ERROR "Tag for git checkout should not be empty.")
   endif()
-  if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.6)
-    set(git_stash_save_options --all --quiet)
-  else()
-    set(git_stash_save_options --quiet)
+  set(git_stash_save_options --quiet)
+  if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7)
+    # This avoids stashing files covered by .gitignore
+    list(APPEND git_stash_save_options --include-untracked)
+  elseif(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.6)
+    # Untracked files, but also ignored files, so potentially slower
+    list(APPEND git_stash_save_options --all)
   endif()
 
   configure_file(
-      "${_ExternalProject_SELF_DIR}/ExternalProject-gitupdate.cmake.in"
+      "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject-gitupdate.cmake.in"
       "${script_filename}"
       @ONLY
   )
@@ -1366,6 +1437,7 @@ function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout inac
     set(SHOW_PROGRESS "SHOW_PROGRESS")
   endif()
 
+  _ep_get_hash_regex(_ep_hash_regex)
   if("${hash}" MATCHES "${_ep_hash_regex}")
     set(ALGO "${CMAKE_MATCH_1}")
     string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
@@ -1446,13 +1518,14 @@ function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout inac
   # * USERPWD_ARGS
   # * HTTP_HEADERS_ARGS
   configure_file(
-      "${_ExternalProject_SELF_DIR}/ExternalProject-download.cmake.in"
+      "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject-download.cmake.in"
       "${script_filename}"
       @ONLY
   )
 endfunction()
 
 function(_ep_write_verifyfile_script script_filename LOCAL hash)
+  _ep_get_hash_regex(_ep_hash_regex)
   if("${hash}" MATCHES "${_ep_hash_regex}")
     set(ALGO "${CMAKE_MATCH_1}")
     string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
@@ -1466,7 +1539,7 @@ function(_ep_write_verifyfile_script script_filename LOCAL hash)
   # * EXPECT_VALUE
   # * LOCAL
   configure_file(
-      "${_ExternalProject_SELF_DIR}/ExternalProject-verify.cmake.in"
+      "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject-verify.cmake.in"
       "${script_filename}"
       @ONLY
   )
@@ -1984,8 +2057,10 @@ if(result)
     message(FATAL_ERROR \"\${msg}\")
   endif()
 else()
-  set(msg \"${name} ${step} command succeeded.  See also ${logbase}-*.log\")
-  message(STATUS \"\${msg}\")
+  if(NOT \"${CMAKE_GENERATOR}\" MATCHES \"Ninja\")
+    set(msg \"${name} ${step} command succeeded.  See also ${logbase}-*.log\")
+    message(STATUS \"\${msg}\")
+  endif()
 endif()
 ")
   file(GENERATE OUTPUT "${script}" CONTENT "${code}")
@@ -2153,7 +2228,21 @@ function(ExternalProject_Add_Step name step)
   _ep_get_complete_stampfile(${name} complete_stamp_file)
   _ep_get_step_stampfile(${name} ${step} stamp_file)
 
-  _ep_parse_arguments(ExternalProject_Add_Step
+  set(keywords
+    COMMAND
+    COMMENT
+    DEPENDEES
+    DEPENDERS
+    DEPENDS
+    INDEPENDENT
+    BYPRODUCTS
+    ALWAYS
+    EXCLUDE_FROM_MAIN
+    WORKING_DIRECTORY
+    LOG
+    USES_TERMINAL
+  )
+  _ep_parse_arguments(ExternalProject_Add_Step "${keywords}"
                       ${name} _EP_${step}_ "${ARGN}")
 
   get_property(independent TARGET ${name} PROPERTY _EP_${step}_INDEPENDENT)
@@ -2536,10 +2625,13 @@ function(_ep_add_download_command name)
       --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args} ${src_name})
     list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
   elseif(git_repository)
-    unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
-    find_package(Git QUIET)
-    if(NOT GIT_EXECUTABLE)
-      message(FATAL_ERROR "error: could not find git for clone of ${name}")
+    # FetchContent gives us these directly, so don't try to recompute them
+    if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
+      unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
+      find_package(Git QUIET)
+      if(NOT GIT_EXECUTABLE)
+        message(FATAL_ERROR "error: could not find git for clone of ${name}")
+      endif()
     endif()
 
     _ep_get_git_submodules_recurse(git_submodules_recurse)
@@ -2571,6 +2663,10 @@ function(_ep_add_download_command name)
     get_property(git_progress TARGET ${name} PROPERTY _EP_GIT_PROGRESS)
     get_property(git_config TARGET ${name} PROPERTY _EP_GIT_CONFIG)
 
+    # Make checkouts quiet when checking out a git hash (this avoids the
+    # very noisy detached head message)
+    list(PREPEND git_config advice.detachedHead=false)
+
     # For the download step, and the git clone operation, only the repository
     # should be recorded in a configured RepositoryInfo file. If the repo
     # changes, the clone script should be run again. But if only the tag
@@ -2643,7 +2739,10 @@ function(_ep_add_download_command name)
   elseif(url)
     get_filename_component(work_dir "${source_dir}" PATH)
     get_property(hash TARGET ${name} PROPERTY _EP_URL_HASH)
+    _ep_get_hash_regex(_ep_hash_regex)
     if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
+      _ep_get_hash_algos(_ep_hash_algos)
+      list(JOIN _ep_hash_algos "|" _ep_hash_algos)
       message(FATAL_ERROR "URL_HASH is set to\n  ${hash}\n"
         "but must be ALGO=value where ALGO is\n  ${_ep_hash_algos}\n"
         "and value is a hex string.")
@@ -2857,10 +2956,13 @@ function(_ep_add_update_command name)
       --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args})
     set(always 1)
   elseif(git_repository)
-    unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
-    find_package(Git QUIET)
-    if(NOT GIT_EXECUTABLE)
-      message(FATAL_ERROR "error: could not find git for fetch of ${name}")
+    # FetchContent gives us these directly, so don't try to recompute them
+    if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
+      unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
+      find_package(Git QUIET)
+      if(NOT GIT_EXECUTABLE)
+        message(FATAL_ERROR "error: could not find git for fetch of ${name}")
+      endif()
     endif()
     set(work_dir ${source_dir})
     set(comment "Performing update step for '${name}'")
@@ -3001,6 +3103,23 @@ function(_ep_add_patch_command name)
   )
 endfunction()
 
+function(_ep_get_file_deps var name)
+  set(file_deps)
+
+  get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
+  foreach(dep IN LISTS deps)
+    get_property(dep_type TARGET ${dep} PROPERTY TYPE)
+    if(dep_type STREQUAL "UTILITY")
+      get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
+      if(is_ep)
+        _ep_get_step_stampfile(${dep} "done" done_stamp_file)
+        list(APPEND file_deps ${done_stamp_file})
+      endif()
+    endif()
+  endforeach()
+
+  set("${var}" "${file_deps}" PARENT_SCOPE)
+endfunction()
 
 function(_ep_extract_configure_command var name)
   get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
@@ -3109,19 +3228,13 @@ endfunction()
 function(_ep_add_configure_command name)
   ExternalProject_Get_Property(${name} binary_dir tmp_dir)
 
-  # Depend on other external projects (file-level).
   set(file_deps)
-  get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
-  foreach(dep IN LISTS deps)
-    get_property(dep_type TARGET ${dep} PROPERTY TYPE)
-    if(dep_type STREQUAL "UTILITY")
-      get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
-      if(is_ep)
-        _ep_get_step_stampfile(${dep} "done" done_stamp_file)
-        list(APPEND file_deps ${done_stamp_file})
-      endif()
-    endif()
-  endforeach()
+  get_property(configure_handled_by_build TARGET ${name}
+               PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+  if(NOT configure_handled_by_build)
+    # Depend on other external projects (file-level)
+    _ep_get_file_deps(file_deps ${name})
+  endif()
 
   _ep_extract_configure_command(cmd ${name})
 
@@ -3172,6 +3285,14 @@ endfunction()
 function(_ep_add_build_command name)
   ExternalProject_Get_Property(${name} binary_dir)
 
+  set(file_deps)
+  get_property(configure_handled_by_build TARGET ${name}
+               PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+  if(configure_handled_by_build)
+    # Depend on other external projects (file-level)
+    _ep_get_file_deps(file_deps ${name})
+  endif()
+
   get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
   if(cmd_set)
     get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
@@ -3214,6 +3335,7 @@ function(_ep_add_build_command name)
       BYPRODUCTS \${build_byproducts}
       WORKING_DIRECTORY \${binary_dir}
       DEPENDEES configure
+      DEPENDS \${file_deps}
       ALWAYS \${always}
       ${log}
       ${uses_terminal}
@@ -3378,7 +3500,136 @@ function(ExternalProject_Add name)
 
   set_property(TARGET ${name} PROPERTY _EP_CMP0114 "${cmp0114}")
 
-  _ep_parse_arguments(ExternalProject_Add ${name} _EP_ "${ARGN}")
+  set(keywords
+    #
+    # Directory options
+    #
+    PREFIX
+    TMP_DIR
+    STAMP_DIR
+    LOG_DIR
+    DOWNLOAD_DIR
+    SOURCE_DIR
+    BINARY_DIR
+    INSTALL_DIR
+    #
+    # Download step options
+    #
+    DOWNLOAD_COMMAND
+    #
+    URL
+    URL_HASH
+    URL_MD5
+    DOWNLOAD_NAME
+    DOWNLOAD_NO_EXTRACT
+    DOWNLOAD_NO_PROGRESS
+    TIMEOUT
+    INACTIVITY_TIMEOUT
+    HTTP_USERNAME
+    HTTP_PASSWORD
+    HTTP_HEADER
+    TLS_VERIFY     # Also used for git clone operations
+    TLS_CAINFO
+    NETRC
+    NETRC_FILE
+    #
+    GIT_REPOSITORY
+    GIT_TAG
+    GIT_REMOTE_NAME
+    GIT_SUBMODULES
+    GIT_SUBMODULES_RECURSE
+    GIT_SHALLOW
+    GIT_PROGRESS
+    GIT_CONFIG
+    GIT_REMOTE_UPDATE_STRATEGY
+    #
+    SVN_REPOSITORY
+    SVN_REVISION
+    SVN_USERNAME
+    SVN_PASSWORD
+    SVN_TRUST_CERT
+    #
+    HG_REPOSITORY
+    HG_TAG
+    #
+    CVS_REPOSITORY
+    CVS_MODULE
+    CVS_TAG
+    #
+    # Update step options
+    #
+    UPDATE_COMMAND
+    UPDATE_DISCONNECTED
+    #
+    # Patch step options
+    #
+    PATCH_COMMAND
+    #
+    # Configure step options
+    #
+    CONFIGURE_COMMAND
+    CMAKE_COMMAND
+    CMAKE_GENERATOR
+    CMAKE_GENERATOR_PLATFORM
+    CMAKE_GENERATOR_TOOLSET
+    CMAKE_GENERATOR_INSTANCE
+    CMAKE_ARGS
+    CMAKE_CACHE_ARGS
+    CMAKE_CACHE_DEFAULT_ARGS
+    SOURCE_SUBDIR
+    CONFIGURE_HANDLED_BY_BUILD
+    #
+    # Build step options
+    #
+    BUILD_COMMAND
+    BUILD_IN_SOURCE
+    BUILD_ALWAYS
+    BUILD_BYPRODUCTS
+    #
+    # Install step options
+    #
+    INSTALL_COMMAND
+    #
+    # Test step options
+    #
+    TEST_COMMAND
+    TEST_BEFORE_INSTALL
+    TEST_AFTER_INSTALL
+    TEST_EXCLUDE_FROM_MAIN
+    #
+    # Logging options
+    #
+    LOG_DOWNLOAD
+    LOG_UPDATE
+    LOG_PATCH
+    LOG_CONFIGURE
+    LOG_BUILD
+    LOG_INSTALL
+    LOG_TEST
+    LOG_MERGED_STDOUTERR
+    LOG_OUTPUT_ON_FAILURE
+    #
+    # Terminal access options
+    #
+    USES_TERMINAL_DOWNLOAD
+    USES_TERMINAL_UPDATE
+    USES_TERMINAL_CONFIGURE
+    USES_TERMINAL_BUILD
+    USES_TERMINAL_INSTALL
+    USES_TERMINAL_TEST
+    #
+    # Target options
+    #
+    DEPENDS
+    EXCLUDE_FROM_ALL
+    STEP_TARGETS
+    INDEPENDENT_STEP_TARGETS
+    #
+    # Miscellaneous options
+    #
+    LIST_SEPARATOR
+  )
+  _ep_parse_arguments(ExternalProject_Add "${keywords}" ${name} _EP_ "${ARGN}")
   _ep_set_directories(${name})
   _ep_get_step_stampfile(${name} "done" done_stamp_file)
   _ep_get_step_stampfile(${name} "install" install_stamp_file)
index 4a3e83a..77c66d1 100644 (file)
@@ -66,6 +66,8 @@ The default value for this global property is ``OPTIONAL``.
 
 .. variable:: FeatureSummary_<TYPE>_DESCRIPTION
 
+.. versionadded:: 3.9
+
 The global property :variable:`FeatureSummary_<TYPE>_DESCRIPTION` can be defined
 for each type to replace the type name with the specified string whenever the
 package type is used in an output string.
@@ -242,12 +244,13 @@ endfunction()
   ``<TYPE>_PACKAGES_NOT_FOUND``
    only those packages which have not been found which have the type <TYPE>
 
-  With the exception of the ``ALL`` value, these values can be combined
-  in order to customize the output. For example:
+  .. versionchanged:: 3.1
+    With the exception of the ``ALL`` value, these values can be combined
+    in order to customize the output. For example:
 
-  .. code-block:: cmake
+    .. code-block:: cmake
 
-    feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)
+      feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)
 
   If a ``FILENAME`` is given, the information is printed into this file.  If
   ``APPEND`` is used, it is appended to this file, otherwise the file is
@@ -268,14 +271,18 @@ endfunction()
   The default value for the :variable:`FeatureSummary_REQUIRED_PKG_TYPES` global
   property is ``REQUIRED``.
 
+  .. versionadded:: 3.9
+    The ``DEFAULT_DESCRIPTION`` option.
+
   The :variable:`FeatureSummary_DEFAULT_PKG_TYPE` global property can be
   modified to change the default package type assigned when not explicitly
   assigned by the user.
 
-  If the ``QUIET_ON_EMPTY`` option is used, if only one type of package was
-  requested, and no packages belonging to that category were found, then no
-  output (including the ``DESCRIPTION``) is printed or added to the ``VAR``
-  variable.
+  .. versionadded:: 3.8
+    If the ``QUIET_ON_EMPTY`` option is used, if only one type of package was
+    requested, and no packages belonging to that category were found, then no
+    output (including the ``DESCRIPTION``) is printed or added to the ``VAR``
+    variable.
 
   Example 1, append everything to a file:
 
@@ -617,6 +624,9 @@ endfunction()
   be displayed using ``feature_summary()`` for ``ENABLED_FEATURES`` and
   ``DISABLED_FEATURES`` respectively.
 
+  .. versionchanged:: 3.8
+    ``<enabled>`` can be a list of conditions.
+
   Example for setting the info for a feature:
 
   .. code-block:: cmake
index c81b371..8adef47 100644 (file)
@@ -77,6 +77,9 @@ operation and would not normally be the way the module is used, but it is
 sometimes useful as part of implementing some higher level feature or to
 populate some content in CMake's script mode.
 
+.. versionchanged:: 3.14
+  ``FetchContent`` commands can access the terminal. This is necessary
+  for password prompts and real-time progress displays to work.
 
 Commands
 ^^^^^^^^
@@ -371,6 +374,8 @@ is simpler and provides additional features over the pattern above.
   :variable:`CMAKE_MAKE_PROGRAM` variables will need to be set appropriately
   on the command line invoking the script.
 
+  .. versionadded:: 3.18
+    Added support for ``DOWNLOAD_NO_EXTRACT`` and ``SOURCE_SUBDIR`` options.
 
 .. command:: FetchContent_GetProperties
 
@@ -416,6 +421,8 @@ is simpler and provides additional features over the pattern above.
 
     FetchContent_MakeAvailable( <name1> [<name2>...] )
 
+  .. versionadded:: 3.14
+
   This command implements the common pattern typically needed for most
   dependencies.  It iterates over each of the named dependencies in turn
   and for each one it loosely follows the
@@ -957,6 +964,22 @@ ExternalProject_Add_Step(${contentName}-populate copyfile
       "-DCMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY=${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
   endif()
 
+  # Avoid using if(... IN_LIST ...) so we don't have to alter policy settings
+  set(__FETCHCONTENT_CACHED_INFO "")
+  list(FIND ARG_UNPARSED_ARGUMENTS GIT_REPOSITORY indexResult)
+  if(indexResult GREATER_EQUAL 0)
+    find_package(Git QUIET)
+    set(__FETCHCONTENT_CACHED_INFO
+"# Pass through things we've already detected in the main project to avoid
+# paying the cost of redetecting them again in ExternalProject_Add()
+set(GIT_EXECUTABLE [==[${GIT_EXECUTABLE}]==])
+set(GIT_VERSION_STRING [==[${GIT_VERSION_STRING}]==])
+set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
+  [==[${GIT_EXECUTABLE};${GIT_VERSION_STRING}]==]
+)
+")
+  endif()
+
   # Create and build a separate CMake project to carry out the population.
   # If we've already previously done these steps, they will not cause
   # anything to be updated, so extra rebuilds of the project won't occur.
index 45e4df0..5ebb12f 100644 (file)
@@ -9,6 +9,8 @@ cmake_minimum_required(VERSION ${CMAKE_VERSION})
 
 project(${contentName}-populate NONE)
 
+@__FETCHCONTENT_CACHED_INFO@
+
 include(ExternalProject)
 ExternalProject_Add(${contentName}-populate
                     ${ARG_EXTRA}
index 88e2681..627866a 100644 (file)
@@ -12,6 +12,8 @@ Find the alsa libraries (``asound``)
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.12
+
 This module defines :prop_tgt:`IMPORTED` target ``ALSA::ALSA``, if
 ALSA has been found.
 
index c8a31a0..f959356 100644 (file)
@@ -8,6 +8,9 @@ FindArmadillo
 Find the Armadillo C++ library.
 Armadillo is a library for linear algebra & scientific computing.
 
+.. versionadded:: 3.18
+  Support for linking wrapped libraries directly (``ARMA_DONT_USE_WRAPPER``).
+
 Using Armadillo:
 
 ::
index 1e1a5a3..3515bf0 100644 (file)
@@ -35,21 +35,31 @@ the path to a yacc file.  ``<CodeOutput>`` is the name of the source file
 generated by bison.  A header file is also be generated, and contains
 the token list.
 
+.. versionchanged:: 3.14
+  When :policy:`CMP0088` is set to ``NEW``, ``bison`` runs in the
+  :variable:`CMAKE_CURRENT_BINARY_DIR` directory.
+
 The options are:
 
 ``COMPILE_FLAGS <flags>``
   Specify flags to be added to the ``bison`` command line.
 
 ``DEFINES_FILE <file>``
+  .. versionadded:: 3.4
+
   Specify a non-default header ``<file>`` to be generated by ``bison``.
 
 ``VERBOSE [<file>]``
   Tell ``bison`` to write a report file of the grammar and parser.
-  If ``<file>`` is given, it specifies path the report file is copied to.
-  ``[<file>]`` is left for backward compatibility of this module.
-  Use ``VERBOSE REPORT_FILE <file>``.
+
+  .. deprecated:: 3.7
+    If ``<file>`` is given, it specifies path the report file is copied to.
+    ``[<file>]`` is left for backward compatibility of this module.
+    Use ``VERBOSE REPORT_FILE <file>``.
 
 ``REPORT_FILE <file>``
+  .. versionadded:: 3.7
+
   Specify a non-default report ``<file>``, if generated.
 
 The macro defines the following variables:
index e4353df..4cf812b 100644 (file)
@@ -53,18 +53,46 @@ The following variables may be set to influence this module's behavior:
   * ``Arm_mp``
   * ``Arm_ilp64``
   * ``Arm_ilp64_mp``
+  * ``EML``
+  * ``EML_mt``
   * ``Generic``
 
+  .. versionadded:: 3.6
+    ``OpenBLAS`` support.
+
+  .. versionadded:: 3.11
+    ``FLAME`` support.
+
+  .. versionadded:: 3.13
+    Added ILP64 MKL variants (``Intel10_64ilp``, ``Intel10_64ilp_seq``).
+
+  .. versionadded:: 3.17
+    Added single dynamic library MKL variant (``Intel10_64_dyn``).
+
+  .. versionadded:: 3.18
+    Arm Performance Libraries support (``Arm``, ``Arm_mp``, ``Arm_ilp64``,
+    ``Arm_ilp64_mp``).
+
+  .. versionadded:: 3.19
+    ``FlexiBLAS`` support.
+
+  .. versionadded:: 3.20
+    Elbrus Math Library support (``EML``, ``EML_mt``).
+
 ``BLA_F95``
   if ``ON`` tries to find the BLAS95 interfaces
 
 ``BLA_PREFER_PKGCONFIG``
+  .. versionadded:: 3.11
+
   if set ``pkg-config`` will be used to search for a BLAS library first
   and if one is found that is preferred
 
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.18
+
 This module defines the following :prop_tgt:`IMPORTED` target:
 
 ``BLAS::BLAS``
@@ -104,10 +132,13 @@ This module defines the following variables:
 Hints
 ^^^^^
 
-Set the ``MKLROOT`` environment variable to a directory that contains an MKL
-installation, or add the directory to the dynamic library loader environment
-variable for your platform (``LIB``, ``DYLD_LIBRARY_PATH`` or
-``LD_LIBRARY_PATH``).
+``MKLROOT``
+  .. versionadded:: 3.15
+
+  Set this environment variable to a directory that contains an MKL
+  installation, or add the directory to the dynamic library loader environment
+  variable for your platform (``LIB``, ``DYLD_LIBRARY_PATH`` or
+  ``LD_LIBRARY_PATH``).
 
 #]=======================================================================]
 
@@ -586,16 +617,22 @@ if(BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
     else()
       find_package(Threads REQUIRED)
     endif()
+    set(_threadlibs "${CMAKE_THREAD_LIBS_INIT}")
+    if(BLA_STATIC)
+      find_package(OpenMP COMPONENTS C)
+      list(PREPEND _threadlibs "${OpenMP_C_LIBRARIES}")
+    endif()
     check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
       "openblas"
-      "${CMAKE_THREAD_LIBS_INIT}"
+      "${_threadlibs}"
       ""
       ""
       )
+    unset(_threadlibs)
   endif()
 endif()
 
@@ -805,6 +842,9 @@ if(BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
     if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
       set(_ACML_COMPILER32 "ifort32")
       set(_ACML_COMPILER64 "ifort64")
+    elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
+      # 32-bit not supported
+      set(_ACML_COMPILER64 "ifx")
     elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "SunPro")
       set(_ACML_COMPILER32 "sun32")
       set(_ACML_COMPILER64 "sun64")
@@ -951,6 +991,31 @@ if(BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
   endif()
 endif()
 
+# Elbrus Math Library?
+if(BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All")
+
+   set(BLAS_EML_LIB "eml")
+
+   # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
+   if(BLA_VENDOR MATCHES "_mt")
+     set(BLAS_EML_LIB "${BLAS_EML_LIB}_mt")
+   endif()
+
+   if(NOT BLAS_LIBRARIES)
+    check_blas_libraries(
+      BLAS_LIBRARIES
+      BLAS
+      sgemm
+      ""
+      "${BLAS_EML_LIB}"
+      ""
+      ""
+      ""
+      )
+  endif()
+
+endif()
+
 # Generic BLAS library?
 if(BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
index 5704d1d..355c4bb 100644 (file)
@@ -10,6 +10,8 @@ Try to find BZip2
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.12
+
 This module defines :prop_tgt:`IMPORTED` target ``BZip2::BZip2``, if
 BZip2 has been found.
 
@@ -21,7 +23,8 @@ This module defines the following variables:
 ``BZIP2_FOUND``
   system has BZip2
 ``BZIP2_INCLUDE_DIRS``
-  the BZip2 include directories
+  .. versionadded:: 3.12
+    the BZip2 include directories
 ``BZIP2_LIBRARIES``
   Link these to use BZip2
 ``BZIP2_NEED_PREFIX``
index 54d9593..f8887ad 100644 (file)
@@ -7,7 +7,9 @@ FindBoost
 
 Find Boost include dirs and libraries
 
-Use this module by invoking find_package with the form::
+Use this module by invoking :command:`find_package` with the form:
+
+.. code-block:: cmake
 
   find_package(Boost
     [version] [EXACT]      # Minimum or EXACT version e.g. 1.67.0
@@ -20,97 +22,134 @@ Use this module by invoking find_package with the form::
 
 This module finds headers and requested component libraries OR a CMake
 package configuration file provided by a "Boost CMake" build.  For the
-latter case skip to the "Boost CMake" section below.  For the former
-case results are reported in variables::
-
-  Boost_FOUND            - True if headers and requested libraries were found
-  Boost_INCLUDE_DIRS     - Boost include directories
-  Boost_LIBRARY_DIRS     - Link directories for Boost libraries
-  Boost_LIBRARIES        - Boost component libraries to be linked
-  Boost_<C>_FOUND        - True if component <C> was found (<C> is upper-case)
-  Boost_<C>_LIBRARY      - Libraries to link for component <C> (may include
-                           target_link_libraries debug/optimized keywords)
-  Boost_VERSION_MACRO    - BOOST_VERSION value from boost/version.hpp
-  Boost_VERSION_STRING   - Boost version number in x.y.z format
-  Boost_VERSION          - if CMP0093 NEW => same as Boost_VERSION_STRING
-                           if CMP0093 OLD or unset => same as Boost_VERSION_MACRO
-  Boost_LIB_VERSION      - Version string appended to library filenames
-  Boost_VERSION_MAJOR    - Boost major version number (X in X.y.z)
-                           alias: Boost_MAJOR_VERSION
-  Boost_VERSION_MINOR    - Boost minor version number (Y in x.Y.z)
-                           alias: Boost_MINOR_VERSION
-  Boost_VERSION_PATCH    - Boost subminor version number (Z in x.y.Z)
-                           alias: Boost_SUBMINOR_VERSION
-  Boost_VERSION_COUNT    - Amount of version components (3)
-  Boost_LIB_DIAGNOSTIC_DEFINITIONS (Windows)
-                         - Pass to add_definitions() to have diagnostic
-                           information about Boost's automatic linking
-                           displayed during compilation
-
-Note that Boost Python components require a Python version suffix
-(Boost 1.67 and later), e.g. ``python36`` or ``python27`` for the
-versions built against Python 3.6 and 2.7, respectively.  This also
-applies to additional components using Python including
-``mpi_python`` and ``numpy``.  Earlier Boost releases may use
-distribution-specific suffixes such as ``2``, ``3`` or ``2.7``.
-These may also be used as suffixes, but note that they are not
-portable.
-
-This module reads hints about search locations from variables::
-
-  BOOST_ROOT             - Preferred installation prefix
-   (or BOOSTROOT)
-  BOOST_INCLUDEDIR       - Preferred include directory e.g. <prefix>/include
-  BOOST_LIBRARYDIR       - Preferred library directory e.g. <prefix>/lib
-  Boost_NO_SYSTEM_PATHS  - Set to ON to disable searching in locations not
-                           specified by these hint variables. Default is OFF.
-  Boost_ADDITIONAL_VERSIONS
-                         - List of Boost versions not known to this module
-                           (Boost install locations may contain the version)
-
-and saves search results persistently in CMake cache entries::
-
-  Boost_INCLUDE_DIR         - Directory containing Boost headers
-  Boost_LIBRARY_DIR_RELEASE - Directory containing release Boost libraries
-  Boost_LIBRARY_DIR_DEBUG   - Directory containing debug Boost libraries
-  Boost_<C>_LIBRARY_DEBUG   - Component <C> library debug variant
-  Boost_<C>_LIBRARY_RELEASE - Component <C> library release variant
-
-The following :prop_tgt:`IMPORTED` targets are also defined::
-
-  Boost::headers                - Target for header-only dependencies
-                                  (Boost include directory)
-                                  alias: Boost::boost
-  Boost::<C>                    - Target for specific component dependency
-                                  (shared or static library); <C> is lower-
-                                  case
-  Boost::diagnostic_definitions - interface target to enable diagnostic
-                                  information about Boost's automatic linking
-                                  during compilation (adds BOOST_LIB_DIAGNOSTIC)
-  Boost::disable_autolinking    - interface target to disable automatic
-                                  linking with MSVC (adds BOOST_ALL_NO_LIB)
-  Boost::dynamic_linking        - interface target to enable dynamic linking
-                                  linking with MSVC (adds BOOST_ALL_DYN_LINK)
+latter case skip to the :ref:`Boost CMake` section below.
 
-Implicit dependencies such as ``Boost::filesystem`` requiring
-``Boost::system`` will be automatically detected and satisfied, even
-if system is not specified when using :command:`find_package` and if
-``Boost::system`` is not added to :command:`target_link_libraries`.  If using
-``Boost::thread``, then ``Threads::Threads`` will also be added automatically.
+.. versionadded:: 3.7
+  ``bzip2`` and ``zlib`` components (Windows only).
 
-It is important to note that the imported targets behave differently
-than variables created by this module: multiple calls to
-:command:`find_package(Boost)` in the same directory or sub-directories with
-different options (e.g. static or shared) will not override the
-values of the targets created by the first call.
+.. versionadded:: 3.11
+  The ``OPTIONAL_COMPONENTS`` option.
+
+.. versionadded:: 3.13
+  ``stacktrace_*`` components.
+
+.. versionadded:: 3.19
+  ``bzip2`` and ``zlib`` components on all platforms.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``Boost_FOUND``
+  True if headers and requested libraries were found.
+
+``Boost_INCLUDE_DIRS``
+  Boost include directories.
+
+``Boost_LIBRARY_DIRS``
+  Link directories for Boost libraries.
+
+``Boost_LIBRARIES``
+  Boost component libraries to be linked.
+
+``Boost_<COMPONENT>_FOUND``
+  True if component ``<COMPONENT>`` was found (``<COMPONENT>`` name is upper-case).
+
+``Boost_<COMPONENT>_LIBRARY``
+  Libraries to link for component ``<COMPONENT>`` (may include
+  :command:`target_link_libraries` debug/optimized keywords).
+
+``Boost_VERSION_MACRO``
+  ``BOOST_VERSION`` value from ``boost/version.hpp``.
+
+``Boost_VERSION_STRING``
+  Boost version number in ``X.Y.Z`` format.
+
+``Boost_VERSION``
+  Boost version number in ``X.Y.Z`` format (same as ``Boost_VERSION_STRING``).
+
+  .. versionchanged:: 3.15
+    In previous CMake versions, this variable used the raw version string
+    from the Boost header (same as ``Boost_VERSION_MACRO``).
+    See policy :policy:`CMP0093`.
+
+``Boost_LIB_VERSION``
+  Version string appended to library filenames.
+
+``Boost_VERSION_MAJOR``, ``Boost_MAJOR_VERSION``
+  Boost major version number (``X`` in ``X.Y.Z``).
+
+``Boost_VERSION_MINOR``, ``Boost_MINOR_VERSION``
+  Boost minor version number (``Y`` in ``X.Y.Z``).
+
+``Boost_VERSION_PATCH``, ``Boost_SUBMINOR_VERSION``
+  Boost subminor version number (``Z`` in ``X.Y.Z``).
+
+``Boost_VERSION_COUNT``
+  Amount of version components (3).
+
+``Boost_LIB_DIAGNOSTIC_DEFINITIONS`` (Windows-specific)
+  Pass to :command:`add_definitions` to have diagnostic
+  information about Boost's automatic linking
+  displayed during compilation
+
+.. versionadded:: 3.15
+  The ``Boost_VERSION_<PART>`` variables.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+Search results are saved persistently in CMake cache entries:
+
+``Boost_INCLUDE_DIR``
+  Directory containing Boost headers.
+
+``Boost_LIBRARY_DIR_RELEASE``
+  Directory containing release Boost libraries.
+
+``Boost_LIBRARY_DIR_DEBUG``
+  Directory containing debug Boost libraries.
+
+``Boost_<COMPONENT>_LIBRARY_DEBUG``
+  Component ``<COMPONENT>`` library debug variant.
+
+``Boost_<COMPONENT>_LIBRARY_RELEASE``
+  Component ``<COMPONENT>`` library release variant.
+
+.. versionadded:: 3.3
+  Per-configuration variables ``Boost_LIBRARY_DIR_RELEASE`` and
+  ``Boost_LIBRARY_DIR_DEBUG``.
+
+Hints
+^^^^^
+
+This module reads hints about search locations from variables:
+
+``BOOST_ROOT``, ``BOOSTROOT``
+  Preferred installation prefix.
+
+``BOOST_INCLUDEDIR``
+  Preferred include directory e.g. ``<prefix>/include``.
+
+``BOOST_LIBRARYDIR``
+  Preferred library directory e.g. ``<prefix>/lib``.
+
+``Boost_NO_SYSTEM_PATHS``
+  Set to ``ON`` to disable searching in locations not
+  specified by these hint variables. Default is ``OFF``.
+
+``Boost_ADDITIONAL_VERSIONS``
+  List of Boost versions not known to this module.
+  (Boost install locations may contain the version).
 
 Users may set these hints or results as ``CACHE`` entries.  Projects
 should not read these entries directly but instead use the above
 result variables.  Note that some hint names start in upper-case
-"BOOST".  One may specify these as environment variables if they are
+``BOOST``.  One may specify these as environment variables if they are
 not specified as CMake variables or cache entries.
 
-This module first searches for the ``Boost`` header files using the above
+This module first searches for the Boost header files using the above
 hint variables (excluding ``BOOST_LIBRARYDIR``) and saves the result in
 ``Boost_INCLUDE_DIR``.  Then it searches for requested component libraries
 using the above hints (excluding ``BOOST_INCLUDEDIR`` and
@@ -118,83 +157,170 @@ using the above hints (excluding ``BOOST_INCLUDEDIR`` and
 and the library name configuration settings below.  It saves the
 library directories in ``Boost_LIBRARY_DIR_DEBUG`` and
 ``Boost_LIBRARY_DIR_RELEASE`` and individual library
-locations in ``Boost_<C>_LIBRARY_DEBUG`` and ``Boost_<C>_LIBRARY_RELEASE``.
+locations in ``Boost_<COMPONENT>_LIBRARY_DEBUG`` and ``Boost_<COMPONENT>_LIBRARY_RELEASE``.
 When one changes settings used by previous searches in the same build
 tree (excluding environment variables) this module discards previous
 search results affected by the changes and searches again.
 
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.5
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``Boost::boost``
+  Target for header-only dependencies. (Boost include directory).
+
+``Boost::headers``
+  .. versionadded:: 3.15
+    Alias for ``Boost::boost``.
+
+``Boost::<component>``
+  Target for specific component dependency (shared or static library);
+  ``<component>`` name is lower-case.
+
+``Boost::diagnostic_definitions``
+  Interface target to enable diagnostic information about Boost's automatic
+  linking during compilation (adds ``-DBOOST_LIB_DIAGNOSTIC``).
+
+``Boost::disable_autolinking``
+  Interface target to disable automatic linking with MSVC
+  (adds ``-DBOOST_ALL_NO_LIB``).
+
+``Boost::dynamic_linking``
+  Interface target to enable dynamic linking linking with MSVC
+  (adds ``-DBOOST_ALL_DYN_LINK``).
+
+Implicit dependencies such as ``Boost::filesystem`` requiring
+``Boost::system`` will be automatically detected and satisfied, even
+if system is not specified when using :command:`find_package` and if
+``Boost::system`` is not added to :command:`target_link_libraries`.  If using
+``Boost::thread``, then ``Threads::Threads`` will also be added automatically.
+
+It is important to note that the imported targets behave differently
+than variables created by this module: multiple calls to
+:command:`find_package(Boost)` in the same directory or sub-directories with
+different options (e.g. static or shared) will not override the
+values of the targets created by the first call.
+
+Other Variables
+^^^^^^^^^^^^^^^
+
 Boost libraries come in many variants encoded in their file name.
 Users or projects may tell this module which variant to find by
-setting variables::
-
-  Boost_USE_DEBUG_LIBS     - Set to ON or OFF to specify whether to search
-                             and use the debug libraries.  Default is ON.
-  Boost_USE_RELEASE_LIBS   - Set to ON or OFF to specify whether to search
-                             and use the release libraries.  Default is ON.
-  Boost_USE_MULTITHREADED  - Set to OFF to use the non-multithreaded
-                             libraries ('mt' tag).  Default is ON.
-  Boost_USE_STATIC_LIBS    - Set to ON to force the use of the static
-                             libraries.  Default is OFF.
-  Boost_USE_STATIC_RUNTIME - Set to ON or OFF to specify whether to use
-                             libraries linked statically to the C++ runtime
-                             ('s' tag).  Default is platform dependent.
-  Boost_USE_DEBUG_RUNTIME  - Set to ON or OFF to specify whether to use
-                             libraries linked to the MS debug C++ runtime
-                             ('g' tag).  Default is ON.
-  Boost_USE_DEBUG_PYTHON   - Set to ON to use libraries compiled with a
-                             debug Python build ('y' tag). Default is OFF.
-  Boost_USE_STLPORT        - Set to ON to use libraries compiled with
-                             STLPort ('p' tag).  Default is OFF.
-  Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS
-                           - Set to ON to use libraries compiled with
-                             STLPort deprecated "native iostreams"
-                             ('n' tag).  Default is OFF.
-  Boost_COMPILER           - Set to the compiler-specific library suffix
-                             (e.g. "-gcc43").  Default is auto-computed
-                             for the C++ compiler in use.  A list may be
-                             used if multiple compatible suffixes should
-                             be tested for, in decreasing order of
-                             preference.
-  Boost_LIB_PREFIX         - Set to the platform-specific library name
-                             prefix (e.g. "lib") used by Boost static libs.
-                             This is needed only on platforms where CMake
-                             does not know the prefix by default.
-  Boost_ARCHITECTURE       - Set to the architecture-specific library suffix
-                             (e.g. "-x64").  Default is auto-computed for the
-                             C++ compiler in use.
-  Boost_THREADAPI          - Suffix for "thread" component library name,
-                             such as "pthread" or "win32".  Names with
-                             and without this suffix will both be tried.
-  Boost_NAMESPACE          - Alternate namespace used to build boost with
-                             e.g. if set to "myboost", will search for
-                             myboost_thread instead of boost_thread.
-
-Other variables one may set to control this module are::
-
-  Boost_DEBUG              - Set to ON to enable debug output from FindBoost.
-                             Please enable this before filing any bug report.
-  Boost_REALPATH           - Set to ON to resolve symlinks for discovered
-                             libraries to assist with packaging.  For example,
-                             the "system" component library may be resolved to
-                             "/usr/lib/libboost_system.so.1.67.0" instead of
-                             "/usr/lib/libboost_system.so".  This does not
-                             affect linking and should not be enabled unless
-                             the user needs this information.
-  Boost_LIBRARY_DIR        - Default value for Boost_LIBRARY_DIR_RELEASE and
-                             Boost_LIBRARY_DIR_DEBUG.
+setting variables:
+
+``Boost_USE_DEBUG_LIBS``
+  .. versionadded:: 3.10
+
+  Set to ``ON`` or ``OFF`` to specify whether to search and use the debug
+  libraries.  Default is ``ON``.
+
+``Boost_USE_RELEASE_LIBS``
+  .. versionadded:: 3.10
+
+  Set to ``ON`` or ``OFF`` to specify whether to search and use the release
+  libraries.  Default is ``ON``.
+
+``Boost_USE_MULTITHREADED``
+  Set to OFF to use the non-multithreaded libraries ("mt" tag). Default is
+  ``ON``.
+
+``Boost_USE_STATIC_LIBS``
+  Set to ON to force the use of the static libraries.  Default is ``OFF``.
+
+``Boost_USE_STATIC_RUNTIME``
+  Set to ``ON`` or ``OFF`` to specify whether to use libraries linked
+  statically to the C++ runtime ("s" tag).  Default is platform dependent.
+
+``Boost_USE_DEBUG_RUNTIME``
+  Set to ``ON`` or ``OFF`` to specify whether to use libraries linked to the
+  MS debug C++ runtime ("g" tag).  Default is ``ON``.
+
+``Boost_USE_DEBUG_PYTHON``
+  Set to ``ON`` to use libraries compiled with a debug Python build ("y"
+  tag).  Default is ``OFF``.
+
+``Boost_USE_STLPORT``
+  Set to ``ON`` to use libraries compiled with STLPort ("p" tag). Default is
+  ``OFF``.
+
+``Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS``
+  Set to ON to use libraries compiled with STLPort deprecated "native
+  iostreams" ("n" tag).  Default is ``OFF``.
+
+``Boost_COMPILER``
+  Set to the compiler-specific library suffix (e.g. ``-gcc43``).  Default is
+  auto-computed for the C++ compiler in use.
+
+  .. versionchanged:: 3.9
+    A list may be used if multiple compatible suffixes should be tested for,
+    in decreasing order of preference.
+
+``Boost_LIB_PREFIX``
+  .. versionadded:: 3.18
+
+  Set to the platform-specific library name prefix (e.g. ``lib``) used by
+  Boost static libs.  This is needed only on platforms where CMake does not
+  know the prefix by default.
+
+``Boost_ARCHITECTURE``
+  .. versionadded:: 3.13
+
+  Set to the architecture-specific library suffix (e.g. ``-x64``).
+  Default is auto-computed for the C++ compiler in use.
+
+``Boost_THREADAPI``
+  Suffix for ``thread`` component library name, such as ``pthread`` or
+  ``win32``.  Names with and without this suffix will both be tried.
+
+``Boost_NAMESPACE``
+  Alternate namespace used to build boost with e.g. if set to ``myboost``,
+  will search for ``myboost_thread`` instead of ``boost_thread``.
+
+Other variables one may set to control this module are:
+
+``Boost_DEBUG``
+  Set to ``ON`` to enable debug output from ``FindBoost``.
+  Please enable this before filing any bug report.
+
+``Boost_REALPATH``
+  Set to ``ON`` to resolve symlinks for discovered libraries to assist with
+  packaging.  For example, the "system" component library may be resolved to
+  ``/usr/lib/libboost_system.so.1.67.0`` instead of
+  ``/usr/lib/libboost_system.so``.  This does not affect linking and should
+  not be enabled unless the user needs this information.
+
+``Boost_LIBRARY_DIR``
+  Default value for ``Boost_LIBRARY_DIR_RELEASE`` and
+  ``Boost_LIBRARY_DIR_DEBUG``.
+
+``Boost_NO_WARN_NEW_VERSIONS``
+  .. versionadded:: 3.20
+
+  Set to ``ON`` to suppress the warning about unknown dependencies for new
+  Boost versions.
 
 On Visual Studio and Borland compilers Boost headers request automatic
 linking to corresponding libraries.  This requires matching libraries
 to be linked explicitly or available in the link library search path.
 In this case setting ``Boost_USE_STATIC_LIBS`` to ``OFF`` may not achieve
 dynamic linking.  Boost automatic linking typically requests static
-libraries with a few exceptions (such as ``Boost.Python``).  Use::
+libraries with a few exceptions (such as ``Boost.Python``).  Use:
+
+.. code-block:: cmake
 
   add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
 
 to ask Boost to report information about automatic linking requests.
 
-Example to find Boost headers only::
+Examples
+^^^^^^^^
+
+Find Boost headers only:
+
+.. code-block:: cmake
 
   find_package(Boost 1.36.0)
   if(Boost_FOUND)
@@ -202,7 +328,9 @@ Example to find Boost headers only::
     add_executable(foo foo.cc)
   endif()
 
-Example to find Boost libraries and use imported targets::
+Find Boost libraries and use imported targets:
+
+.. code-block:: cmake
 
   find_package(Boost 1.56 REQUIRED COMPONENTS
                date_time filesystem iostreams)
@@ -210,17 +338,21 @@ Example to find Boost libraries and use imported targets::
   target_link_libraries(foo Boost::date_time Boost::filesystem
                             Boost::iostreams)
 
-Example to find Boost Python 3.6 libraries and use imported targets::
+Find Boost Python 3.6 libraries and use imported targets:
+
+.. code-block:: cmake
 
   find_package(Boost 1.67 REQUIRED COMPONENTS
                python36 numpy36)
   add_executable(foo foo.cc)
   target_link_libraries(foo Boost::python36 Boost::numpy36)
 
-Example to find Boost headers and some *static* (release only) libraries::
+Find Boost headers and some *static* (release only) libraries:
+
+.. code-block:: cmake
 
   set(Boost_USE_STATIC_LIBS        ON)  # only find static libs
-  set(Boost_USE_DEBUG_LIBS         OFF) # ignore debug libs and
+  set(Boost_USE_DEBUG_LIBS        OFF)  # ignore debug libs and
   set(Boost_USE_RELEASE_LIBS       ON)  # only find release libs
   set(Boost_USE_MULTITHREADED      ON)
   set(Boost_USE_STATIC_RUNTIME    OFF)
@@ -231,6 +363,8 @@ Example to find Boost headers and some *static* (release only) libraries::
     target_link_libraries(foo ${Boost_LIBRARIES})
   endif()
 
+.. _`Boost CMake`:
+
 Boost CMake
 ^^^^^^^^^^^
 
@@ -238,7 +372,7 @@ If Boost was built using the boost-cmake project or from Boost 1.70.0 on
 it provides a package configuration file for use with find_package's config mode.
 This module looks for the package configuration file called
 ``BoostConfig.cmake`` or ``boost-config.cmake`` and stores the result in
-``CACHE`` entry "Boost_DIR".  If found, the package configuration file is loaded
+``CACHE`` entry ``Boost_DIR``.  If found, the package configuration file is loaded
 and this module returns with no further action.  See documentation of
 the Boost CMake package configuration for details on what it provides.
 
@@ -725,7 +859,8 @@ endfunction()
 # Guesses Boost's compiler prefix used in built library names
 # Returns the guess by setting the variable pointed to by _ret
 function(_Boost_GUESS_COMPILER_PREFIX _ret)
-  if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel")
+  if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel"
+      OR "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "xIntelLLVM")
     if(WIN32)
       set (_boost_COMPILER "-iw")
     else()
@@ -1215,7 +1350,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
       set(_Boost_TIMER_DEPENDENCIES chrono)
       set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic)
       set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
-      if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.76.0)
+      if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.76.0 AND NOT Boost_NO_WARN_NEW_VERSIONS)
         message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets")
       endif()
     endif()
@@ -1778,7 +1913,8 @@ endif()
 if(WIN32 AND Boost_USE_DEBUG_RUNTIME)
   if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC"
           OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang"
-          OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel")
+          OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel"
+          OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntelLLVM")
     string(APPEND _boost_DEBUG_ABI_TAG "g")
   endif()
 endif()
index f04f571..620e32a 100644 (file)
@@ -4,12 +4,6 @@ FindCUDA
 
 .. deprecated:: 3.10
 
-  Superseded by first-class support for the CUDA language in CMake.
-  Superseded by the :module:`FindCUDAToolkit` for CUDA toolkit libraries.
-
-Replacement
-^^^^^^^^^^^
-
 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
 in the top-level call to the :command:`project` command, or call the
@@ -17,9 +11,10 @@ in the top-level call to the :command:`project` command, or call the
 Then one can add CUDA (``.cu``) sources to programs directly
 in calls to :command:`add_library` and :command:`add_executable`.
 
-To find and use the CUDA toolkit libraries the :module:`FindCUDAToolkit`
-module has superseded this module.  It works whether or not the ``CUDA``
-language is enabled.
+.. versionadded:: 3.17
+  To find and use the CUDA toolkit libraries the :module:`FindCUDAToolkit`
+  module has superseded this module.  It works whether or not the ``CUDA``
+  language is enabled.
 
 Documentation of Deprecated Usage
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -30,6 +25,9 @@ This script locates the NVIDIA CUDA C tools.  It should work on Linux,
 Windows, and macOS and should be reasonably up to date with CUDA C
 releases.
 
+.. versionadded:: 3.19
+  QNX support.
+
 This script makes use of the standard :command:`find_package` arguments of
 ``<VERSION>``, ``REQUIRED`` and ``QUIET``.  ``CUDA_FOUND`` will report if an
 acceptable version of CUDA was found.
@@ -50,342 +48,476 @@ location.  In newer versions of the toolkit the CUDA library is
 included with the graphics driver -- be sure that the driver version
 matches what is needed by the CUDA runtime version.
 
+Input Variables
+"""""""""""""""
+
 The following variables affect the behavior of the macros in the
 script (in alphabetical order).  Note that any of these flags can be
 changed multiple times in the same directory before calling
-``CUDA_ADD_EXECUTABLE``, ``CUDA_ADD_LIBRARY``, ``CUDA_COMPILE``,
-``CUDA_COMPILE_PTX``, ``CUDA_COMPILE_FATBIN``, ``CUDA_COMPILE_CUBIN``
-or ``CUDA_WRAP_SRCS``::
-
-  CUDA_64_BIT_DEVICE_CODE (Default matches host bit size)
-  -- Set to ON to compile for 64 bit device code, OFF for 32 bit device code.
-     Note that making this different from the host code when generating object
-     or C files from CUDA code just won't work, because size_t gets defined by
-     nvcc in the generated source.  If you compile to PTX and then load the
-     file yourself, you can mix bit sizes between device and host.
-
-  CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE (Default ON)
-  -- Set to ON if you want the custom build rule to be attached to the source
-     file in Visual Studio.  Turn OFF if you add the same cuda file to multiple
-     targets.
-
-     This allows the user to build the target from the CUDA file; however, bad
-     things can happen if the CUDA source file is added to multiple targets.
-     When performing parallel builds it is possible for the custom build
-     command to be run more than once and in parallel causing cryptic build
-     errors.  VS runs the rules for every source file in the target, and a
-     source can have only one rule no matter how many projects it is added to.
-     When the rule is run from multiple targets race conditions can occur on
-     the generated file.  Eventually everything will get built, but if the user
-     is unaware of this behavior, there may be confusion.  It would be nice if
-     this script could detect the reuse of source files across multiple targets
-     and turn the option off for the user, but no good solution could be found.
-
-  CUDA_BUILD_CUBIN (Default OFF)
-  -- Set to ON to enable and extra compilation pass with the -cubin option in
-     Device mode. The output is parsed and register, shared memory usage is
-     printed during build.
-
-  CUDA_BUILD_EMULATION (Default OFF for device mode)
-  -- Set to ON for Emulation mode. -D_DEVICEEMU is defined for CUDA C files
-     when CUDA_BUILD_EMULATION is TRUE.
-
-  CUDA_LINK_LIBRARIES_KEYWORD (Default "")
-   -- The <PRIVATE|PUBLIC|INTERFACE> keyword to use for internal
-      target_link_libraries calls. The default is to use no keyword which
-      uses the old "plain" form of target_link_libraries. Note that is matters
-      because whatever is used inside the FindCUDA module must also be used
-      outside - the two forms of target_link_libraries cannot be mixed.
-
-  CUDA_GENERATED_OUTPUT_DIR (Default CMAKE_CURRENT_BINARY_DIR)
-  -- Set to the path you wish to have the generated files placed.  If it is
-     blank output files will be placed in CMAKE_CURRENT_BINARY_DIR.
-     Intermediate files will always be placed in
-     CMAKE_CURRENT_BINARY_DIR/CMakeFiles.
-
-  CUDA_HOST_COMPILATION_CPP (Default ON)
-  -- Set to OFF for C compilation of host code.
-
-  CUDA_HOST_COMPILER (Default CMAKE_C_COMPILER)
-  -- Set the host compiler to be used by nvcc.  Ignored if -ccbin or
-     --compiler-bindir is already present in the CUDA_NVCC_FLAGS or
-     CUDA_NVCC_FLAGS_<CONFIG> variables.  For Visual Studio targets,
-     the host compiler is constructed with one or more visual studio macros
-     such as $(VCInstallDir), that expands out to the path when
-     the command is run from within VS.
-     If the CUDAHOSTCXX environment variable is set it will
-     be used as the default.
+``cuda_add_executable()``, ``cuda_add_library()``, ``cuda_compile()``,
+``cuda_compile_ptx()``, ``cuda_compile_fatbin()``, ``cuda_compile_cubin()``
+or ``cuda_wrap_srcs()``:
+
+``CUDA_64_BIT_DEVICE_CODE`` (Default: host bit size)
+  Set to ``ON`` to compile for 64 bit device code, OFF for 32 bit device code.
+  Note that making this different from the host code when generating object
+  or C files from CUDA code just won't work, because size_t gets defined by
+  nvcc in the generated source.  If you compile to PTX and then load the
+  file yourself, you can mix bit sizes between device and host.
+
+``CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE`` (Default: ``ON``)
+  Set to ``ON`` if you want the custom build rule to be attached to the source
+  file in Visual Studio.  Turn OFF if you add the same cuda file to multiple
+  targets.
+
+  This allows the user to build the target from the CUDA file; however, bad
+  things can happen if the CUDA source file is added to multiple targets.
+  When performing parallel builds it is possible for the custom build
+  command to be run more than once and in parallel causing cryptic build
+  errors.  VS runs the rules for every source file in the target, and a
+  source can have only one rule no matter how many projects it is added to.
+  When the rule is run from multiple targets race conditions can occur on
+  the generated file.  Eventually everything will get built, but if the user
+  is unaware of this behavior, there may be confusion.  It would be nice if
+  this script could detect the reuse of source files across multiple targets
+  and turn the option off for the user, but no good solution could be found.
+
+``CUDA_BUILD_CUBIN`` (Default: ``OFF``)
+  Set to ``ON`` to enable and extra compilation pass with the ``-cubin`` option in
+  Device mode. The output is parsed and register, shared memory usage is
+  printed during build.
+
+``CUDA_BUILD_EMULATION`` (Default: ``OFF`` for device mode)
+  Set to ``ON`` for Emulation mode. ``-D_DEVICEEMU`` is defined for CUDA C files
+  when ``CUDA_BUILD_EMULATION`` is ``TRUE``.
+
+``CUDA_LINK_LIBRARIES_KEYWORD`` (Default: ``""``)
+  .. versionadded:: 3.9
+
+  The ``<PRIVATE|PUBLIC|INTERFACE>`` keyword to use for internal
+  :command:`target_link_libraries` calls. The default is to use no keyword which
+  uses the old "plain" form of :command:`target_link_libraries`. Note that is matters
+  because whatever is used inside the ``FindCUDA`` module must also be used
+  outside - the two forms of :command:`target_link_libraries` cannot be mixed.
+
+``CUDA_GENERATED_OUTPUT_DIR`` (Default: :variable:`CMAKE_CURRENT_BINARY_DIR`)
+  Set to the path you wish to have the generated files placed.  If it is
+  blank output files will be placed in :variable:`CMAKE_CURRENT_BINARY_DIR`.
+  Intermediate files will always be placed in
+  ``CMAKE_CURRENT_BINARY_DIR/CMakeFiles``.
+
+``CUDA_HOST_COMPILATION_CPP`` (Default: ``ON``)
+  Set to ``OFF`` for C compilation of host code.
+
+``CUDA_HOST_COMPILER`` (Default: ``CMAKE_C_COMPILER``)
+  Set the host compiler to be used by nvcc.  Ignored if ``-ccbin`` or
+  ``--compiler-bindir`` is already present in the ``CUDA_NVCC_FLAGS`` or
+  ``CUDA_NVCC_FLAGS_<CONFIG>`` variables.  For Visual Studio targets,
+  the host compiler is constructed with one or more visual studio macros
+  such as ``$(VCInstallDir)``, that expands out to the path when
+  the command is run from within VS.
+
+  .. versionadded:: 3.13
+    If the :envvar:`CUDAHOSTCXX` environment variable is set it will
+    be used as the default.
+
+``CUDA_NVCC_FLAGS``, ``CUDA_NVCC_FLAGS_<CONFIG>``
+  Additional NVCC command line arguments.  NOTE: multiple arguments must be
+  semi-colon delimited (e.g. ``--compiler-options;-Wall``)
+
+  .. versionadded:: 3.6
+    Contents of these variables may use
+    :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+``CUDA_PROPAGATE_HOST_FLAGS`` (Default: ``ON``)
+  Set to ``ON`` to propagate :variable:`CMAKE_{C,CXX}_FLAGS <CMAKE_<LANG>_FLAGS>` and their configuration
+  dependent counterparts (e.g. ``CMAKE_C_FLAGS_DEBUG``) automatically to the
+  host compiler through nvcc's ``-Xcompiler`` flag.  This helps make the
+  generated host code match the rest of the system better.  Sometimes
+  certain flags give nvcc problems, and this will help you turn the flag
+  propagation off.  This does not affect the flags supplied directly to nvcc
+  via ``CUDA_NVCC_FLAGS`` or through the ``OPTION`` flags specified through
+  ``cuda_add_library()``, ``cuda_add_executable()``, or ``cuda_wrap_srcs()``.  Flags used for
+  shared library compilation are not affected by this flag.
 
-  CUDA_NVCC_FLAGS
-  CUDA_NVCC_FLAGS_<CONFIG>
-  -- Additional NVCC command line arguments.  NOTE: multiple arguments must be
-     semi-colon delimited (e.g. --compiler-options;-Wall)
-
-  CUDA_PROPAGATE_HOST_FLAGS (Default ON)
-  -- Set to ON to propagate CMAKE_{C,CXX}_FLAGS and their configuration
-     dependent counterparts (e.g. CMAKE_C_FLAGS_DEBUG) automatically to the
-     host compiler through nvcc's -Xcompiler flag.  This helps make the
-     generated host code match the rest of the system better.  Sometimes
-     certain flags give nvcc problems, and this will help you turn the flag
-     propagation off.  This does not affect the flags supplied directly to nvcc
-     via CUDA_NVCC_FLAGS or through the OPTION flags specified through
-     CUDA_ADD_LIBRARY, CUDA_ADD_EXECUTABLE, or CUDA_WRAP_SRCS.  Flags used for
-     shared library compilation are not affected by this flag.
-
-  CUDA_SEPARABLE_COMPILATION (Default OFF)
-  -- If set this will enable separable compilation for all CUDA runtime object
-     files.  If used outside of CUDA_ADD_EXECUTABLE and CUDA_ADD_LIBRARY
-     (e.g. calling CUDA_WRAP_SRCS directly),
-     CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME and
-     CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS should be called.
-
-  CUDA_SOURCE_PROPERTY_FORMAT
-  -- If this source file property is set, it can override the format specified
-     to CUDA_WRAP_SRCS (OBJ, PTX, CUBIN, or FATBIN).  If an input source file
-     is not a .cu file, setting this file will cause it to be treated as a .cu
-     file. See documentation for set_source_files_properties on how to set
-     this property.
-
-  CUDA_USE_STATIC_CUDA_RUNTIME (Default ON)
-  -- When enabled the static version of the CUDA runtime library will be used
-     in CUDA_LIBRARIES.  If the version of CUDA configured doesn't support
-     this option, then it will be silently disabled.
-
-  CUDA_VERBOSE_BUILD (Default OFF)
-  -- Set to ON to see all the commands used when building the CUDA file.  When
-     using a Makefile generator the value defaults to VERBOSE (run make
-     VERBOSE=1 to see output), although setting CUDA_VERBOSE_BUILD to ON will
-     always print the output.
-
-The script creates the following macros (in alphabetical order)::
-
-  CUDA_ADD_CUFFT_TO_TARGET( cuda_target )
-  -- Adds the cufft library to the target (can be any target).  Handles whether
-     you are in emulation mode or not.
-
-  CUDA_ADD_CUBLAS_TO_TARGET( cuda_target )
-  -- Adds the cublas library to the target (can be any target).  Handles
-     whether you are in emulation mode or not.
-
-  CUDA_ADD_EXECUTABLE( cuda_target file0 file1 ...
-                       [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [OPTIONS ...] )
-  -- Creates an executable "cuda_target" which is made up of the files
-     specified.  All of the non CUDA C files are compiled using the standard
-     build rules specified by CMAKE and the cuda files are compiled to object
-     files using nvcc and the host compiler.  In addition CUDA_INCLUDE_DIRS is
-     added automatically to include_directories().  Some standard CMake target
-     calls can be used on the target after calling this macro
-     (e.g. set_target_properties and target_link_libraries), but setting
-     properties that adjust compilation flags will not affect code compiled by
-     nvcc.  Such flags should be modified before calling CUDA_ADD_EXECUTABLE,
-     CUDA_ADD_LIBRARY or CUDA_WRAP_SRCS.
-
-  CUDA_ADD_LIBRARY( cuda_target file0 file1 ...
-                    [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [OPTIONS ...] )
-  -- Same as CUDA_ADD_EXECUTABLE except that a library is created.
-
-  CUDA_BUILD_CLEAN_TARGET()
-  -- Creates a convenience target that deletes all the dependency files
-     generated.  You should make clean after running this target to ensure the
-     dependency files get regenerated.
-
-  CUDA_COMPILE( generated_files file0 file1 ... [STATIC | SHARED | MODULE]
-                [OPTIONS ...] )
-  -- Returns a list of generated files from the input source files to be used
-     with ADD_LIBRARY or ADD_EXECUTABLE.
-
-  CUDA_COMPILE_PTX( generated_files file0 file1 ... [OPTIONS ...] )
-  -- Returns a list of PTX files generated from the input source files.
-
-  CUDA_COMPILE_FATBIN( generated_files file0 file1 ... [OPTIONS ...] )
-  -- Returns a list of FATBIN files generated from the input source files.
-
-  CUDA_COMPILE_CUBIN( generated_files file0 file1 ... [OPTIONS ...] )
-  -- Returns a list of CUBIN files generated from the input source files.
-
-  CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME( output_file_var
-                                                       cuda_target
-                                                       object_files )
-  -- Compute the name of the intermediate link file used for separable
-     compilation.  This file name is typically passed into
-     CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS.  output_file_var is produced
-     based on cuda_target the list of objects files that need separable
-     compilation as specified by object_files.  If the object_files list is
-     empty, then output_file_var will be empty.  This function is called
-     automatically for CUDA_ADD_LIBRARY and CUDA_ADD_EXECUTABLE.  Note that
-     this is a function and not a macro.
-
-  CUDA_INCLUDE_DIRECTORIES( path0 path1 ... )
-  -- Sets the directories that should be passed to nvcc
-     (e.g. nvcc -Ipath0 -Ipath1 ... ). These paths usually contain other .cu
-     files.
-
-
-  CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS( output_file_var cuda_target
-                                           nvcc_flags object_files)
-  -- Generates the link object required by separable compilation from the given
-     object files.  This is called automatically for CUDA_ADD_EXECUTABLE and
-     CUDA_ADD_LIBRARY, but can be called manually when using CUDA_WRAP_SRCS
-     directly.  When called from CUDA_ADD_LIBRARY or CUDA_ADD_EXECUTABLE the
-     nvcc_flags passed in are the same as the flags passed in via the OPTIONS
-     argument.  The only nvcc flag added automatically is the bitness flag as
-     specified by CUDA_64_BIT_DEVICE_CODE.  Note that this is a function
-     instead of a macro.
-
-  CUDA_SELECT_NVCC_ARCH_FLAGS(out_variable [target_CUDA_architectures])
-  -- Selects GPU arch flags for nvcc based on target_CUDA_architectures
-     target_CUDA_architectures : Auto | Common | All | LIST(ARCH_AND_PTX ...)
-      - "Auto" detects local machine GPU compute arch at runtime.
-      - "Common" and "All" cover common and entire subsets of architectures
-     ARCH_AND_PTX : NAME | NUM.NUM | NUM.NUM(NUM.NUM) | NUM.NUM+PTX
-     NAME: Fermi Kepler Maxwell Kepler+Tegra Kepler+Tesla Maxwell+Tegra Pascal
-     NUM: Any number. Only those pairs are currently accepted by NVCC though:
-           2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2
-     Returns LIST of flags to be added to CUDA_NVCC_FLAGS in ${out_variable}
-     Additionally, sets ${out_variable}_readable to the resulting numeric list
-     Example:
-      CUDA_SELECT_NVCC_ARCH_FLAGS(ARCH_FLAGS 3.0 3.5+PTX 5.2(5.0) Maxwell)
-       LIST(APPEND CUDA_NVCC_FLAGS ${ARCH_FLAGS})
-
-     More info on CUDA architectures: https://en.wikipedia.org/wiki/CUDA
-     Note that this is a function instead of a macro.
-
-  CUDA_WRAP_SRCS ( cuda_target format generated_files file0 file1 ...
-                   [STATIC | SHARED | MODULE] [OPTIONS ...] )
-  -- This is where all the magic happens.  CUDA_ADD_EXECUTABLE,
-     CUDA_ADD_LIBRARY, CUDA_COMPILE, and CUDA_COMPILE_PTX all call this
-     function under the hood.
-
-     Given the list of files (file0 file1 ... fileN) this macro generates
-     custom commands that generate either PTX or linkable objects (use "PTX" or
-     "OBJ" for the format argument to switch).  Files that don't end with .cu
-     or have the HEADER_FILE_ONLY property are ignored.
-
-     The arguments passed in after OPTIONS are extra command line options to
-     give to nvcc.  You can also specify per configuration options by
-     specifying the name of the configuration followed by the options.  General
-     options must precede configuration specific options.  Not all
-     configurations need to be specified, only the ones provided will be used.
-
-        OPTIONS -DFLAG=2 "-DFLAG_OTHER=space in flag"
-        DEBUG -g
-        RELEASE --use_fast_math
-        RELWITHDEBINFO --use_fast_math;-g
-        MINSIZEREL --use_fast_math
-
-     For certain configurations (namely VS generating object files with
-     CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE set to ON), no generated file will
-     be produced for the given cuda file.  This is because when you add the
-     cuda file to Visual Studio it knows that this file produces an object file
-     and will link in the resulting object file automatically.
-
-     This script will also generate a separate cmake script that is used at
-     build time to invoke nvcc.  This is for several reasons.
-
-       1. nvcc can return negative numbers as return values which confuses
-       Visual Studio into thinking that the command succeeded.  The script now
-       checks the error codes and produces errors when there was a problem.
-
-       2. nvcc has been known to not delete incomplete results when it
-       encounters problems.  This confuses build systems into thinking the
-       target was generated when in fact an unusable file exists.  The script
-       now deletes the output files if there was an error.
-
-       3. By putting all the options that affect the build into a file and then
-       make the build rule dependent on the file, the output files will be
-       regenerated when the options change.
-
-     This script also looks at optional arguments STATIC, SHARED, or MODULE to
-     determine when to target the object compilation for a shared library.
-     BUILD_SHARED_LIBS is ignored in CUDA_WRAP_SRCS, but it is respected in
-     CUDA_ADD_LIBRARY.  On some systems special flags are added for building
-     objects intended for shared libraries.  A preprocessor macro,
-     <target_name>_EXPORTS is defined when a shared library compilation is
-     detected.
-
-     Flags passed into add_definitions with -D or /D are passed along to nvcc.
-
-
-
-The script defines the following variables::
-
-  CUDA_VERSION_MAJOR    -- The major version of cuda as reported by nvcc.
-  CUDA_VERSION_MINOR    -- The minor version.
-  CUDA_VERSION
-  CUDA_VERSION_STRING   -- CUDA_VERSION_MAJOR.CUDA_VERSION_MINOR
-  CUDA_HAS_FP16         -- Whether a short float (float16,fp16) is supported.
-
-  CUDA_TOOLKIT_ROOT_DIR -- Path to the CUDA Toolkit (defined if not set).
-  CUDA_SDK_ROOT_DIR     -- Path to the CUDA SDK.  Use this to find files in the
-                           SDK.  This script will not directly support finding
-                           specific libraries or headers, as that isn't
-                           supported by NVIDIA.  If you want to change
-                           libraries when the path changes see the
-                           FindCUDA.cmake script for an example of how to clear
-                           these variables.  There are also examples of how to
-                           use the CUDA_SDK_ROOT_DIR to locate headers or
-                           libraries, if you so choose (at your own risk).
-  CUDA_INCLUDE_DIRS     -- Include directory for cuda headers.  Added automatically
-                           for CUDA_ADD_EXECUTABLE and CUDA_ADD_LIBRARY.
-  CUDA_LIBRARIES        -- Cuda RT library.
-  CUDA_CUFFT_LIBRARIES  -- Device or emulation library for the Cuda FFT
-                           implementation (alternative to:
-                           CUDA_ADD_CUFFT_TO_TARGET macro)
-  CUDA_CUBLAS_LIBRARIES -- Device or emulation library for the Cuda BLAS
-                           implementation (alternative to:
-                           CUDA_ADD_CUBLAS_TO_TARGET macro).
-  CUDA_cudart_static_LIBRARY -- Statically linkable cuda runtime library.
-                                Only available for CUDA version 5.5+
-  CUDA_cudadevrt_LIBRARY -- Device runtime library.
-                            Required for separable compilation.
-  CUDA_cupti_LIBRARY    -- CUDA Profiling Tools Interface library.
-                           Only available for CUDA version 4.0+.
-  CUDA_curand_LIBRARY   -- CUDA Random Number Generation library.
-                           Only available for CUDA version 3.2+.
-  CUDA_cusolver_LIBRARY -- CUDA Direct Solver library.
-                           Only available for CUDA version 7.0+.
-  CUDA_cusparse_LIBRARY -- CUDA Sparse Matrix library.
-                           Only available for CUDA version 3.2+.
-  CUDA_npp_LIBRARY      -- NVIDIA Performance Primitives lib.
-                           Only available for CUDA version 4.0+.
-  CUDA_nppc_LIBRARY     -- NVIDIA Performance Primitives lib (core).
-                           Only available for CUDA version 5.5+.
-  CUDA_nppi_LIBRARY     -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 5.5 - 8.0.
-  CUDA_nppial_LIBRARY   -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppicc_LIBRARY   -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppicom_LIBRARY  -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0 - 10.2.
-                           Replaced by nvjpeg.
-  CUDA_nppidei_LIBRARY  -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppif_LIBRARY    -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppig_LIBRARY    -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppim_LIBRARY    -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppist_LIBRARY   -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppisu_LIBRARY   -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_nppitc_LIBRARY   -- NVIDIA Performance Primitives lib (image processing).
-                           Only available for CUDA version 9.0.
-  CUDA_npps_LIBRARY     -- NVIDIA Performance Primitives lib (signal processing).
-                           Only available for CUDA version 5.5+.
-  CUDA_nvcuvenc_LIBRARY -- CUDA Video Encoder library.
-                           Only available for CUDA version 3.2+.
-                           Windows only.
-  CUDA_nvcuvid_LIBRARY  -- CUDA Video Decoder library.
-                           Only available for CUDA version 3.2+.
-                           Windows only.
-  CUDA_nvToolsExt_LIBRARY
-                        -- NVIDA CUDA Tools Extension library.
-                           Available for CUDA version 5+.
-  CUDA_OpenCL_LIBRARY   -- NVIDA CUDA OpenCL library.
-                           Available for CUDA version 5+.
+``CUDA_SEPARABLE_COMPILATION`` (Default: ``OFF``)
+  If set this will enable separable compilation for all CUDA runtime object
+  files.  If used outside of ``cuda_add_executable()`` and ``cuda_add_library()``
+  (e.g. calling ``cuda_wrap_srcs()`` directly),
+  ``cuda_compute_separable_compilation_object_file_name()`` and
+  ``cuda_link_separable_compilation_objects()`` should be called.
+
+``CUDA_SOURCE_PROPERTY_FORMAT``
+  .. versionadded:: 3.3
+
+  If this source file property is set, it can override the format specified
+  to ``cuda_wrap_srcs()`` (``OBJ``, ``PTX``, ``CUBIN``, or ``FATBIN``).  If an input source file
+  is not a ``.cu`` file, setting this file will cause it to be treated as a ``.cu``
+  file. See documentation for set_source_files_properties on how to set
+  this property.
+
+``CUDA_USE_STATIC_CUDA_RUNTIME`` (Default: ``ON``)
+  .. versionadded:: 3.3
+
+  When enabled the static version of the CUDA runtime library will be used
+  in ``CUDA_LIBRARIES``.  If the version of CUDA configured doesn't support
+  this option, then it will be silently disabled.
+
+``CUDA_VERBOSE_BUILD`` (Default: ``OFF``)
+  Set to ``ON`` to see all the commands used when building the CUDA file.  When
+  using a Makefile generator the value defaults to ``VERBOSE`` (run
+  ``make VERBOSE=1`` to see output), although setting ``CUDA_VERBOSE_BUILD`` to ``ON`` will
+  always print the output.
+
+Commands
+""""""""
+
+The script creates the following functions and macros (in alphabetical order):
+
+.. code-block:: cmake
+
+  cuda_add_cufft_to_target(<cuda_target>)
+
+Adds the cufft library to the target (can be any target).  Handles whether
+you are in emulation mode or not.
+
+.. code-block:: cmake
+
+  cuda_add_cublas_to_target(<cuda_target>)
+
+Adds the cublas library to the target (can be any target).  Handles
+whether you are in emulation mode or not.
+
+.. code-block:: cmake
+
+  cuda_add_executable(<cuda_target> <file>...
+                      [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [OPTIONS ...])
+
+Creates an executable ``<cuda_target>`` which is made up of the files
+specified.  All of the non CUDA C files are compiled using the standard
+build rules specified by CMake and the CUDA files are compiled to object
+files using nvcc and the host compiler.  In addition ``CUDA_INCLUDE_DIRS`` is
+added automatically to :command:`include_directories`.  Some standard CMake target
+calls can be used on the target after calling this macro
+(e.g. :command:`set_target_properties` and :command:`target_link_libraries`), but setting
+properties that adjust compilation flags will not affect code compiled by
+nvcc.  Such flags should be modified before calling ``cuda_add_executable()``,
+``cuda_add_library()`` or ``cuda_wrap_srcs()``.
+
+.. code-block:: cmake
+
+  cuda_add_library(<cuda_target> <file>...
+                   [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [OPTIONS ...])
+
+Same as ``cuda_add_executable()`` except that a library is created.
+
+.. code-block:: cmake
+
+  cuda_build_clean_target()
+
+Creates a convenience target that deletes all the dependency files
+generated.  You should make clean after running this target to ensure the
+dependency files get regenerated.
+
+.. code-block:: cmake
+
+  cuda_compile(<generated_files> <file>... [STATIC | SHARED | MODULE]
+               [OPTIONS ...])
+
+Returns a list of generated files from the input source files to be used
+with :command:`add_library` or :command:`add_executable`.
+
+.. code-block:: cmake
+
+  cuda_compile_ptx(<generated_files> <file>... [OPTIONS ...])
+
+Returns a list of ``PTX`` files generated from the input source files.
+
+.. code-block:: cmake
+
+  cuda_compile_fatbin(<generated_files> <file>... [OPTIONS ...])
+
+.. versionadded:: 3.1
+
+Returns a list of ``FATBIN`` files generated from the input source files.
+
+.. code-block:: cmake
+
+  cuda_compile_cubin(<generated_files> <file>... [OPTIONS ...])
+
+.. versionadded:: 3.1
+
+Returns a list of ``CUBIN`` files generated from the input source files.
+
+.. code-block:: cmake
+
+  cuda_compute_separable_compilation_object_file_name(<output_file_var>
+                                                      <cuda_target>
+                                                      <object_files>)
+
+Compute the name of the intermediate link file used for separable
+compilation.  This file name is typically passed into
+``CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS``.  output_file_var is produced
+based on cuda_target the list of objects files that need separable
+compilation as specified by ``<object_files>``.  If the ``<object_files>`` list is
+empty, then ``<output_file_var>`` will be empty.  This function is called
+automatically for ``cuda_add_library()`` and ``cuda_add_executable()``.  Note that
+this is a function and not a macro.
+
+.. code-block:: cmake
+
+  cuda_include_directories(path0 path1 ...)
+
+Sets the directories that should be passed to nvcc
+(e.g. ``nvcc -Ipath0 -Ipath1 ...``). These paths usually contain other ``.cu``
+files.
+
+.. code-block:: cmake
+
+  cuda_link_separable_compilation_objects(<output_file_var> <cuda_target>
+                                          <nvcc_flags> <object_files>)
+
+Generates the link object required by separable compilation from the given
+object files.  This is called automatically for ``cuda_add_executable()`` and
+``cuda_add_library()``, but can be called manually when using ``cuda_wrap_srcs()``
+directly.  When called from ``cuda_add_library()`` or ``cuda_add_executable()`` the
+``<nvcc_flags>`` passed in are the same as the flags passed in via the ``OPTIONS``
+argument.  The only nvcc flag added automatically is the bitness flag as
+specified by ``CUDA_64_BIT_DEVICE_CODE``.  Note that this is a function
+instead of a macro.
+
+.. code-block:: cmake
+
+  cuda_select_nvcc_arch_flags(<out_variable> [<target_CUDA_architecture> ...])
+
+Selects GPU arch flags for nvcc based on ``target_CUDA_architecture``.
+
+Values for ``target_CUDA_architecture``:
+
+* ``Auto``: detects local machine GPU compute arch at runtime.
+* ``Common`` and ``All``: cover common and entire subsets of architectures.
+* ``<name>``: one of ``Fermi``, ``Kepler``, ``Maxwell``, ``Kepler+Tegra``, ``Kepler+Tesla``, ``Maxwell+Tegra``, ``Pascal``.
+* ``<ver>``, ``<ver>(<ver>)``, ``<ver>+PTX``, where ``<ver>`` is one of
+  ``2.0``, ``2.1``, ``3.0``, ``3.2``, ``3.5``, ``3.7``, ``5.0``, ``5.2``, ``5.3``, ``6.0``, ``6.2``.
+
+Returns list of flags to be added to ``CUDA_NVCC_FLAGS`` in ``<out_variable>``.
+Additionally, sets ``<out_variable>_readable`` to the resulting numeric list.
+
+Example::
+
+  cuda_select_nvcc_arch_flags(ARCH_FLAGS 3.0 3.5+PTX 5.2(5.0) Maxwell)
+  list(APPEND CUDA_NVCC_FLAGS ${ARCH_FLAGS})
+
+More info on CUDA architectures: https://en.wikipedia.org/wiki/CUDA.
+Note that this is a function instead of a macro.
+
+.. code-block:: cmake
+
+  cuda_wrap_srcs(<cuda_target> <format> <generated_files> <file>...
+                 [STATIC | SHARED | MODULE] [OPTIONS ...])
+
+This is where all the magic happens.  ``cuda_add_executable()``,
+``cuda_add_library()``, ``cuda_compile()``, and ``cuda_compile_ptx()`` all call this
+function under the hood.
+
+Given the list of files ``<file>...`` this macro generates
+custom commands that generate either PTX or linkable objects (use ``PTX`` or
+``OBJ`` for the ``<format>`` argument to switch).  Files that don't end with ``.cu``
+or have the ``HEADER_FILE_ONLY`` property are ignored.
+
+The arguments passed in after ``OPTIONS`` are extra command line options to
+give to nvcc.  You can also specify per configuration options by
+specifying the name of the configuration followed by the options.  General
+options must precede configuration specific options.  Not all
+configurations need to be specified, only the ones provided will be used.
+For example:
+
+.. code-block:: cmake
+
+  cuda_add_executable(...
+    OPTIONS -DFLAG=2 "-DFLAG_OTHER=space in flag"
+    DEBUG -g
+    RELEASE --use_fast_math
+    RELWITHDEBINFO --use_fast_math;-g
+    MINSIZEREL --use_fast_math)
+
+For certain configurations (namely VS generating object files with
+``CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE`` set to ``ON``), no generated file will
+be produced for the given cuda file.  This is because when you add the
+cuda file to Visual Studio it knows that this file produces an object file
+and will link in the resulting object file automatically.
+
+This script will also generate a separate cmake script that is used at
+build time to invoke nvcc.  This is for several reasons:
+
+* nvcc can return negative numbers as return values which confuses
+  Visual Studio into thinking that the command succeeded.  The script now
+  checks the error codes and produces errors when there was a problem.
+
+* nvcc has been known to not delete incomplete results when it
+  encounters problems.  This confuses build systems into thinking the
+  target was generated when in fact an unusable file exists.  The script
+  now deletes the output files if there was an error.
+
+* By putting all the options that affect the build into a file and then
+  make the build rule dependent on the file, the output files will be
+  regenerated when the options change.
+
+This script also looks at optional arguments ``STATIC``, ``SHARED``, or ``MODULE`` to
+determine when to target the object compilation for a shared library.
+:variable:`BUILD_SHARED_LIBS` is ignored in ``cuda_wrap_srcs()``, but it is respected in
+``cuda_add_library()``.  On some systems special flags are added for building
+objects intended for shared libraries.  A preprocessor macro,
+``<target_name>_EXPORTS`` is defined when a shared library compilation is
+detected.
+
+Flags passed into add_definitions with ``-D`` or ``/D`` are passed along to nvcc.
+
+Result Variables
+""""""""""""""""
+
+The script defines the following variables:
+
+``CUDA_VERSION_MAJOR``
+  The major version of cuda as reported by nvcc.
+
+``CUDA_VERSION_MINOR``
+  The minor version.
+
+``CUDA_VERSION``, ``CUDA_VERSION_STRING``
+  Full version in the ``X.Y`` format.
+
+``CUDA_HAS_FP16``
+  .. versionadded:: 3.6
+    Whether a short float (``float16``, ``fp16``) is supported.
+
+``CUDA_TOOLKIT_ROOT_DIR``
+  Path to the CUDA Toolkit (defined if not set).
+
+``CUDA_SDK_ROOT_DIR``
+  Path to the CUDA SDK.  Use this to find files in the SDK.  This script will
+  not directly support finding specific libraries or headers, as that isn't
+  supported by NVIDIA.  If you want to change libraries when the path changes
+  see the ``FindCUDA.cmake`` script for an example of how to clear these
+  variables.  There are also examples of how to use the ``CUDA_SDK_ROOT_DIR``
+  to locate headers or libraries, if you so choose (at your own risk).
+
+``CUDA_INCLUDE_DIRS``
+  Include directory for cuda headers.  Added automatically
+  for ``cuda_add_executable()`` and ``cuda_add_library()``.
+
+``CUDA_LIBRARIES``
+  Cuda RT library.
+
+``CUDA_CUFFT_LIBRARIES``
+  Device or emulation library for the Cuda FFT implementation (alternative to
+  ``cuda_add_cufft_to_target()`` macro)
+
+``CUDA_CUBLAS_LIBRARIES``
+  Device or emulation library for the Cuda BLAS implementation (alternative to
+  ``cuda_add_cublas_to_target()`` macro).
+
+``CUDA_cudart_static_LIBRARY``
+  Statically linkable cuda runtime library.
+  Only available for CUDA version 5.5+.
+
+``CUDA_cudadevrt_LIBRARY``
+  .. versionadded:: 3.7
+    Device runtime library.  Required for separable compilation.
+
+``CUDA_cupti_LIBRARY``
+  CUDA Profiling Tools Interface library.
+  Only available for CUDA version 4.0+.
+
+``CUDA_curand_LIBRARY``
+  CUDA Random Number Generation library.
+  Only available for CUDA version 3.2+.
+
+``CUDA_cusolver_LIBRARY``
+  .. versionadded:: 3.2
+    CUDA Direct Solver library.
+    Only available for CUDA version 7.0+.
+
+``CUDA_cusparse_LIBRARY``
+  CUDA Sparse Matrix library.
+  Only available for CUDA version 3.2+.
+
+``CUDA_npp_LIBRARY``
+  NVIDIA Performance Primitives lib.
+  Only available for CUDA version 4.0+.
+
+``CUDA_nppc_LIBRARY``
+  NVIDIA Performance Primitives lib (core).
+  Only available for CUDA version 5.5+.
+
+``CUDA_nppi_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 5.5 - 8.0.
+
+``CUDA_nppial_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppicc_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppicom_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0 - 10.2.
+  Replaced by nvjpeg.
+
+``CUDA_nppidei_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppif_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppig_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppim_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppist_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppisu_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_nppitc_LIBRARY``
+  NVIDIA Performance Primitives lib (image processing).
+  Only available for CUDA version 9.0.
+
+``CUDA_npps_LIBRARY``
+  NVIDIA Performance Primitives lib (signal processing).
+  Only available for CUDA version 5.5+.
+
+``CUDA_nvcuvenc_LIBRARY``
+  CUDA Video Encoder library.
+  Only available for CUDA version 3.2+.
+  Windows only.
+
+``CUDA_nvcuvid_LIBRARY``
+  CUDA Video Decoder library.
+  Only available for CUDA version 3.2+.
+  Windows only.
+
+``CUDA_nvToolsExt_LIBRARY``
+  .. versionadded:: 3.16
+    NVIDA CUDA Tools Extension library.
+    Available for CUDA version 5+.
+
+``CUDA_OpenCL_LIBRARY``
+  .. versionadded:: 3.16
+    NVIDA CUDA OpenCL library.
+    Available for CUDA version 5+.
 
 #]=======================================================================]
 
@@ -702,8 +834,19 @@ if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING)
     )
 
   if (CUDA_TOOLKIT_ROOT_DIR_NVCC)
-    get_filename_component(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY)
-    get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR}" DIRECTORY CACHE)
+    # Given that NVCC can be provided by multiple different sources (NVIDIA HPC SDK, CUDA Toolkit, distro)
+    # each of which has a different layout, we need to extract the CUDA toolkit root from the compiler
+    # itself, allowing us to support numerous different scattered toolkit layouts
+    execute_process(COMMAND ${CUDA_TOOLKIT_ROOT_DIR_NVCC} "-v" "__cmake_determine_cuda"
+      OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT)
+    if(_CUDA_NVCC_OUT MATCHES "TOP=([^\r\n]*)")
+      get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CMAKE_MATCH_1}" ABSOLUTE CACHE)
+    else()
+      get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY)
+      get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR}" DIRECTORY CACHE)
+    endif()
+    unset(_CUDA_NVCC_OUT)
+
     string(REGEX REPLACE "[/\\\\]?bin[64]*[/\\\\]?$" "" CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR})
     # We need to force this back into the cache.
     set(CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR} CACHE PATH "Toolkit location." FORCE)
index 9351288..a35b3f8 100644 (file)
@@ -25,44 +25,26 @@ if(CMAKE_CUDA_COMPILER_LOADED) # CUDA as a language
 endif()
 
 # See: https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#gpu-feature-list
+# Additions, deprecations, and removals can be found in the release notes:
+# https://developer.nvidia.com/cuda-toolkit-archive
 
-# This list will be used for CUDA_ARCH_NAME = All option
-set(CUDA_KNOWN_GPU_ARCHITECTURES  "Fermi" "Kepler" "Maxwell")
+# The initial status here is for CUDA 7.0
+set(CUDA_KNOWN_GPU_ARCHITECTURES  "Fermi" "Kepler" "Maxwell" "Kepler+Tegra" "Kepler+Tesla" "Maxwell+Tegra")
+set(CUDA_COMMON_GPU_ARCHITECTURES "2.0" "2.1" "3.0" "3.5" "5.0" "5.3")
+set(CUDA_LIMIT_GPU_ARCHITECTURE "6.0")
+set(CUDA_ALL_GPU_ARCHITECTURES "2.0" "2.1" "3.0" "3.2" "3.5" "3.7" "5.0" "5.2" "5.3")
+set(_CUDA_MAX_COMMON_ARCHITECTURE "5.2+PTX")
 
-# This list will be used for CUDA_ARCH_NAME = Common option (enabled by default)
-set(CUDA_COMMON_GPU_ARCHITECTURES "3.5" "5.0")
-# 3.0 is removed in CUDA 11, see:
-# https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#deprecated-features
-if(CUDA_VERSION VERSION_LESS "11.0")
-  list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "3.0")
-endif()
-
-if(CUDA_VERSION VERSION_LESS "7.0")
-  set(CUDA_LIMIT_GPU_ARCHITECTURE "5.2")
-endif()
-
-# This list is used to filter CUDA archs when autodetecting
-set(CUDA_ALL_GPU_ARCHITECTURES "3.0" "3.2" "3.5" "5.0")
-
-if(CUDA_VERSION VERSION_GREATER_EQUAL "7.0")
-  list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Kepler+Tegra" "Kepler+Tesla" "Maxwell+Tegra")
-  list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "5.2")
-
-  if(CUDA_VERSION VERSION_LESS "8.0")
-    list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "5.2+PTX")
-    set(CUDA_LIMIT_GPU_ARCHITECTURE "6.0")
-  endif()
-endif()
 
 if(CUDA_VERSION VERSION_GREATER_EQUAL "8.0")
   list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Pascal")
   list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "6.0" "6.1")
   list(APPEND CUDA_ALL_GPU_ARCHITECTURES "6.0" "6.1" "6.2")
 
-  if(CUDA_VERSION VERSION_LESS "9.0")
-    list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "6.2+PTX")
-    set(CUDA_LIMIT_GPU_ARCHITECTURE "7.0")
-  endif()
+  set(_CUDA_MAX_COMMON_ARCHITECTURE "6.2+PTX")
+  set(CUDA_LIMIT_GPU_ARCHITECTURE "7.0")
+
+  list(REMOVE_ITEM CUDA_COMMON_GPU_ARCHITECTURES "2.0" "2.1")
 endif ()
 
 if(CUDA_VERSION VERSION_GREATER_EQUAL "9.0")
@@ -70,10 +52,11 @@ if(CUDA_VERSION VERSION_GREATER_EQUAL "9.0")
   list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.0")
   list(APPEND CUDA_ALL_GPU_ARCHITECTURES "7.0" "7.2")
 
-  if(CUDA_VERSION VERSION_LESS "10.0")
-    list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.2+PTX")
-    set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
-  endif()
+  set(_CUDA_MAX_COMMON_ARCHITECTURE "7.2+PTX")
+  set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
+
+  list(REMOVE_ITEM CUDA_KNOWN_GPU_ARCHITECTURES "Fermi")
+  list(REMOVE_ITEM CUDA_ALL_GPU_ARCHITECTURES "2.0" "2.1")
 endif()
 
 if(CUDA_VERSION VERSION_GREATER_EQUAL "10.0")
@@ -81,32 +64,46 @@ if(CUDA_VERSION VERSION_GREATER_EQUAL "10.0")
   list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.5")
   list(APPEND CUDA_ALL_GPU_ARCHITECTURES "7.5")
 
-  if(CUDA_VERSION VERSION_LESS "11.0")
-    list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "7.5+PTX")
-    set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
-  endif()
+  set(_CUDA_MAX_COMMON_ARCHITECTURE "7.5+PTX")
+  set(CUDA_LIMIT_GPU_ARCHITECTURE "8.0")
+
+  list(REMOVE_ITEM CUDA_COMMON_GPU_ARCHITECTURES "3.0")
 endif()
 
+# https://docs.nvidia.com/cuda/archive/11.0/cuda-toolkit-release-notes/index.html#cuda-general-new-features
+# https://docs.nvidia.com/cuda/archive/11.0/cuda-toolkit-release-notes/index.html#deprecated-features
 if(CUDA_VERSION VERSION_GREATER_EQUAL "11.0")
   list(APPEND CUDA_KNOWN_GPU_ARCHITECTURES "Ampere")
   list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0")
   list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.0")
 
-  if(CUDA_VERSION VERSION_LESS "11.1")
-    list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.0+PTX")
-    set(CUDA_LIMIT_GPU_ARCHITECTURE "8.6")
-  endif()
+  set(_CUDA_MAX_COMMON_ARCHITECTURE "8.0+PTX")
+  set(CUDA_LIMIT_GPU_ARCHITECTURE "8.6")
+
+  list(REMOVE_ITEM CUDA_COMMON_GPU_ARCHITECTURES "3.5" "5.0")
+  list(REMOVE_ITEM CUDA_ALL_GPU_ARCHITECTURES "3.0" "3.2")
 endif()
 
 if(CUDA_VERSION VERSION_GREATER_EQUAL "11.1")
-  list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.6" "8.6+PTX")
+  list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "8.6")
   list(APPEND CUDA_ALL_GPU_ARCHITECTURES "8.6")
 
-  if(CUDA_VERSION VERSION_LESS "12.0")
-    set(CUDA_LIMIT_GPU_ARCHITECTURE "9.0")
-  endif()
+  set(_CUDA_MAX_COMMON_ARCHITECTURE "8.6+PTX")
+  set(CUDA_LIMIT_GPU_ARCHITECTURE "9.0")
 endif()
 
+list(APPEND CUDA_COMMON_GPU_ARCHITECTURES "${_CUDA_MAX_COMMON_ARCHITECTURE}")
+
+# Check with: cmake -DCUDA_VERSION=7.0 -P select_compute_arch.cmake
+if(DEFINED CMAKE_SCRIPT_MODE_FILE)
+  include(CMakePrintHelpers)
+  cmake_print_variables(CUDA_KNOWN_GPU_ARCHITECTURES)
+  cmake_print_variables(CUDA_COMMON_GPU_ARCHITECTURES)
+  cmake_print_variables(CUDA_LIMIT_GPU_ARCHITECTURE)
+  cmake_print_variables(CUDA_ALL_GPU_ARCHITECTURES)
+endif()
+
+
 ################################################################################################
 # A function for automatic detection of GPUs installed  (if autodetection is enabled)
 # Usage:
index d4cd338..de2b068 100644 (file)
@@ -11,6 +11,9 @@ This script locates the NVIDIA CUDA toolkit and the associated libraries, but
 does not require the ``CUDA`` language be enabled for a given project. This
 module does not search for the NVIDIA CUDA Samples.
 
+.. versionadded:: 3.19
+  QNX support.
+
 Search Behavior
 ^^^^^^^^^^^^^^^
 
@@ -426,6 +429,8 @@ Result variables
     Runtime library ``cudart``.
 
 ``CUDAToolkit_LIBRARY_ROOT``
+    .. versionadded:: 3.18
+
     The path to the CUDA Toolkit directory containing the nvvm directory and
     version.txt.
 
@@ -513,12 +518,24 @@ else()
         )
       endif()
 
-      if(CUDAToolkit_NVCC_EXECUTABLE)
-        get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
+      if(EXISTS "${CUDAToolkit_NVCC_EXECUTABLE}")
+        # If NVCC exists  then invoke it to find the toolkit location.
+        # This allows us to support wrapper scripts (e.g. ccache or colornvcc), CUDA Toolkit,
+        # NVIDIA HPC SDK, and distro's splayed layouts
+        execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda"
+          OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT)
+        if(_CUDA_NVCC_OUT MATCHES "TOP=([^\r\n]*)")
+          get_filename_component(CUDAToolkit_BIN_DIR "${CMAKE_MATCH_1}/bin" ABSOLUTE)
+        else()
+          get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
+        endif()
+        unset(_CUDA_NVCC_OUT)
 
-        set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
         mark_as_advanced(CUDAToolkit_BIN_DIR)
-      elseif(CUDAToolkit_SENTINEL_FILE)
+        set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
+      endif()
+
+      if(CUDAToolkit_SENTINEL_FILE)
         get_filename_component(CUDAToolkit_BIN_DIR ${CUDAToolkit_SENTINEL_FILE} DIRECTORY ABSOLUTE)
         set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}/bin")
 
@@ -721,6 +738,7 @@ elseif(NOT CUDAToolkit_FIND_QUIETLY)
 endif()
 
 if(CUDAToolkit_NVCC_EXECUTABLE AND
+   CMAKE_CUDA_COMPILER_VERSION AND
    CUDAToolkit_NVCC_EXECUTABLE STREQUAL CMAKE_CUDA_COMPILER)
   # Need to set these based off the already computed CMAKE_CUDA_COMPILER_VERSION value
   # This if statement will always match, but is used to provide variables for MATCH 1,2,3...
index 74b36c6..e37d225 100644 (file)
@@ -7,8 +7,11 @@ FindCURL
 
 Find the native CURL headers and libraries.
 
-This module accept optional COMPONENTS to check supported features and
-protocols::
+.. versionadded:: 3.14
+  This module accept optional COMPONENTS to check supported features and
+  protocols:
+
+::
 
   PROTOCOLS: ICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP LDAPS POP3
              POP3S RTMP RTSP SCP SFTP SMB SMBS SMTP SMTPS TELNET TFTP
@@ -18,6 +21,8 @@ protocols::
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.12
+
 This module defines :prop_tgt:`IMPORTED` target ``CURL::libcurl``, if
 curl has been found.
 
@@ -38,9 +43,14 @@ This module defines the following variables:
 ``CURL_VERSION_STRING``
   The version of ``curl`` found.
 
+.. versionadded:: 3.13
+  Debug and Release variants are found separately.
+
 CURL CMake
 ^^^^^^^^^^
 
+.. versionadded:: 3.17
+
 If CURL was built using the CMake buildsystem then it provides its own
 ``CURLConfig.cmake`` file for use with the :command:`find_package` command's
 config mode. This module looks for this file and, if found,
index 4e8232d..cf0d341 100644 (file)
@@ -13,6 +13,8 @@ features this function (i.e. at least ``1.1.19``)
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.15
+
 This module defines :prop_tgt:`IMPORTED` target ``Cups::Cups``, if Cups has
 been found.
 
index cde3a4d..5e25deb 100644 (file)
@@ -19,6 +19,8 @@ This module defines the following variables:
 ``CURSES_LIBRARIES``
   The libraries needed to use Curses.
 ``CURSES_CFLAGS``
+  .. versionadded:: 3.16
+
   Parameters which ought be given to C/C++ compilers when using Curses.
 ``CURSES_HAVE_CURSES_H``
   True if curses.h is available.
@@ -31,8 +33,10 @@ This module defines the following variables:
 
 Set ``CURSES_NEED_NCURSES`` to ``TRUE`` before the
 ``find_package(Curses)`` call if NCurses functionality is required.
-Set ``CURSES_NEED_WIDE`` to ``TRUE`` before the
-``find_package(Curses)`` call if unicode functionality is required.
+
+.. versionadded:: 3.10
+  Set ``CURSES_NEED_WIDE`` to ``TRUE`` before the
+  ``find_package(Curses)`` call if unicode functionality is required.
 
 Backward Compatibility
 ^^^^^^^^^^^^^^^^^^^^^^
index 81fbbb7..bbf941e 100644 (file)
@@ -6,8 +6,7 @@ FindDoxygen
 -----------
 
 Doxygen is a documentation generation tool (see http://www.doxygen.org).
-This module looks for Doxygen and some optional tools it supports. These
-tools are enabled as components in the :command:`find_package` command:
+This module looks for Doxygen and some optional tools it supports:
 
 ``dot``
   `Graphviz <http://graphviz.org>`_ ``dot`` utility used to render various
@@ -19,7 +18,9 @@ tools are enabled as components in the :command:`find_package` command:
   `Dia <https://wiki.gnome.org/Apps/Dia>`_ the diagram editor used by Doxygen's
   ``\diafile`` command.
 
-Examples:
+.. versionadded:: 3.9
+  These tools are available as components in the :command:`find_package` command.
+  For example:
 
 .. code-block:: cmake
 
@@ -38,12 +39,13 @@ The following variables are defined by this module:
 
   The version reported by ``doxygen --version``.
 
-The module defines ``IMPORTED`` targets for Doxygen and each component found.
-These can be used as part of custom commands, etc. and should be preferred over
-old-style (and now deprecated) variables like ``DOXYGEN_EXECUTABLE``. The
-following import targets are defined if their corresponding executable could be
-found (the component import targets will only be defined if that component was
-requested):
+.. versionadded:: 3.9
+  The module defines ``IMPORTED`` targets for Doxygen and each component found.
+  These can be used as part of custom commands, etc. and should be preferred over
+  old-style (and now deprecated) variables like ``DOXYGEN_EXECUTABLE``. The
+  following import targets are defined if their corresponding executable could be
+  found (the component import targets will only be defined if that component was
+  requested):
 
 ::
 
@@ -58,6 +60,8 @@ Functions
 
 .. command:: doxygen_add_docs
 
+  .. versionadded:: 3.9
+
   This function is intended as a convenience for adding a target for generating
   documentation with Doxygen. It aims to provide sensible defaults so that
   projects can generally just provide the input files and directories and that
@@ -93,19 +97,21 @@ Functions
   the :command:`add_custom_target` command used to create the custom target
   internally.
 
-  If ``ALL`` is set, the target will be added to the default build target.
-
-  If ``USE_STAMP_FILE`` is set, the custom command defined by this function will
-  create a stamp file with the name ``<targetName>.stamp`` in the current
-  binary directory whenever doxygen is re-run.  With this option present, all
-  items in ``<filesOrDirs>`` must be files (i.e. no directories, symlinks or
-  wildcards) and each of the files must exist at the time
-  ``doxygen_add_docs()`` is called.  An error will be raised if any of the
-  items listed is missing or is not a file when ``USE_STAMP_FILE`` is given.
-  A dependency will be created on each of the files so that doxygen will only
-  be re-run if one of the files is updated.  Without the ``USE_STAMP_FILE``
-  option, doxygen will always be re-run if the ``<targetName>`` target is built
-  regardless of whether anything listed in ``<filesOrDirs>`` has changed.
+  .. versionadded:: 3.12
+    If ``ALL`` is set, the target will be added to the default build target.
+
+  .. versionadded:: 3.16
+    If ``USE_STAMP_FILE`` is set, the custom command defined by this function will
+    create a stamp file with the name ``<targetName>.stamp`` in the current
+    binary directory whenever doxygen is re-run.  With this option present, all
+    items in ``<filesOrDirs>`` must be files (i.e. no directories, symlinks or
+    wildcards) and each of the files must exist at the time
+    ``doxygen_add_docs()`` is called.  An error will be raised if any of the
+    items listed is missing or is not a file when ``USE_STAMP_FILE`` is given.
+    A dependency will be created on each of the files so that doxygen will only
+    be re-run if one of the files is updated.  Without the ``USE_STAMP_FILE``
+    option, doxygen will always be re-run if the ``<targetName>`` target is built
+    regardless of whether anything listed in ``<filesOrDirs>`` has changed.
 
   The contents of the generated ``Doxyfile`` can be customized by setting CMake
   variables before calling ``doxygen_add_docs()``. Any variable with a name of
@@ -308,18 +314,19 @@ if they contain at least one space:
   WARN_LOGFILE
   XML_OUTPUT
 
-There are situations where it may be undesirable for a particular config option
-to be automatically quoted by ``doxygen_add_docs()``, such as ``ALIASES`` which
-may need to include its own embedded quoting.  The ``DOXYGEN_VERBATIM_VARS``
-variable can be used to specify a list of Doxygen variables (including the
-leading ``DOXYGEN_`` prefix) which should not be quoted.  The project is then
-responsible for ensuring that those variables' values make sense when placed
-directly in the Doxygen input file.  In the case of list variables, list items
-are still separated by spaces, it is only the automatic quoting that is
-skipped.  For example, the following allows ``doxygen_add_docs()`` to apply
-quoting to ``DOXYGEN_PROJECT_BRIEF``, but not each item in the
-``DOXYGEN_ALIASES`` list (:ref:`bracket syntax <Bracket Argument>` can also
-be used to make working with embedded quotes easier):
+.. versionadded:: 3.11
+  There are situations where it may be undesirable for a particular config option
+  to be automatically quoted by ``doxygen_add_docs()``, such as ``ALIASES`` which
+  may need to include its own embedded quoting.  The ``DOXYGEN_VERBATIM_VARS``
+  variable can be used to specify a list of Doxygen variables (including the
+  leading ``DOXYGEN_`` prefix) which should not be quoted.  The project is then
+  responsible for ensuring that those variables' values make sense when placed
+  directly in the Doxygen input file.  In the case of list variables, list items
+  are still separated by spaces, it is only the automatic quoting that is
+  skipped.  For example, the following allows ``doxygen_add_docs()`` to apply
+  quoting to ``DOXYGEN_PROJECT_BRIEF``, but not each item in the
+  ``DOXYGEN_ALIASES`` list (:ref:`bracket syntax <Bracket Argument>` can also
+  be used to make working with embedded quotes easier):
 
 .. code-block:: cmake
 
@@ -341,6 +348,8 @@ The resultant ``Doxyfile`` will contain the following lines:
 Deprecated Result Variables
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. deprecated:: 3.9
+
 For compatibility with previous versions of CMake, the following variables
 are also defined but they are deprecated and should no longer be used:
 
@@ -375,6 +384,8 @@ are also defined but they are deprecated and should no longer be used:
 Deprecated Hint Variables
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. deprecated:: 3.9
+
 .. variable:: DOXYGEN_SKIP_DOT
 
   This variable has no effect for the component form of ``find_package``.
index b0bb02a..f9cb432 100644 (file)
@@ -11,6 +11,8 @@ Expat is a stream-oriented XML parser library written in C.
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.10
+
 This module defines the following :prop_tgt:`IMPORTED` targets:
 
 ``EXPAT::EXPAT``
index 1384736..e67e931 100644 (file)
@@ -37,11 +37,20 @@ If flex is found on the system, the module provides the macro:
               )
 
 which creates a custom command to generate the ``FlexOutput`` file from
-the ``FlexInput`` file.  If ``COMPILE_FLAGS`` option is specified, the next
-parameter is added to the flex command line. If flex is configured to
-output a header file, the ``DEFINES_FILE`` option may be used to specify its
-name. Name is an alias used to get details of this custom command.
-Indeed the macro defines the following variables:
+the ``FlexInput`` file.  Name is an alias used to get details of this custom
+command.  If ``COMPILE_FLAGS`` option is specified, the next
+parameter is added to the flex command line.
+
+.. versionadded:: 3.5
+  If flex is configured to
+  output a header file, the ``DEFINES_FILE`` option may be used to specify its
+  name.
+
+.. versionchanged:: 3.17
+  When :policy:`CMP0098` is set to ``NEW``, ``flex`` runs in the
+  :variable:`CMAKE_CURRENT_BINARY_DIR` directory.
+
+The macro defines the following variables:
 
 ::
 
index e273642..e1e239a 100644 (file)
@@ -77,6 +77,10 @@ The following cache variables are also available to set or use:
 
 ``FLTK_IMAGES_LIBRARY_DEBUG``
   The FLTK Images library (debug)
+
+.. versionadded:: 3.11
+  Debug and Release variants are found separately and use per-configuration
+  variables.
 #]=======================================================================]
 
 if(NOT FLTK_SKIP_OPENGL)
index 3e6a177..82885cb 100644 (file)
@@ -10,6 +10,8 @@ Find the FreeType font renderer includes and library.
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.10
+
 This module defines the following :prop_tgt:`IMPORTED` target:
 
 ``Freetype::Freetype``
@@ -33,7 +35,10 @@ This module will set the following variables in your project:
 ``FREETYPE_LIBRARIES``
   the library to link against
 ``FREETYPE_VERSION_STRING``
-  the version of freetype found (since CMake 2.8.8)
+  the version of freetype found
+
+.. versionadded:: 3.7
+  Debug and Release variants are found separately.
 
 Hints
 ^^^^^
index fde84d4..5237e15 100644 (file)
@@ -10,6 +10,8 @@ Find Geospatial Data Abstraction Library (GDAL).
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.14
+
 This module defines :prop_tgt:`IMPORTED` target ``GDAL::GDAL``
 if GDAL has been found.
 
@@ -25,7 +27,8 @@ This module will set the following variables in your project:
 ``GDAL_LIBRARIES``
   Libraries to link to GDAL.
 ``GDAL_VERSION``
-  The version of GDAL found.
+  .. versionadded:: 3.14
+    The version of GDAL found.
 
 Cache variables
 ^^^^^^^^^^^^^^^
@@ -42,6 +45,15 @@ Hints
 
 Set ``GDAL_DIR`` or ``GDAL_ROOT`` in the environment to specify the
 GDAL installation prefix.
+
+The following variables may be set to modify the search strategy:
+
+``FindGDAL_SKIP_GDAL_CONFIG``
+  If set, ``gdal-config`` will not be used. This can be useful if there are
+  GDAL libraries built with autotools (which provide the tool) and CMake (which
+  do not) in the same environment.
+``GDAL_ADDITIONAL_LIBRARY_VERSIONS``
+  Extra versions of library names to search for.
 #]=======================================================================]
 
 # $GDALDIR is an environment variable that would
@@ -65,12 +77,14 @@ find_path(GDAL_INCLUDE_DIR gdal.h
     ENV GDAL_DIR
     ENV GDAL_ROOT
   PATH_SUFFIXES
-     include/gdal
-     include/GDAL
-     include
+    include/gdal
+    include/GDAL
+    include
+  DOC "Path to the GDAL include directory"
 )
+mark_as_advanced(GDAL_INCLUDE_DIR)
 
-if(UNIX)
+if(UNIX AND NOT FindGDAL_SKIP_GDAL_CONFIG)
     # Use gdal-config to obtain the library version (this should hopefully
     # allow us to -lgdal1.x.y where x.y are correct version)
     # For some reason, libgdal development packages do not contain
@@ -80,10 +94,12 @@ if(UNIX)
           ENV GDAL_DIR
           ENV GDAL_ROOT
         PATH_SUFFIXES bin
+        DOC "Path to the gdal-config tool"
     )
+    mark_as_advanced(GDAL_CONFIG)
 
     if(GDAL_CONFIG)
-        exec_program(${GDAL_CONFIG} ARGS --libs OUTPUT_VARIABLE GDAL_CONFIG_LIBS)
+        execute_process(COMMAND ${GDAL_CONFIG} --libs OUTPUT_VARIABLE GDAL_CONFIG_LIBS)
 
         if(GDAL_CONFIG_LIBS)
             # treat the output as a command line and split it up
@@ -131,14 +147,30 @@ if(UNIX)
     endif()
 endif()
 
+# GDAL name its library when built with CMake as `gdal${major}${minor}`.
+set(_gdal_versions
+    ${GDAL_ADDITIONAL_LIBRARY_VERSIONS} 3.0 2.4 2.3 2.2 2.1 2.0 1.11 1.10 1.9 1.8 1.7 1.6 1.5 1.4 1.3 1.2)
+
+set(_gdal_libnames)
+foreach (_gdal_version IN LISTS _gdal_versions)
+    string(REPLACE "." "" _gdal_version "${_gdal_version}")
+    list(APPEND _gdal_libnames "gdal${_gdal_version}" "GDAL${_gdal_version}")
+endforeach ()
+unset(_gdal_version)
+unset(_gdal_versions)
+
 find_library(GDAL_LIBRARY
-  NAMES ${_gdal_lib} gdal gdal_i gdal1.5.0 gdal1.4.0 gdal1.3.2 GDAL
+  NAMES ${_gdal_lib} ${_gdal_libnames} gdal gdal_i gdal1.5.0 gdal1.4.0 gdal1.3.2 GDAL
   HINTS
      ENV GDAL_DIR
      ENV GDAL_ROOT
      ${_gdal_libpath}
   PATH_SUFFIXES lib
+  DOC "Path to the GDAL library"
 )
+mark_as_advanced(GDAL_LIBRARY)
+unset(_gdal_libnames)
+unset(_gdal_lib)
 
 if (EXISTS "${GDAL_INCLUDE_DIR}/gdal_version.h")
     file(STRINGS "${GDAL_INCLUDE_DIR}/gdal_version.h" _gdal_version
@@ -154,12 +186,14 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(GDAL
     VERSION_VAR GDAL_VERSION
     REQUIRED_VARS GDAL_LIBRARY GDAL_INCLUDE_DIR)
 
-if (GDAL_FOUND AND NOT TARGET GDAL::GDAL)
-    add_library(GDAL::GDAL UNKNOWN IMPORTED)
-    set_target_properties(GDAL::GDAL PROPERTIES
-        IMPORTED_LOCATION "${GDAL_LIBRARY}"
-        INTERFACE_INCLUDE_DIRECTORIES "${GDAL_INCLUDE_DIR}")
-endif ()
+if (GDAL_FOUND)
+    set(GDAL_LIBRARIES ${GDAL_LIBRARY})
+    set(GDAL_INCLUDE_DIRS ${GDAL_INCLUDE_DIR})
 
-set(GDAL_LIBRARIES ${GDAL_LIBRARY})
-set(GDAL_INCLUDE_DIRS ${GDAL_INCLUDE_DIR})
+    if (NOT TARGET GDAL::GDAL)
+        add_library(GDAL::GDAL UNKNOWN IMPORTED)
+        set_target_properties(GDAL::GDAL PROPERTIES
+            IMPORTED_LOCATION "${GDAL_LIBRARY}"
+            INTERFACE_INCLUDE_DIRECTORIES "${GDAL_INCLUDE_DIR}")
+    endif ()
+endif ()
index 187b6a8..b9ebe08 100644 (file)
@@ -21,6 +21,8 @@ The following variables may be set to influence this module's behavior:
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.1
+
 This module defines the following :ref:`Imported Targets <Imported Targets>`:
 
 
@@ -55,6 +57,9 @@ This module defines the following variables:
 ``GLEW_VERSION_MICRO``
   GLEW micro version
 
+.. versionadded:: 3.7
+  Debug and Release variants are found separately.
+
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
index 15561d6..2770c60 100644 (file)
@@ -10,6 +10,8 @@ Find OpenGL Utility Toolkit (GLUT) library and include files.
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.1
+
 This module defines the :prop_tgt:`IMPORTED` targets:
 
 ``GLUT::GLUT``
@@ -33,6 +35,9 @@ Also defined, but not for general use are:
   GLUT_glut_LIBRARY = the full path to the glut library.
   GLUT_Xmu_LIBRARY  = the full path to the Xmu library.
   GLUT_Xi_LIBRARY   = the full path to the Xi Library.
+
+.. versionadded:: 3.13
+  Debug and Release variants are found separately.
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
index 62f1614..00bfc29 100644 (file)
@@ -16,6 +16,23 @@ module.  See example below.
 * ``glade``
 * ``glademm``
 
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` targets (subject to
+component selection):
+
+``GTK2::atk``, ``GTK2::atkmm``, ``GTK2::cairo``, ``GTK2::cairomm``,
+``GTK2::gdk_pixbuf``, ``GTK2::gdk``, ``GTK2::gdkmm``, ``GTK2::gio``,
+``GTK2::giomm``, ``GTK2::glade``, ``GTK2::glademm``, ``GTK2::glib``,
+``GTK2::glibmm``, ``GTK2::gmodule``, ``GTK2::gobject``, ``GTK2::gthread``,
+``GTK2::gtk``, ``GTK2::gtkmm``, ``GTK2::harfbuzz``, ``GTK2::pango``,
+``GTK2::pangocairo``, ``GTK2::pangoft2``, ``GTK2::pangomm``,
+``GTK2::pangoxft``, ``GTK2::sigc``.
+
+.. versionadded:: 3.16.7
+  Added the ``GTK2::harfbuzz`` target.
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
@@ -28,7 +45,8 @@ The following variables will be defined for your use
 ``GTK2_LIBRARIES``
   All libraries
 ``GTK2_TARGETS``
-  All imported targets
+  .. versionadded:: 3.5
+    All imported targets
 ``GTK2_DEFINITIONS``
   Additional compiler flags
 ``GTK2_VERSION``
@@ -40,6 +58,10 @@ The following variables will be defined for your use
 ``GTK2_PATCH_VERSION``
   The patch version of GTK2
 
+.. versionadded:: 3.5
+  When ``GTK2_USE_IMPORTED_TARGETS`` is set to ``TRUE``, ``GTK2_LIBRARIES``
+  will list imported targets instead of library paths.
+
 Input Variables
 ^^^^^^^^^^^^^^^
 
@@ -783,6 +805,7 @@ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
         _GTK2_ADD_TARGET      (GIOMM GTK2_DEPENDS gio glibmm gobject sigc++ glib)
 
         _GTK2_FIND_INCLUDE_DIR(ATKMM atkmm.h)
+        _GTK2_FIND_INCLUDE_DIR(ATKMMCONFIG atkmmconfig.h)
         _GTK2_FIND_LIBRARY    (ATKMM atkmm true true)
         _GTK2_ADD_TARGET      (ATKMM GTK2_DEPENDS atk glibmm gobject sigc++ glib)
 
index 53cab1a..8e22f79 100644 (file)
@@ -7,10 +7,24 @@ FindGTest
 
 Locate the Google C++ Testing Framework.
 
+.. versionadded:: 3.20
+  Upstream ``GTestConfig.cmake`` is used if possible.
+
 Imported targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :prop_tgt:`IMPORTED` targets:
+.. versionadded:: 3.20
+  This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``GTest::gtest``
+  The Google Test ``gtest`` library, if found; adds Thread::Thread
+  automatically
+``GTest::gtest_main``
+  The Google Test ``gtest_main`` library, if found
+
+.. deprecated:: 3.20
+  For backwards compatibility, this module defines additionally the
+  following deprecated :prop_tgt:`IMPORTED` targets (available since 3.5):
 
 ``GTest::GTest``
   The Google Test ``gtest`` library, if found; adds Thread::Thread
@@ -24,7 +38,7 @@ Result variables
 
 This module will set the following variables in your project:
 
-``GTEST_FOUND``
+``GTest_FOUND``
   Found the Google Testing framework
 ``GTEST_INCLUDE_DIRS``
   the directory containing the Google Test headers
@@ -62,7 +76,7 @@ Example usage
     find_package(GTest REQUIRED)
 
     add_executable(foo foo.cc)
-    target_link_libraries(foo GTest::GTest GTest::Main)
+    target_link_libraries(foo GTest::gtest GTest::gtest_main)
 
     add_test(AllTestsInFoo foo)
 
@@ -72,6 +86,10 @@ Deeper integration with CTest
 
 See :module:`GoogleTest` for information on the :command:`gtest_add_tests`
 and :command:`gtest_discover_tests` commands.
+
+.. versionchanged:: 3.9
+  Previous CMake versions defined :command:`gtest_add_tests` macro in this
+  module.
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/GoogleTest.cmake)
@@ -146,8 +164,41 @@ function(__gtest_import_library _target _var _config)
     endif()
 endfunction()
 
+function(__gtest_define_backwards_compatible_library_targets)
+    set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} PARENT_SCOPE)
+
+    # Add targets mapping the same library names as defined in
+    # older versions of CMake's FindGTest
+    if(NOT TARGET GTest::GTest)
+        add_library(GTest::GTest INTERFACE IMPORTED)
+        target_link_libraries(GTest::GTest INTERFACE GTest::gtest)
+    endif()
+    if(NOT TARGET GTest::Main)
+        add_library(GTest::Main INTERFACE IMPORTED)
+        target_link_libraries(GTest::Main INTERFACE GTest::gtest_main)
+    endif()
+endfunction()
+
 #
 
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+# first specifically look for the CMake version of GTest
+find_package(GTest QUIET NO_MODULE)
+
+# if we found the GTest cmake package then we are done, and
+# can print what we found and return.
+if(GTest_FOUND)
+    FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest HANDLE_COMPONENTS CONFIG_MODE)
+
+    set(GTEST_LIBRARIES      GTest::gtest)
+    set(GTEST_MAIN_LIBRARIES GTest::gtest_main)
+
+    __gtest_define_backwards_compatible_library_targets()
+
+    return()
+endif()
+
 if(NOT DEFINED GTEST_MSVC_SEARCH)
     set(GTEST_MSVC_SEARCH MD)
 endif()
@@ -201,54 +252,43 @@ else()
     __gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind)
 endif()
 
-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY)
 
-if(GTEST_FOUND)
+if(GTest_FOUND)
     set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR})
     __gtest_append_debugs(GTEST_LIBRARIES      GTEST_LIBRARY)
     __gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY)
-    set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
 
     find_package(Threads QUIET)
 
-    if(NOT TARGET GTest::GTest)
+    if(NOT TARGET GTest::gtest)
         __gtest_determine_library_type(GTEST_LIBRARY)
-        add_library(GTest::GTest ${GTEST_LIBRARY_TYPE} IMPORTED)
+        add_library(GTest::gtest ${GTEST_LIBRARY_TYPE} IMPORTED)
         if(TARGET Threads::Threads)
-            set_target_properties(GTest::GTest PROPERTIES
+            set_target_properties(GTest::gtest PROPERTIES
                 INTERFACE_LINK_LIBRARIES Threads::Threads)
         endif()
         if(GTEST_LIBRARY_TYPE STREQUAL "SHARED")
-            set_target_properties(GTest::GTest PROPERTIES
+            set_target_properties(GTest::gtest PROPERTIES
                 INTERFACE_COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
         endif()
         if(GTEST_INCLUDE_DIRS)
-            set_target_properties(GTest::GTest PROPERTIES
+            set_target_properties(GTest::gtest PROPERTIES
                 INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}")
         endif()
-        __gtest_import_library(GTest::GTest GTEST_LIBRARY "")
-        __gtest_import_library(GTest::GTest GTEST_LIBRARY "RELEASE")
-        __gtest_import_library(GTest::GTest GTEST_LIBRARY "DEBUG")
+        __gtest_import_library(GTest::gtest GTEST_LIBRARY "")
+        __gtest_import_library(GTest::gtest GTEST_LIBRARY "RELEASE")
+        __gtest_import_library(GTest::gtest GTEST_LIBRARY "DEBUG")
     endif()
-    if(NOT TARGET GTest::Main)
+    if(NOT TARGET GTest::gtest_main)
         __gtest_determine_library_type(GTEST_MAIN_LIBRARY)
-        add_library(GTest::Main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED)
-        set_target_properties(GTest::Main PROPERTIES
-            INTERFACE_LINK_LIBRARIES "GTest::GTest")
-        __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "")
-        __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "RELEASE")
-        __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "DEBUG")
+        add_library(GTest::gtest_main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED)
+        set_target_properties(GTest::gtest_main PROPERTIES
+            INTERFACE_LINK_LIBRARIES "GTest::gtest")
+        __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "")
+        __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "RELEASE")
+        __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "DEBUG")
     endif()
 
-    # Add targets mapping the same library names as defined in
-    # GTest's CMake package config.
-    if(NOT TARGET GTest::gtest)
-        add_library(GTest::gtest INTERFACE IMPORTED)
-        target_link_libraries(GTest::gtest INTERFACE GTest::GTest)
-    endif()
-    if(NOT TARGET GTest::gtest_main)
-        add_library(GTest::gtest_main INTERFACE IMPORTED)
-        target_link_libraries(GTest::gtest_main INTERFACE GTest::Main)
-    endif()
+    __gtest_define_backwards_compatible_library_targets()
 endif()
index 213ad13..252f2ae 100644 (file)
@@ -54,7 +54,7 @@ PO_FILES <po1> <po2> ...  )
      If ALL is specified, the po files are processed when building the all traget.
      It creates a custom target "pofiles".
 
-.. note::
+.. versionadded:: 3.2
   If you wish to use the Gettext library (libintl), use :module:`FindIntl`.
 #]=======================================================================]
 
index 3491cdc..99850b4 100644 (file)
@@ -5,12 +5,6 @@
 FindGit
 -------
 
-The module defines the following ``IMPORTED`` targets (when
-:prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
-
-``Git::Git``
-  Executable of the Git command-line client.
-
 The module defines the following variables:
 
 ``GIT_EXECUTABLE``
@@ -20,6 +14,13 @@ The module defines the following variables:
 ``GIT_VERSION_STRING``
   The version of Git found.
 
+.. versionadded:: 3.14
+  The module defines the following ``IMPORTED`` targets (when
+  :prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
+
+``Git::Git``
+  Executable of the Git command-line client.
+
 Example usage:
 
 .. code-block:: cmake
@@ -76,20 +77,51 @@ unset(git_names)
 unset(_git_sourcetree_path)
 
 if(GIT_EXECUTABLE)
-  execute_process(COMMAND ${GIT_EXECUTABLE} --version
-                  OUTPUT_VARIABLE git_version
-                  ERROR_QUIET
-                  OUTPUT_STRIP_TRAILING_WHITESPACE)
-  if (git_version MATCHES "^git version [0-9]")
-    string(REPLACE "git version " "" GIT_VERSION_STRING "${git_version}")
+  # Avoid querying the version if we've already done that this run. For
+  # projects that use things like ExternalProject or FetchContent heavily,
+  # this saving can be measurable on some platforms.
+  #
+  # This is an internal property, projects must not try to use it.
+  # We don't want this stored in the cache because it might still change
+  # between CMake runs, but it shouldn't change during a run for a given
+  # git executable location.
+  set(__doGitVersionCheck TRUE)
+  get_property(__gitVersionProp GLOBAL
+    PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
+  )
+  if(__gitVersionProp)
+    list(GET __gitVersionProp 0 __gitExe)
+    list(GET __gitVersionProp 1 __gitVersion)
+    if(__gitExe STREQUAL GIT_EXECUTABLE AND NOT __gitVersion STREQUAL "")
+      set(GIT_VERSION_STRING "${__gitVersion}")
+      set(__doGitVersionCheck FALSE)
+    endif()
+    unset(__gitExe)
+    unset(__gitVersion)
+  endif()
+  unset(__gitVersionProp)
+
+  if(__doGitVersionCheck)
+    execute_process(COMMAND ${GIT_EXECUTABLE} --version
+                    OUTPUT_VARIABLE git_version
+                    ERROR_QUIET
+                    OUTPUT_STRIP_TRAILING_WHITESPACE)
+    if (git_version MATCHES "^git version [0-9]")
+      string(REPLACE "git version " "" GIT_VERSION_STRING "${git_version}")
+      set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
+        "${GIT_EXECUTABLE};${GIT_VERSION_STRING}"
+      )
+    endif()
+    unset(git_version)
   endif()
-  unset(git_version)
+  unset(__doGitVersionCheck)
 
   get_property(_findgit_role GLOBAL PROPERTY CMAKE_ROLE)
   if(_findgit_role STREQUAL "PROJECT" AND NOT TARGET Git::Git)
     add_executable(Git::Git IMPORTED)
     set_property(TARGET Git::Git PROPERTY IMPORTED_LOCATION "${GIT_EXECUTABLE}")
   endif()
+  unset(_findgit_role)
 endif()
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
index 819f000..782a72b 100644 (file)
@@ -10,6 +10,8 @@ Find the GNU Transport Layer Security library (gnutls)
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.16
+
 This module defines :prop_tgt:`IMPORTED` target ``GnuTLS::GnuTLS``, if
 gnutls has been found.
 
index 38388d9..16bf279 100644 (file)
@@ -32,6 +32,9 @@ static link to a dynamic link for ``HDF5`` and all of it's dependencies.
 To use this feature, make sure that the ``HDF5_USE_STATIC_LIBRARIES``
 variable is set before the call to find_package.
 
+.. versionadded:: 3.10
+  Support for ``HDF5_USE_STATIC_LIBRARIES`` on Windows.
+
 Both the serial and parallel ``HDF5`` wrappers are considered and the first
 directory to contain either one will be used.  In the event that both appear
 in the same directory the serial version is preferentially selected. This
@@ -51,7 +54,8 @@ This module will set the following variables in your project:
 ``HDF5_FOUND``
   HDF5 was found on the system
 ``HDF5_VERSION``
-  HDF5 library version
+  .. versionadded:: 3.3
+    HDF5 library version
 ``HDF5_INCLUDE_DIRS``
   Location of the HDF5 header files
 ``HDF5_DEFINITIONS``
@@ -112,15 +116,22 @@ also be defined.  With all components enabled, the following variables will be d
 
 With all components enabled, the following targets will be defined:
 
-::
-
-  ``hdf5::hdf5``
-  ``hdf5::hdf5_hl_cpp``
-  ``hdf5::hdf5_fortran``
-  ``hdf5::hdf5_hl``
-  ``hdf5::hdf5_hl_cpp``
-  ``hdf5::hdf5_hl_fortran``
-  ``hdf5::h5diff``
+``HDF5::HDF5``
+  All detected ``HDF5_LIBRARIES``.
+``hdf5::hdf5``
+  C library.
+``hdf5::hdf5_cpp``
+  C++ library.
+``hdf5::hdf5_fortran``
+  Fortran library.
+``hdf5::hdf5_hl``
+  High-level C library.
+``hdf5::hdf5_hl_cpp``
+  High-level C++ library.
+``hdf5::hdf5_hl_fortran``
+  High-level Fortran library.
+``hdf5::h5diff``
+  ``h5diff`` executable.
 
 Hints
 ^^^^^
@@ -128,12 +139,18 @@ Hints
 The following variables can be set to guide the search for HDF5 libraries and includes:
 
 ``HDF5_PREFER_PARALLEL``
+  .. versionadded:: 3.4
+
   set ``true`` to prefer parallel HDF5 (by default, serial is preferred)
 
 ``HDF5_FIND_DEBUG``
+  .. versionadded:: 3.9
+
   Set ``true`` to get extra debugging output.
 
 ``HDF5_NO_FIND_PACKAGE_CONFIG_FILE``
+  .. versionadded:: 3.8
+
   Set ``true`` to skip trying to find ``hdf5-config.cmake``.
 #]=======================================================================]
 
@@ -196,22 +213,6 @@ else()
   set(HDF5_Fortran_COMPILER_NAMES h5fc h5pfc)
 endif()
 
-# We may have picked up some duplicates in various lists during the above
-# process for the language bindings (both the C and C++ bindings depend on
-# libz for example).  Remove the duplicates. It appears that the default
-# CMake behavior is to remove duplicates from the end of a list. However,
-# for link lines, this is incorrect since unresolved symbols are searched
-# for down the link line. Therefore, we reverse the list, remove the
-# duplicates, and then reverse it again to get the duplicates removed from
-# the beginning.
-macro(_HDF5_remove_duplicates_from_beginning _list_name)
-  if(${_list_name})
-    list(REVERSE ${_list_name})
-    list(REMOVE_DUPLICATES ${_list_name})
-    list(REVERSE ${_list_name})
-  endif()
-endmacro()
-
 # Test first if the current compilers automatically wrap HDF5
 function(_HDF5_test_regular_compiler_C success version is_parallel)
   set(scratch_directory
@@ -716,10 +717,8 @@ if(NOT HDF5_FOUND)
           endif()
 
           set(HDF5_${_lang}_FOUND TRUE)
-          _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_DEFINITIONS)
-          _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_INCLUDE_DIRS)
-          _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_LIBRARIES)
-          _HDF5_remove_duplicates_from_beginning(HDF5_${_lang}_HL_LIBRARIES)
+          list(REMOVE_DUPLICATES HDF5_${_lang}_DEFINITIONS)
+          list(REMOVE_DUPLICATES HDF5_${_lang}_INCLUDE_DIRS)
         else()
           set(_HDF5_NEED_TO_SEARCH TRUE)
         endif()
@@ -772,10 +771,8 @@ elseif(NOT HDF5_FOUND AND NOT _HDF5_NEED_TO_SEARCH)
       endif()
     endif()
   endforeach()
-  _HDF5_remove_duplicates_from_beginning(HDF5_DEFINITIONS)
-  _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS)
-  _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES)
-  _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES)
+  list(REMOVE_DUPLICATES HDF5_DEFINITIONS)
+  list(REMOVE_DUPLICATES HDF5_INCLUDE_DIRS)
   set(HDF5_FOUND TRUE)
   set(HDF5_REQUIRED_VARS HDF5_LIBRARIES)
   if(HDF5_FIND_HL)
@@ -915,10 +912,8 @@ if( NOT HDF5_FOUND )
         set(HDF5_HL_FOUND TRUE)
     endif()
 
-    _HDF5_remove_duplicates_from_beginning(HDF5_DEFINITIONS)
-    _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS)
-    _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES)
-    _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES)
+    list(REMOVE_DUPLICATES HDF5_DEFINITIONS)
+    list(REMOVE_DUPLICATES HDF5_INCLUDE_DIRS)
 
     # If the HDF5 include directory was found, open H5pubconf.h to determine if
     # HDF5 was compiled with parallel IO support
@@ -1139,6 +1134,21 @@ if (HDF5_FIND_DEBUG)
     message(STATUS "HDF5_${_lang}_HL_LIBRARY: ${HDF5_${_lang}_HL_LIBRARY}")
     message(STATUS "HDF5_${_lang}_HL_LIBRARIES: ${HDF5_${_lang}_HL_LIBRARIES}")
   endforeach()
+  message(STATUS "Defined targets (if any):")
+  foreach(_lang IN  ITEMS "" "_cpp" "_fortran")
+    foreach(_hl IN  ITEMS "" "_hl")
+      foreach(_prefix IN ITEMS "hdf5::" "")
+        foreach(_suffix IN ITEMS "-static" "-shared" "")
+          set (_target ${_prefix}hdf5${_hl}${_lang}${_suffix})
+          if (TARGET  ${_target})
+            message(STATUS "... ${_target}")
+          else()
+            #message(STATUS "... ${_target} does not exist")
+          endif()
+        endforeach()
+      endforeach()
+    endforeach()
+  endforeach()
 endif()
 unset(_lang)
 unset(_HDF5_NEED_TO_SEARCH)
index 1358363..e9f2c82 100644 (file)
@@ -15,7 +15,8 @@ The module defines the following variables:
    HG_FOUND - true if the command line client was found
    HG_VERSION_STRING - the version of mercurial found
 
-If the command line client executable is found the following macro is defined:
+.. versionadded:: 3.1
+  If the command line client executable is found the following macro is defined:
 
 ::
 
index c8b3e1f..2bb49ad 100644 (file)
@@ -18,6 +18,9 @@ Note that on Windows ``data`` is named ``dt`` and ``i18n`` is named
 ``in``; any of the names may be used, and the appropriate
 platform-specific library name will be automatically selected.
 
+.. versionadded:: 3.11
+  Added support for static libraries on Windows.
+
 This module reports information about the ICU installation in
 several variables.  General variables::
 
@@ -31,7 +34,7 @@ Imported targets::
   ICU::<C>
 
 Where ``<C>`` is the name of an ICU component, for example
-``ICU::i18n``.
+``ICU::i18n``; ``<C>`` is lower-case.
 
 ICU programs are reported in::
 
@@ -54,16 +57,14 @@ ICU programs are reported in::
 
 ICU component libraries are reported in::
 
-  ICU_<C>_FOUND - ON if component was found
-  ICU_<C>_LIBRARIES - libraries for component
+  ICU_<C>_FOUND - ON if component was found; ``<C>`` is upper-case.
+  ICU_<C>_LIBRARIES - libraries for component; ``<C>`` is upper-case.
 
 ICU datafiles are reported in::
 
   ICU_MAKEFILE_INC - Makefile.inc
   ICU_PKGDATA_INC - pkgdata.inc
 
-Note that ``<C>`` is the uppercased name of the component.
-
 This module reads hints about search results from::
 
   ICU_ROOT - the root of the ICU installation
@@ -73,9 +74,9 @@ ICU_ROOT variable takes precedence.
 
 The following cache variables may also be set::
 
-  ICU_<P>_EXECUTABLE - the path to executable <P>
+  ICU_<P>_EXECUTABLE - the path to executable <P>; ``<P>`` is upper-case.
   ICU_INCLUDE_DIR - the directory containing the ICU headers
-  ICU_<C>_LIBRARY - the library for component <C>
+  ICU_<C>_LIBRARY - the library for component <C>; ``<C>`` is upper-case.
 
 .. note::
 
@@ -188,7 +189,8 @@ function(_ICU_FIND)
     set(component_cache "ICU_${component_upcase}_LIBRARY")
     set(component_cache_release "${component_cache}_RELEASE")
     set(component_cache_debug "${component_cache}_DEBUG")
-    set(component_found "${component_upcase}_FOUND")
+    set(component_found "ICU_${component_upcase}_FOUND")
+    set(component_found_compat "${component_upcase}_FOUND")
     set(component_libnames "icu${component}")
     set(component_debug_libnames "icu${component}d")
 
@@ -250,12 +252,15 @@ function(_ICU_FIND)
     mark_as_advanced("${component_cache_release}" "${component_cache_debug}")
     if(${component_cache})
       set("${component_found}" ON)
+      set("${component_found_compat}" ON)
       list(APPEND ICU_LIBRARY "${${component_cache}}")
     endif()
     mark_as_advanced("${component_found}")
+    mark_as_advanced("${component_found_compat}")
     set("${component_cache}" "${${component_cache}}" PARENT_SCOPE)
     set("${component_found}" "${${component_found}}" PARENT_SCOPE)
-    if(${component_found})
+    set("${component_found_compat}" "${${component_found_compat}}" PARENT_SCOPE)
+    if(component_found OR component_found_compat)
       if (ICU_FIND_REQUIRED_${component})
         list(APPEND ICU_LIBS_FOUND "${component} (required)")
       else()
@@ -346,7 +351,7 @@ if(ICU_FOUND)
     set(_ICU_component_cache_release "ICU_${_ICU_component_upcase}_LIBRARY_RELEASE")
     set(_ICU_component_cache_debug "ICU_${_ICU_component_upcase}_LIBRARY_DEBUG")
     set(_ICU_component_lib "ICU_${_ICU_component_upcase}_LIBRARIES")
-    set(_ICU_component_found "${_ICU_component_upcase}_FOUND")
+    set(_ICU_component_found "ICU_${_ICU_component_upcase}_FOUND")
     set(_ICU_imported_target "ICU::${_ICU_component}")
     if(${_ICU_component_found})
       set("${_ICU_component_lib}" "${${_ICU_component_cache}}")
@@ -400,7 +405,7 @@ if(ICU_DEBUG)
   foreach(program IN LISTS icu_programs)
     string(TOUPPER "${program}" program_upcase)
     set(program_lib "ICU_${program_upcase}_EXECUTABLE")
-    message(STATUS "${program} program: ${${program_lib}}")
+    message(STATUS "${program} program: ${program_lib}=${${program_lib}}")
     unset(program_upcase)
     unset(program_lib)
   endforeach()
@@ -409,7 +414,7 @@ if(ICU_DEBUG)
     string(TOUPPER "${data}" data_upcase)
     string(REPLACE "." "_" data_upcase "${data_upcase}")
     set(data_lib "ICU_${data_upcase}")
-    message(STATUS "${data} data: ${${data_lib}}")
+    message(STATUS "${data} data: ${data_lib}=${${data_lib}}")
     unset(data_upcase)
     unset(data_lib)
   endforeach()
@@ -417,12 +422,15 @@ if(ICU_DEBUG)
   foreach(component IN LISTS ICU_FIND_COMPONENTS)
     string(TOUPPER "${component}" component_upcase)
     set(component_lib "ICU_${component_upcase}_LIBRARIES")
-    set(component_found "${component_upcase}_FOUND")
-    message(STATUS "${component} library found: ${${component_found}}")
-    message(STATUS "${component} library: ${${component_lib}}")
+    set(component_found "ICU_${component_upcase}_FOUND")
+    set(component_found_compat "${component_upcase}_FOUND")
+    message(STATUS "${component} library found: ${component_found}=${${component_found}}")
+    message(STATUS "${component} library found (compat name): ${component_found_compat}=${${component_found_compat}}")
+    message(STATUS "${component} library: ${component_lib}=${${component_lib}}")
     unset(component_upcase)
     unset(component_lib)
     unset(component_found)
+    unset(component_found_compat)
   endforeach()
   message(STATUS "----------------")
 endif()
index 0f821e8..543e10c 100644 (file)
@@ -23,6 +23,15 @@ Ice 3.7 and later also include C++11-specific components:
 
 Note that the set of supported components is Ice version-specific.
 
+.. versionadded:: 3.4
+  Imported targets for components and most ``EXECUTABLE`` variables.
+
+.. versionadded:: 3.7
+  Debug and Release variants are found separately.
+
+.. versionadded:: 3.10
+  Ice 3.7 support, including new components, programs and the Nuget package.
+
 This module reports information about the Ice installation in
 several variables.  General variables::
 
@@ -56,6 +65,9 @@ Ice slice programs are reported in::
   Ice_SLICE2PY_EXECUTABLE - path to slice2py executable
   Ice_SLICE2RB_EXECUTABLE - path to slice2rb executable
 
+.. versionadded:: 3.14
+  Variables for ``slice2confluence`` and ``slice2matlab``.
+
 Ice programs are reported in::
 
   Ice_GLACIER2ROUTER_EXECUTABLE - path to glacier2router executable
index 8bf5123..d7de0dd 100644 (file)
@@ -7,6 +7,9 @@ FindImageMagick
 
 Find ImageMagick binary suite.
 
+.. versionadded:: 3.9
+  Added support for ImageMagick 7.
+
 This module will search for a set of ImageMagick tools specified as
 components in the :command:`find_package` call.  Typical components include,
 but are not limited to (future versions of ImageMagick might have
index 1a09a60..686c818 100644 (file)
@@ -16,10 +16,21 @@ installation in several variables.  General variables::
   Intl_INCLUDE_DIRS - the directory containing the libintl headers
   Intl_LIBRARIES - libintl libraries to be linked
 
+.. versionadded:: 3.20
+  This module defines :prop_tgt:`IMPORTED` target ``Intl::Intl``.
+
 The following cache variables may also be set::
 
   Intl_INCLUDE_DIR - the directory containing the libintl headers
   Intl_LIBRARY - the libintl library (if any)
+  Intl_HAVE_GETTEXT_BUILTIN - check if gettext is in the C library
+  Intl_HAVE_DCGETTEXT_BUILTIN - check if dcgettext is in the C library
+  Intl_IS_BUILTIN - whether intl is a part of the C library determined
+      from the result of Intl_HAVE_GETTEXT_BUILTIN and Intl_HAVE_DCGETTEXT_BUILTIN
+
+.. versionadded:: 3.20
+  Added the ``Intl_HAVE_GETTEXT_BUILTIN``, ``Intl_HAVE_DCGETTEXT_BUILTIN`` and
+  ``Intl_IS_BUILTIN`` variables.
 
 .. note::
   On some platforms, such as Linux with GNU libc, the gettext
@@ -35,6 +46,22 @@ The following cache variables may also be set::
 
 # Written by Roger Leigh <rleigh@codelibre.net>
 
+include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake)
+
+# Check if we have libintl is a part of libc
+cmake_push_check_state(RESET)
+set(CMAKE_REQUIRED_QUIET TRUE)
+check_symbol_exists(gettext libintl.h Intl_HAVE_GETTEXT_BUILTIN)
+check_symbol_exists(dcgettext libintl.h Intl_HAVE_DCGETTEXT_BUILTIN) # redundant check
+cmake_pop_check_state()
+
+if(Intl_HAVE_GETTEXT_BUILTIN AND Intl_HAVE_DCGETTEXT_BUILTIN)
+  set(Intl_IS_BUILTIN TRUE)
+else()
+  set(Intl_IS_BUILTIN FALSE)
+endif()
+
 # Find include directory
 find_path(Intl_INCLUDE_DIR
           NAMES "libintl.h"
@@ -42,21 +69,28 @@ find_path(Intl_INCLUDE_DIR
 mark_as_advanced(Intl_INCLUDE_DIR)
 
 # Find all Intl libraries
-find_library(Intl_LIBRARY "intl" NAMES_PER_DIR
-  DOC "libintl libraries (if not in the C library)")
-mark_as_advanced(Intl_LIBRARY)
+set(Intl_REQUIRED_VARS)
+if(NOT Intl_IS_BUILTIN)
+  find_library(Intl_LIBRARY "intl" "libintl" NAMES_PER_DIR
+    DOC "libintl libraries (if not in the C library)")
+  mark_as_advanced(Intl_LIBRARY)
+  list(APPEND Intl_REQUIRED_VARS Intl_LIBRARY)
+endif()
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(Intl
                                   FOUND_VAR Intl_FOUND
-                                  REQUIRED_VARS Intl_INCLUDE_DIR
+                                  REQUIRED_VARS Intl_INCLUDE_DIR ${Intl_REQUIRED_VARS}
                                   FAIL_MESSAGE "Failed to find Gettext libintl")
+unset(Intl_REQUIRED_VARS)
 
 if(Intl_FOUND)
   set(Intl_INCLUDE_DIRS "${Intl_INCLUDE_DIR}")
-  if(Intl_LIBRARY)
-    set(Intl_LIBRARIES "${Intl_LIBRARY}")
-  else()
-    unset(Intl_LIBRARIES)
+  set(Intl_LIBRARIES "${Intl_LIBRARY}")
+  if(NOT TARGET Intl::Intl)
+    add_library(Intl::Intl INTERFACE IMPORTED)
+    set_target_properties(Intl::Intl PROPERTIES
+      INTERFACE_INCLUDE_DIRECTORIES "${Intl_INCLUDE_DIRS}"
+      INTERFACE_LINK_LIBRARIES "${Intl_LIBRARIES}")
   endif()
 endif()
index 632fc9a..add2486 100644 (file)
@@ -10,6 +10,8 @@ Find the Joint Photographic Experts Group (JPEG) library (``libjpeg``)
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.12
+
 This module defines the following :prop_tgt:`IMPORTED` targets:
 
 ``JPEG::JPEG``
@@ -27,7 +29,8 @@ This module will set the following variables in your project:
 ``JPEG_LIBRARIES``
   the libraries needed to use JPEG.
 ``JPEG_VERSION``
-  the version of the JPEG library found
+  .. versionadded:: 3.12
+    the version of the JPEG library found
 
 Cache variables
 ^^^^^^^^^^^^^^^
@@ -41,6 +44,9 @@ The following cache variables may also be set:
 ``JPEG_LIBRARY_DEBUG``
   where to find the JPEG library (debug).
 
+.. versionadded:: 3.12
+  Debug and Release variand are found separately.
+
 Obsolete variables
 ^^^^^^^^^^^^^^^^^^
 
@@ -52,7 +58,7 @@ Obsolete variables
 
 find_path(JPEG_INCLUDE_DIR jpeglib.h)
 
-set(jpeg_names ${JPEG_NAMES} jpeg jpeg-static libjpeg libjpeg-static)
+set(jpeg_names ${JPEG_NAMES} jpeg jpeg-static libjpeg libjpeg-static turbojpeg turbojpeg-static)
 foreach(name ${jpeg_names})
   list(APPEND jpeg_names_debug "${name}d")
 endforeach()
index 9db740b..4f0e0fe 100644 (file)
@@ -13,6 +13,9 @@ to specify a Java installation prefix explicitly.
 
 See also the :module:`FindJNI` module to find Java Native Interface (JNI).
 
+.. versionadded:: 3.10
+  Added support for Java 9+ version parsing.
+
 Specify one or more of the following components as you call this find module. See example below.
 
 ::
@@ -41,7 +44,9 @@ This module sets the following result variables:
   Java_VERSION_TWEAK        = The tweak version of the package found (after '_')
   Java_VERSION              = This is set to: $major[.$minor[.$patch[.$tweak]]]
 
-
+.. versionadded:: 3.4
+  Added the ``Java_IDLJ_EXECUTABLE`` and ``Java_JARSIGNER_EXECUTABLE``
+  variables.
 
 The minimum required version of Java can be specified using the
 :command:`find_package` syntax, e.g.
index 4b71cee..45e4be7 100644 (file)
@@ -43,14 +43,46 @@ The following variables may be set to influence this module's behavior:
   * ``Arm_mp``
   * ``Arm_ilp64``
   * ``Arm_ilp64_mp``
+  * ``EML``
+  * ``EML_mt``
   * ``Generic``
 
+  .. versionadded:: 3.6
+    ``OpenBLAS`` support.
+
+  .. versionadded:: 3.11
+    ``FLAME`` support.
+
+    .. versionadded:: 3.13
+      Added ILP64 MKL variants (``Intel10_64ilp``, ``Intel10_64ilp_seq``).
+
+  .. versionadded:: 3.17
+    Added single dynamic library MKL variant (``Intel10_64_dyn``).
+
+  .. versionadded:: 3.18
+    Arm Performance Libraries support (``Arm``, ``Arm_mp``, ``Arm_ilp64``,
+    ``Arm_ilp64_mp``).
+
+  .. versionadded:: 3.19
+    ``FlexiBLAS`` support.
+
+  .. versionadded:: 3.20
+    Elbrus Math Library support (``EML``, ``EML_mt``).
+
 ``BLA_F95``
   if ``ON`` tries to find the BLAS95/LAPACK95 interfaces
 
+``BLA_PREFER_PKGCONFIG``
+  .. versionadded:: 3.20
+
+  if set ``pkg-config`` will be used to search for a LAPACK library first
+  and if one is found that is preferred
+
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.18
+
 This module defines the following :prop_tgt:`IMPORTED` target:
 
 ``LAPACK::LAPACK``
@@ -95,6 +127,26 @@ endif()
 include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 
+function(_add_lapack_target)
+  if(LAPACK_FOUND AND NOT TARGET LAPACK::LAPACK)
+    add_library(LAPACK::LAPACK INTERFACE IMPORTED)
+    set(_lapack_libs "${LAPACK_LIBRARIES}")
+    if(_lapack_libs AND TARGET BLAS::BLAS)
+      # remove the ${BLAS_LIBRARIES} from the interface and replace it
+      # with the BLAS::BLAS target
+      list(REMOVE_ITEM _lapack_libs "${BLAS_LIBRARIES}")
+      list(APPEND _lapack_libs BLAS::BLAS)
+    endif()
+
+    if(_lapack_libs)
+      set_target_properties(LAPACK::LAPACK PROPERTIES
+        INTERFACE_LINK_LIBRARIES "${_lapack_libs}"
+      )
+    endif()
+    unset(_lapack_libs)
+  endif()
+endfunction()
+
 macro(_lapack_find_library_setup)
   cmake_push_check_state()
   set(CMAKE_REQUIRED_QUIET ${LAPACK_FIND_QUIETLY})
@@ -239,6 +291,21 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
   _lapack_find_dependency(BLAS)
 endif()
 
+# Search with pkg-config if specified
+if(BLA_PREFER_PKGCONFIG)
+  find_package(PkgConfig)
+  pkg_check_modules(PKGC_LAPACK lapack)
+  if(PKGC_LAPACK_FOUND)
+    set(LAPACK_FOUND TRUE)
+    set(LAPACK_LIBRARIES "${PKGC_LAPACK_LINK_LIBRARIES}")
+    if (BLAS_LIBRARIES)
+      list(APPEND LAPACK_LIBRARIES "${BLAS_LIBRARIES}")
+    endif()
+    _add_lapack_target()
+    return()
+  endif()
+endif()
+
 # Search for different LAPACK distributions if BLAS is found
 if(NOT LAPACK_NOT_FOUND_MESSAGE)
   set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS})
@@ -494,6 +561,30 @@ if(NOT LAPACK_NOT_FOUND_MESSAGE)
     )
   endif()
 
+  # Elbrus Math Library?
+  if(NOT LAPACK_LIBRARIES
+      AND (BLA_VENDOR MATCHES "EML" OR BLA_VENDOR STREQUAL "All"))
+
+    set(LAPACK_EML_LIB "eml")
+
+    # Check for OpenMP support, VIA BLA_VENDOR of eml_mt
+    if(BLA_VENDOR MATCHES "_mt")
+     set(LAPACK_EML_LIB "${LAPACK_EML_LIB}_mt")
+    endif()
+
+    check_lapack_libraries(
+      LAPACK_LIBRARIES
+      LAPACK
+      cheev
+      ""
+      "${LAPACK_EML_LIB}"
+      ""
+      ""
+      ""
+      "${BLAS_LIBRARIES}"
+    )
+  endif()
+
   # Generic LAPACK library?
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR STREQUAL "Generic"
@@ -535,21 +626,6 @@ if(LAPACK_LIBRARIES STREQUAL "LAPACK_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
   set(LAPACK_LIBRARIES "")
 endif()
 
-if(LAPACK_FOUND AND NOT TARGET LAPACK::LAPACK)
-  add_library(LAPACK::LAPACK INTERFACE IMPORTED)
-  set(_lapack_libs "${LAPACK_LIBRARIES}")
-  if(_lapack_libs AND TARGET BLAS::BLAS)
-    # remove the ${BLAS_LIBRARIES} from the interface and replace it
-    # with the BLAS::BLAS target
-    list(REMOVE_ITEM _lapack_libs "${BLAS_LIBRARIES}")
-  endif()
-
-  if(_lapack_libs)
-    set_target_properties(LAPACK::LAPACK PROPERTIES
-      INTERFACE_LINK_LIBRARIES "${_lapack_libs}"
-    )
-  endif()
-  unset(_lapack_libs)
-endif()
+_add_lapack_target()
 
 _lapack_find_library_teardown()
index b0dad7d..1e82651 100644 (file)
@@ -11,6 +11,10 @@ This module finds an installed LaTeX and determines the location
 of the compiler.  Additionally the module looks for Latex-related
 software like BibTeX.
 
+.. versionadded:: 3.2
+  Component processing; support for htlatex, pdftops, Biber, xindy, XeLaTeX,
+  LuaLaTeX.
+
 This module sets the following result variables::
 
   LATEX_FOUND:          whether found Latex and requested components
index ce3c8b8..08078a2 100644 (file)
@@ -22,6 +22,10 @@ The module defines the following ``IMPORTED`` targets:
 ::
 
   LibArchive::LibArchive  - target for linking against libarchive
+
+.. versionadded:: 3.6
+  Support for new libarchive 3.2 version string format.
+
 #]=======================================================================]
 
 find_path(LibArchive_INCLUDE_DIR
index 4a79a10..9ec8f07 100644 (file)
@@ -11,6 +11,8 @@ Find LZMA compression algorithm headers and library.
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.14
+
 This module defines :prop_tgt:`IMPORTED` target ``LibLZMA::LibLZMA``, if
 liblzma has been found.
 
index 0631607..ce28d03 100644 (file)
@@ -10,12 +10,16 @@ Find the XML processing library (libxml2).
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.12
+
 The following :prop_tgt:`IMPORTED` targets may be defined:
 
 ``LibXml2::LibXml2``
-  If the libxml2 library has been found
+  libxml2 library.
 ``LibXml2::xmllint``
-  If the xmllint command-line executable has been found
+  .. versionadded:: 3.17
+
+  xmllint command-line executable.
 
 Result variables
 ^^^^^^^^^^^^^^^^
index fc7adeb..97943d6 100644 (file)
@@ -11,6 +11,8 @@ Transformations (XSLT) library (LibXslt)
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.18
+
 The following :prop_tgt:`IMPORTED` targets may be defined:
 
 ``LibXslt::LibXslt``
@@ -35,7 +37,8 @@ Additionally, the following two variables are set (but not required
 for using xslt):
 
 ``LIBXSLT_EXSLT_INCLUDE_DIR``
-  The include directory for exslt.
+  .. versionadded:: 3.18
+    The include directory for exslt.
 ``LIBXSLT_EXSLT_LIBRARIES``
   Link to these if you need to link against the exslt library.
 ``LIBXSLT_XSLTPROC_EXECUTABLE``
index c4361b7..32642fe 100644 (file)
@@ -5,10 +5,11 @@
 FindLua
 -------
 
-
-
 Locate Lua library.
 
+.. versionadded:: 3.18
+  Support for Lua 5.4.
+
 This module defines::
 
 ::
index 789a72e..195ca49 100644 (file)
@@ -12,6 +12,10 @@ high-performance distributed-memory parallel applications, and is
 typically deployed on a cluster.  MPI is a standard interface (defined
 by the MPI forum) for which many implementations are available.
 
+.. versionadded:: 3.10
+  Major overhaul of the module: many new variables, per-language components,
+  support for a wider variety of runtimes.
+
 Variables for using MPI
 ^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -50,7 +54,8 @@ project, where ``<lang>`` is one of C, CXX, or Fortran:
 ``MPI_<lang>_LIBRARIES``
   All libraries to link MPI programs against.
 
-Additionally, the following :prop_tgt:`IMPORTED` targets are defined:
+.. versionadded:: 3.9
+  Additionally, the following :prop_tgt:`IMPORTED` targets are defined:
 
 ``MPI::MPI_<lang>``
   Target for using MPI from ``<lang>``.
@@ -236,8 +241,10 @@ If the following variables are set to true, the respective search will be perfor
 Backward Compatibility
 ^^^^^^^^^^^^^^^^^^^^^^
 
+.. deprecated:: 3.10
+
 For backward compatibility with older versions of FindMPI, these
-variables are set, but deprecated:
+variables are set:
 
 ::
 
@@ -287,6 +294,11 @@ if(WIN32)
   set(_MPI_Intel_CXX_COMPILER_NAMES          mpiicpc.bat)
   set(_MPI_Intel_Fortran_COMPILER_NAMES      mpiifort.bat mpif77.bat mpif90.bat)
 
+  # Intel MPI compiler names
+  set(_MPI_IntelLLVM_C_COMPILER_NAMES            mpiicc.bat)
+  set(_MPI_IntelLLVM_CXX_COMPILER_NAMES          mpiicpc.bat)
+  set(_MPI_IntelLLVM_Fortran_COMPILER_NAMES      mpiifort.bat mpif77.bat mpif90.bat)
+
   # Intel MPI compiler names for MSMPI
   set(_MPI_MSVC_C_COMPILER_NAMES             mpicl.bat)
   set(_MPI_MSVC_CXX_COMPILER_NAMES           mpicl.bat)
@@ -295,6 +307,11 @@ else()
   set(_MPI_Intel_C_COMPILER_NAMES            mpiicc)
   set(_MPI_Intel_CXX_COMPILER_NAMES          mpiicpc  mpiicxx mpiic++)
   set(_MPI_Intel_Fortran_COMPILER_NAMES      mpiifort mpiif95 mpiif90 mpiif77)
+
+  # Intel compiler names
+  set(_MPI_IntelLLVM_C_COMPILER_NAMES            mpiicc)
+  set(_MPI_IntelLLVM_CXX_COMPILER_NAMES          mpiicpc  mpiicxx mpiic++)
+  set(_MPI_IntelLLVM_Fortran_COMPILER_NAMES      mpiifort mpiif95 mpiif90 mpiif77)
 endif()
 
 # PGI compiler names
@@ -320,7 +337,7 @@ set(_MPI_XL_Fortran_COMPILER_NAMES         mpixlf95   mpixlf95_r mpxlf95 mpxlf95
 # pick up the right settings for it.
 foreach (LANG IN ITEMS C CXX Fortran)
   set(_MPI_${LANG}_COMPILER_NAMES "")
-  foreach (id IN ITEMS GNU Intel MSVC PGI XL)
+  foreach (id IN ITEMS GNU Intel IntelLLVM MSVC PGI XL)
     if (NOT CMAKE_${LANG}_COMPILER_ID OR CMAKE_${LANG}_COMPILER_ID STREQUAL id)
       foreach(_COMPILER_NAME IN LISTS _MPI_${id}_${LANG}_COMPILER_NAMES)
         list(APPEND _MPI_${LANG}_COMPILER_NAMES ${_COMPILER_NAME}${MPI_EXECUTABLE_SUFFIX})
@@ -1411,7 +1428,9 @@ foreach(LANG IN ITEMS C CXX Fortran)
     endif()
   else()
     set(_MPI_FIND_${LANG} FALSE)
-    string(APPEND _MPI_FAIL_REASON "MPI component '${LANG}' was requested, but language ${LANG} is not enabled.  ")
+    if(${LANG} IN_LIST MPI_FIND_COMPONENTS)
+      string(APPEND _MPI_FAIL_REASON "MPI component '${LANG}' was requested, but language ${LANG} is not enabled.  ")
+    endif()
   endif()
   if(_MPI_FIND_${LANG})
     if( ${LANG} STREQUAL CXX AND NOT MPICXX IN_LIST MPI_FIND_COMPONENTS )
index 01f0492..2f56d15 100644 (file)
@@ -17,6 +17,9 @@ can also be used:
 * to retrieve various information from Matlab (mex extensions, versions and
   release queries, ...)
 
+.. versionadded:: 3.12
+  Added Matlab Compiler Runtime (MCR) support.
+
 The module supports the following components:
 
 * ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the ``ENG`` and ``MAT``
@@ -28,6 +31,17 @@ The module supports the following components:
 * ``MCC_COMPILER`` the MCC compiler, included with the Matlab Compiler add-on.
 * ``SIMULINK`` the Simulink environment.
 
+.. versionadded:: 3.7
+  Added the ``MAT_LIBRARY`` component.
+
+.. versionadded:: 3.13
+  Added the ``ENGINE_LIBRARY``, ``DATAARRAY_LIBRARY`` and ``MCC_COMPILER``
+  components.
+
+.. versionchanged:: 3.14
+  Removed the ``MX_LIBRARY``, ``ENGINE_LIBRARY`` and ``DATAARRAY_LIBRARY``
+  components.  These libraries are found unconditionally.
+
 .. note::
 
   The version given to the :command:`find_package` directive is the Matlab
@@ -107,8 +121,12 @@ Result variables
   Matlab matrix library. Available only if the component ``MAT_LIBRARY``
   is requested.
 ``Matlab_ENGINE_LIBRARY``
+  .. versionadded:: 3.13
+
   Matlab C++ engine library, always available for R2018a and newer.
 ``Matlab_DATAARRAY_LIBRARY``
+  .. versionadded:: 3.13
+
   Matlab C++ data array library, always available for R2018a and newer.
 ``Matlab_LIBRARIES``
   the whole set of libraries of Matlab
@@ -116,6 +134,8 @@ Result variables
   the mex compiler of Matlab. Currently not used.
   Available only if the component ``MEX_COMPILER`` is requested.
 ``Matlab_MCC_COMPILER``
+  .. versionadded:: 3.13
+
   the mcc compiler of Matlab. Included with the Matlab Compiler add-on.
   Available only if the component ``MCC_COMPILER`` is requested.
 
@@ -241,6 +261,7 @@ if(NOT MATLAB_ADDITIONAL_VERSIONS)
 endif()
 
 set(MATLAB_VERSIONS_MAPPING
+  "R2021a=9.10"
   "R2020b=9.9"
   "R2020a=9.8"
   "R2019b=9.7"
@@ -389,12 +410,12 @@ function(matlab_extract_all_installed_versions_from_registry win64 matlab_versio
 
   set(matlabs_from_registry)
 
-  foreach(_installation_type IN ITEMS "MATLAB" "MATLAB Runtime")
+  foreach(_installation_type IN ITEMS "MATLAB" "MATLAB Runtime" "MATLAB Compiler Runtime")
 
     # /reg:64 should be added on 64 bits capable OSs in order to enable the
     # redirection of 64 bits applications
     execute_process(
-      COMMAND reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\${_installation_type} /f * /k ${APPEND_REG}
+      COMMAND reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Mathworks\\${_installation_type}" /f * /k ${APPEND_REG}
       RESULT_VARIABLE resultMatlab
       OUTPUT_VARIABLE varMatlab
       ERROR_VARIABLE errMatlab
@@ -405,12 +426,12 @@ function(matlab_extract_all_installed_versions_from_registry win64 matlab_versio
     if(resultMatlab EQUAL 0)
 
       string(
-        REGEX MATCHALL "MATLAB\\\\([0-9]+(\\.[0-9]+)?)"
+        REGEX MATCHALL "${_installation_type}\\\\([0-9]+(\\.[0-9]+)?)"
         matlab_versions_regex ${varMatlab})
 
       foreach(match IN LISTS matlab_versions_regex)
         string(
-          REGEX MATCH "MATLAB\\\\(([0-9]+)(\\.([0-9]+))?)"
+          REGEX MATCH "${_installation_type}\\\\(([0-9]+)(\\.([0-9]+))?)"
           current_match ${match})
 
         set(_matlab_current_version ${CMAKE_MATCH_1})
@@ -517,7 +538,7 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_
       "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]"
       ABSOLUTE)
 
-    if(EXISTS ${current_MATLAB_ROOT})
+    if(EXISTS "${current_MATLAB_ROOT}")
       list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT})
     endif()
 
@@ -533,7 +554,23 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_
     # remove the dot
     string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
 
-    if(EXISTS ${current_MATLAB_ROOT})
+    if(EXISTS "${current_MATLAB_ROOT}")
+      list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
+    endif()
+
+  endforeach()
+
+  # Check for old MCR installations
+  foreach(_matlab_current_version ${matlab_versions})
+    get_filename_component(
+      current_MATLAB_ROOT
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Compiler Runtime\\${_matlab_current_version};MATLABROOT]"
+      ABSOLUTE)
+
+    # remove the dot
+    string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
+
+    if(EXISTS "${current_MATLAB_ROOT}")
       list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
     endif()
 
@@ -923,14 +960,26 @@ endfunction()
     the same folder without any processing, with the same name as the final
     mex file, and with extension `.m`. In that case, typing ``help <name>``
     in Matlab prints the documentation contained in this file.
-  ``R2017b`` or ``R2018a`` may be given to specify the version of the C API
+  ``R2017b`` or ``R2018a``
+    .. versionadded:: 3.14
+
+    May be given to specify the version of the C API
     to use: ``R2017b`` specifies the traditional (separate complex) C API,
     and corresponds to the ``-R2017b`` flag for the `mex` command. ``R2018a``
     specifies the new interleaved complex C API, and corresponds to the
     ``-R2018a`` flag for the `mex` command. Ignored if MATLAB version prior
     to R2018a. Defaults to ``R2017b``.
-  ``MODULE`` or ``SHARED`` may be given to specify the type of library to be
-    created. ``EXECUTABLE`` may be given to create an executable instead of
+
+  ``MODULE`` or ``SHARED``
+    .. versionadded:: 3.7
+
+    May be given to specify the type of library to be
+    created.
+
+  ``EXECUTABLE``
+    .. versionadded:: 3.7
+
+    May be given to create an executable instead of
     a library. If no type is given explicitly, the type is ``SHARED``.
   ``EXCLUDE_FROM_ALL``
     This option has the same meaning as for :prop_tgt:`EXCLUDE_FROM_ALL` and
@@ -1035,7 +1084,12 @@ function(matlab_add_mex)
   target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS})
 
   if(Matlab_HAS_CPP_API)
-    target_link_libraries(${${prefix}_NAME} ${Matlab_ENGINE_LIBRARY} ${Matlab_DATAARRAY_LIBRARY})
+    if(Matlab_ENGINE_LIBRARY)
+      target_link_libraries(${${prefix}_NAME} ${Matlab_ENGINE_LIBRARY})
+    endif()
+    if(Matlab_DATAARRAY_LIBRARY)
+      target_link_libraries(${${prefix}_NAME} ${Matlab_DATAARRAY_LIBRARY})
+    endif()
   endif()
 
   target_link_libraries(${${prefix}_NAME} ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${${prefix}_LINK_TO})
@@ -1655,32 +1709,34 @@ find_path(
   )
 list(APPEND _matlab_required_variables Matlab_INCLUDE_DIRS)
 
-_Matlab_find_library(
-  ${_matlab_lib_prefix_for_search}
-  Matlab_MEX_LIBRARY
-  mex
-  PATHS ${_matlab_lib_dir_for_search}
-  NO_DEFAULT_PATH
-)
-list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY)
+if(Matlab_Or_MCR STREQUAL "MATLAB" OR Matlab_Or_MCR STREQUAL "UNKNOWN")
+  _Matlab_find_library(
+    ${_matlab_lib_prefix_for_search}
+    Matlab_MEX_LIBRARY
+    mex
+    PATHS ${_matlab_lib_dir_for_search}
+    NO_DEFAULT_PATH
+  )
+  list(APPEND _matlab_required_variables Matlab_MEX_LIBRARY)
 
-# the MEX extension is required
-list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION)
+  # the MEX extension is required
+  list(APPEND _matlab_required_variables Matlab_MEX_EXTENSION)
 
-# the matlab root is required
-list(APPEND _matlab_required_variables Matlab_ROOT_DIR)
+  # the matlab root is required
+  list(APPEND _matlab_required_variables Matlab_ROOT_DIR)
 
-# The MX library is required
-_Matlab_find_library(
-  ${_matlab_lib_prefix_for_search}
-  Matlab_MX_LIBRARY
-  mx
-  PATHS ${_matlab_lib_dir_for_search}
-  NO_DEFAULT_PATH
-)
-list(APPEND _matlab_required_variables Matlab_MX_LIBRARY)
-if(Matlab_MX_LIBRARY)
-  set(Matlab_MX_LIBRARY_FOUND TRUE)
+  # The MX library is required
+  _Matlab_find_library(
+    ${_matlab_lib_prefix_for_search}
+    Matlab_MX_LIBRARY
+    mx
+    PATHS ${_matlab_lib_dir_for_search}
+    NO_DEFAULT_PATH
+  )
+  list(APPEND _matlab_required_variables Matlab_MX_LIBRARY)
+  if(Matlab_MX_LIBRARY)
+    set(Matlab_MX_LIBRARY_FOUND TRUE)
+  endif()
 endif()
 
 if(Matlab_HAS_CPP_API)
@@ -1694,7 +1750,6 @@ if(Matlab_HAS_CPP_API)
     DOC "MatlabEngine Library"
     NO_DEFAULT_PATH
   )
-  list(APPEND _matlab_required_variables Matlab_ENGINE_LIBRARY)
   if(Matlab_ENGINE_LIBRARY)
     set(Matlab_ENGINE_LIBRARY_FOUND TRUE)
   endif()
@@ -1708,7 +1763,6 @@ if(Matlab_HAS_CPP_API)
     DOC "MatlabDataArray Library"
     NO_DEFAULT_PATH
   )
-  list(APPEND _matlab_required_variables Matlab_DATAARRAY_LIBRARY)
   if(Matlab_DATAARRAY_LIBRARY)
     set(Matlab_DATAARRAY_LIBRARY_FOUND TRUE)
   endif()
@@ -1801,8 +1855,15 @@ endif()
 
 set(Matlab_LIBRARIES
   ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY}
-  ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY}
-  ${Matlab_DATAARRAY_LIBRARY} ${Matlab_ENGINE_LIBRARY})
+  ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY})
+
+if(Matlab_ENGINE_LIBRARY)
+  list(APPEND Matlab_LIBRARIES ${Matlab_ENGINE_LIBRARY})
+endif()
+
+if(Matlab_DATAARRAY_LIBRARY)
+  list(APPEND Matlab_LIBRARIES ${Matlab_DATAARRAY_LIBRARY})
+endif()
 
 find_package_handle_standard_args(
   Matlab
index ed52e35..cf58f3b 100644 (file)
@@ -12,7 +12,17 @@ Detect OpenACC support by the compiler.
 This module can be used to detect OpenACC support in a compiler.
 If the compiler supports OpenACC, the flags required to compile with
 OpenACC support are returned in variables for the different languages.
-Currently, only PGI, GNU and Cray compilers are supported.
+Currently, only NVHPC, PGI, GNU and Cray compilers are supported.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.16
+
+The module provides :prop_tgt:`IMPORTED` targets:
+
+``OpenACC::OpenACC_<lang>``
+  Target for using OpenACC from ``<lang>``.
 
 Variables
 ^^^^^^^^^
@@ -25,14 +35,11 @@ project, where ``<lang>`` is one of C, CXX, or Fortran:
 ``OpenACC_<lang>_FLAGS``
   OpenACC compiler flags for ``<lang>``, separated by spaces.
 ``OpenACC_<lang>_OPTIONS``
+  .. versionadded:: 3.16
+
   OpenACC compiler flags for ``<lang>``, as a list. Suitable for usage
   with target_compile_options or target_link_options.
 
-Additionally, the module provides :prop_tgt:`IMPORTED` targets:
-
-``OpenACC::OpenACC_<lang>``
-  Target for using OpenACC from ``<lang>``.
-
 The module will also try to provide the OpenACC version variables:
 
 ``OpenACC_<lang>_SPEC_DATE``
@@ -132,6 +139,7 @@ endfunction()
 
 
 function(_OPENACC_GET_FLAGS_CANDIDATE LANG FLAG_VAR)
+  set(ACC_FLAG_NVHPC "-acc")
   set(ACC_FLAG_PGI "-acc")
   set(ACC_FLAG_GNU "-fopenacc")
   set(ACC_FLAG_Cray "-h acc")
@@ -148,6 +156,7 @@ endfunction()
 
 function(_OPENACC_GET_ACCEL_TARGET_FLAG LANG TARGET FLAG_VAR)
   # Find target accelerator flags.
+  set(ACC_TARGET_FLAG_NVHPC "-ta")
   set(ACC_TARGET_FLAG_PGI "-ta")
   if(DEFINED ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID})
     set("${FLAG_VAR}" "${ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID}}=${TARGET}" PARENT_SCOPE)
@@ -157,6 +166,7 @@ endfunction()
 
 function(_OPENACC_GET_VERBOSE_FLAG LANG FLAG_VAR)
   # Find compiler's verbose flag for OpenACC.
+  set(ACC_VERBOSE_FLAG_NVHPC "-Minfo=accel")
   set(ACC_VERBOSE_FLAG_PGI "-Minfo=accel")
   if(DEFINED ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID})
     set("${FLAG_VAR}" "${ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID}}" PARENT_SCOPE)
index b3e5a9f..1b4662b 100644 (file)
@@ -9,9 +9,14 @@ FindOpenCL
 
 Finds Open Computing Language (OpenCL)
 
+.. versionadded:: 3.10
+  Detection of OpenCL 2.1 and 2.2.
+
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.7
+
 This module defines :prop_tgt:`IMPORTED` target ``OpenCL::OpenCL``, if
 OpenCL has been found.
 
index 110e7f9..d6d1c00 100644 (file)
@@ -7,27 +7,41 @@ FindOpenGL
 
 FindModule for OpenGL and OpenGL Utility Library (GLU).
 
+.. versionchanged:: 3.2
+  X11 is no longer added as a dependency on Unix/Linux systems.
+
+.. versionadded:: 3.10
+  GLVND support on Linux.  See the :ref:`Linux Specific` section below.
+
 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.
 
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.8
+
 This module defines the :prop_tgt:`IMPORTED` targets:
 
 ``OpenGL::GL``
- Defined to the platform-specific OpenGL libraries if the system has OpenGL.
-``OpenGL::OpenGL``
- Defined to libOpenGL if the system is GLVND-based.
+  Defined to the platform-specific OpenGL libraries if the system has OpenGL.
 ``OpenGL::GLU``
- Defined if the system has OpenGL Utility Library (GLU).
+  Defined if the system has OpenGL Utility Library (GLU).
+
+.. versionadded:: 3.10
+  Additionally, the following GLVND-specific library targets are defined:
+
+``OpenGL::OpenGL``
+  Defined to libOpenGL if the system is GLVND-based.
 ``OpenGL::GLX``
- Defined if the system has OpenGL Extension to the X Window System (GLX).
 Defined if the system has OpenGL Extension to the X Window System (GLX).
 ``OpenGL::EGL``
- Defined if the system has EGL.
 Defined if the system has EGL.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -55,6 +69,9 @@ This module sets the following variables:
  On Linux, this assumes GLX and is never correct for EGL-based targets.
  Clients are encouraged to use the ``OpenGL::*`` import targets instead.
 
+.. versionadded:: 3.10
+  Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``.
+
 Cache variables
 ^^^^^^^^^^^^^^^
 
@@ -72,6 +89,11 @@ The following cache variables may also be set:
  Path to the OpenGL library.  New code should prefer the ``OpenGL::*`` import
  targets.
 
+.. versionadded:: 3.10
+  Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``.
+
+.. _`Linux Specific`:
+
 Linux-specific
 ^^^^^^^^^^^^^^
 
@@ -97,14 +119,14 @@ The value may be one of:
 ``GLVND``
  If the GLVND OpenGL and GLX libraries are available, prefer them.
  This forces ``OPENGL_gl_LIBRARY`` to be empty.
- This is the default if components were requested (since components
- correspond to GLVND libraries) or if policy :policy:`CMP0072` is
- set to ``NEW``.
+
+ .. versionchanged:: 3.11
+  This is the default, unless policy :policy:`CMP0072` is set to ``OLD``
+  and no components are requeted (since components
+  correspond to GLVND libraries).
 
 ``LEGACY``
  Prefer to use the legacy libGL library, if available.
- This is the default if no components were requested and
- policy :policy:`CMP0072` is not set to ``NEW``.
 
 For EGL targets the client must rely on GLVND support on the user's system.
 Linking should use the ``OpenGL::OpenGL OpenGL::EGL`` targets.  Using GLES*
@@ -443,7 +465,7 @@ if(OPENGL_FOUND)
 
   # ::GLX is a GLVND library, and thus Linux-only: we don't bother checking
   # for a framework version of this library.
-  if(OpenGL_GLX_FOUND AND NOT TARGET OpenGL::GLX)
+  if(OpenGL_GLX_FOUND AND NOT TARGET OpenGL::GLX AND TARGET OpenGL::OpenGL)
     if(IS_ABSOLUTE "${OPENGL_glx_LIBRARY}")
       add_library(OpenGL::GLX UNKNOWN IMPORTED)
       set_target_properties(OpenGL::GLX PROPERTIES IMPORTED_LOCATION
index bb38e28..52330a4 100644 (file)
@@ -13,11 +13,15 @@ OpenMP support are returned in variables for the different languages.
 The variables may be empty if the compiler does not need a special
 flag to support OpenMP.
 
+.. versionadded:: 3.5
+  Clang support.
+
 Variables
 ^^^^^^^^^
 
-The module exposes the components ``C``, ``CXX``, and ``Fortran``.
-Each of these controls the various languages to search OpenMP support for.
+.. versionadded:: 3.10
+  The module exposes the components ``C``, ``CXX``, and ``Fortran``.
+  Each of these controls the various languages to search OpenMP support for.
 
 Depending on the enabled components the following variables will be set:
 
@@ -65,6 +69,8 @@ Specifically for Fortran, the module sets the following variables:
 The module will also try to provide the OpenMP version variables:
 
 ``OpenMP_<lang>_SPEC_DATE``
+  .. versionadded:: 3.7
+
   Date of the OpenMP specification implemented by the ``<lang>`` compiler.
 ``OpenMP_<lang>_VERSION_MAJOR``
   Major version of OpenMP implemented by the ``<lang>`` compiler.
@@ -107,10 +113,17 @@ function(_OPENMP_FLAG_CANDIDATES LANG)
     else()
       set(OMP_FLAG_Intel "-qopenmp")
     endif()
+    if(CMAKE_${LANG}_COMPILER_ID STREQUAL "IntelLLVM" AND
+      "x${CMAKE_${LANG}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+      set(OMP_FLAG_IntelLLVM "-Qiopenmp")
+    else()
+      set(OMP_FLAG_IntelLLVM "-fiopenmp")
+    endif()
     set(OMP_FLAG_MSVC "-openmp")
     set(OMP_FLAG_PathScale "-openmp")
     set(OMP_FLAG_NAG "-openmp")
     set(OMP_FLAG_Absoft "-openmp")
+    set(OMP_FLAG_NVHPC "-mp")
     set(OMP_FLAG_PGI "-mp")
     set(OMP_FLAG_Flang "-fopenmp")
     set(OMP_FLAG_SunPro "-xopenmp")
index 91a65fd..b1afa5f 100644 (file)
@@ -7,15 +7,29 @@ FindOpenSSL
 
 Find the OpenSSL encryption library.
 
+This module finds an installed OpenSSL library and determines its version.
+
+.. versionadded:: 3.19
+  When a version is requested, it can be specified as a simple value or as a
+  range. For a detailed description of version range usage and capabilities,
+  refer to the :command:`find_package` command.
+
+.. versionadded:: 3.18
+  Support for OpenSSL 3.0.
+
 Optional COMPONENTS
 ^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.12
+
 This module supports two optional COMPONENTS: ``Crypto`` and ``SSL``.  Both
 components have associated imported targets, as described below.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.4
+
 This module defines the following :prop_tgt:`IMPORTED` targets:
 
 ``OpenSSL::SSL``
@@ -23,6 +37,8 @@ This module defines the following :prop_tgt:`IMPORTED` targets:
 ``OpenSSL::Crypto``
   The OpenSSL ``crypto`` library, if found.
 ``OpenSSL::applink``
+  .. versionadded:: 3.18
+
   The OpenSSL ``applink`` components that might be need to be compiled into
   projects under MSVC. This target is available only if found OpenSSL version
   is not less than 0.9.8. By linking this target the above OpenSSL targets can
@@ -75,8 +91,12 @@ Hints
 ^^^^^
 
 Set ``OPENSSL_ROOT_DIR`` to the root directory of an OpenSSL installation.
-Set ``OPENSSL_USE_STATIC_LIBS`` to ``TRUE`` to look for static libraries.
-Set ``OPENSSL_MSVC_STATIC_RT`` set ``TRUE`` to choose the MT version of the lib.
+
+.. versionadded:: 3.4
+  Set ``OPENSSL_USE_STATIC_LIBS`` to ``TRUE`` to look for static libraries.
+
+.. versionadded:: 3.5
+  Set ``OPENSSL_MSVC_STATIC_RT`` set ``TRUE`` to choose the MT version of the lib.
 #]=======================================================================]
 
 macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library)
@@ -128,16 +148,30 @@ if (WIN32)
     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
     ENV OPENSSL_ROOT_DIR
     )
-  file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
+
+  if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+    set(_arch "Win64")
+    file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
+  else()
+    set(_arch "Win32")
+    set(_progfiles_x86 "ProgramFiles(x86)")
+    if(NOT "$ENV{${_progfiles_x86}}" STREQUAL "")
+      # under windows 64 bit machine
+      file(TO_CMAKE_PATH "$ENV{${_progfiles_x86}}" _programfiles)
+    else()
+      # under windows 32 bit machine
+      file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _programfiles)
+    endif()
+  endif()
+
   set(_OPENSSL_ROOT_PATHS
     "${_programfiles}/OpenSSL"
-    "${_programfiles}/OpenSSL-Win32"
-    "${_programfiles}/OpenSSL-Win64"
+    "${_programfiles}/OpenSSL-${_arch}"
     "C:/OpenSSL/"
-    "C:/OpenSSL-Win32/"
-    "C:/OpenSSL-Win64/"
+    "C:/OpenSSL-${_arch}/"
     )
   unset(_programfiles)
+  unset(_arch)
 else ()
   set(_OPENSSL_ROOT_HINTS
     ${OPENSSL_ROOT_DIR}
@@ -539,6 +573,7 @@ find_package_handle_standard_args(OpenSSL
     OPENSSL_INCLUDE_DIR
   VERSION_VAR
     OPENSSL_VERSION
+  HANDLE_VERSION_RANGE
   HANDLE_COMPONENTS
   FAIL_MESSAGE
     "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
index fd0e4e9..94d15db 100644 (file)
@@ -10,6 +10,8 @@ Find libpng, the official reference library for the PNG image format.
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.5
+
 This module defines the following :prop_tgt:`IMPORTED` target:
 
 ``PNG::PNG``
@@ -53,6 +55,7 @@ find_package(ZLIB ${_FIND_ZLIB_ARG})
 
 if(ZLIB_FOUND)
   find_path(PNG_PNG_INCLUDE_DIR png.h PATH_SUFFIXES include/libpng)
+  mark_as_advanced(PNG_PNG_INCLUDE_DIR)
 
   list(APPEND PNG_NAMES png libpng)
   unset(PNG_NAMES_DEBUG)
@@ -156,5 +159,3 @@ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 find_package_handle_standard_args(PNG
                                   REQUIRED_VARS PNG_LIBRARY PNG_PNG_INCLUDE_DIR
                                   VERSION_VAR PNG_VERSION_STRING)
-
-mark_as_advanced(PNG_PNG_INCLUDE_DIR PNG_LIBRARY )
index 7e17277..fbcf7cd 100644 (file)
@@ -51,7 +51,9 @@ implementing :command:`find_package(<PackageName>)` calls.
     (recommended).  Not valid in the full signature.
 
   ``FOUND_VAR <result-var>``
-    Obsolete.  Specifies either ``<PackageName>_FOUND`` or
+    .. deprecated:: 3.3
+
+    Specifies either ``<PackageName>_FOUND`` or
     ``<PACKAGENAME>_FOUND`` as the result variable.  This exists only
     for compatibility with older versions of CMake and is now ignored.
     Result variables of both names are always set for compatibility.
@@ -61,8 +63,10 @@ implementing :command:`find_package(<PackageName>)` calls.
     These may be named in the generated failure message asking the
     user to set the missing variable values.  Therefore these should
     typically be cache entries such as ``FOO_LIBRARY`` and not output
-    variables like ``FOO_LIBRARIES``. This option is mandatory if
-    ``HANDLE_COMPONENTS`` is not specified.
+    variables like ``FOO_LIBRARIES``.
+
+    .. versionchanged:: 3.18
+      If ``HANDLE_COMPONENTS`` is specified, this option can be omitted.
 
   ``VERSION_VAR <version-var>``
     Specify the name of a variable that holds the version of the package
@@ -74,6 +78,8 @@ implementing :command:`find_package(<PackageName>)` calls.
     if the version is ok or not.
 
   ``HANDLE_VERSION_RANGE``
+    .. versionadded:: 3.19
+
     Enable handling of a version range, if one is specified. Without this
     option, a developer warning will be displayed if a version range is
     specified.
@@ -94,6 +100,8 @@ implementing :command:`find_package(<PackageName>)` calls.
     was found.
 
   ``REASON_FAILURE_MESSAGE <reason-failure-message>``
+    .. versionadded:: 3.16
+
     Specify a custom message of the reason for the failure which will be
     appended to the default generated message.
 
@@ -102,6 +110,8 @@ implementing :command:`find_package(<PackageName>)` calls.
     generated message.  Not recommended.
 
   ``NAME_MISMATCHED``
+    .. versionadded:: 3.17
+
     Indicate that the ``<PackageName>`` does not match
     ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a
     warning, but it may be intentional for usage of the command for components
@@ -163,6 +173,8 @@ message.
 
 .. command:: find_package_check_version
 
+  .. versionadded:: 3.19
+
   Helper function which can be used to check if a ``<version>`` is valid
   against version-related arguments of :command:`find_package`.
 
index 360f439..38c8da7 100644 (file)
@@ -635,19 +635,38 @@ endmacro()
 
   When the ``QUIET`` argument is given, no status messages will be printed.
 
-  By default, if :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or
-  later, or if :variable:`PKG_CONFIG_USE_CMAKE_PREFIX_PATH` is set to a
-  boolean ``True`` value, then the :variable:`CMAKE_PREFIX_PATH`,
-  :variable:`CMAKE_FRAMEWORK_PATH`, and :variable:`CMAKE_APPBUNDLE_PATH` cache
-  and environment variables will be added to the ``pkg-config`` search path.
-  The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments
-  disable this behavior for the cache variables and environment variables
-  respectively.
-
-  The ``IMPORTED_TARGET`` argument will create an imported target named
-  ``PkgConfig::<prefix>`` that can be passed directly as an argument to
-  :command:`target_link_libraries`. The ``GLOBAL`` argument will make the
-  imported target available in global scope.
+  .. versionadded:: 3.1
+    The :variable:`CMAKE_PREFIX_PATH`,
+    :variable:`CMAKE_FRAMEWORK_PATH`, and :variable:`CMAKE_APPBUNDLE_PATH` cache
+    and environment variables will be added to the ``pkg-config`` search path.
+    The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments
+    disable this behavior for the cache variables and environment variables
+    respectively.
+    The :variable:`PKG_CONFIG_USE_CMAKE_PREFIX_PATH` variable set to ``FALSE``
+    disables this behavior globally.
+
+    .. This didn't actually work until 3.3.
+
+  .. versionadded:: 3.6
+    The ``IMPORTED_TARGET`` argument will create an imported target named
+    ``PkgConfig::<prefix>`` that can be passed directly as an argument to
+    :command:`target_link_libraries`.
+
+    .. This didn't actually work until 3.7.
+
+  .. versionadded:: 3.13
+    The ``GLOBAL`` argument will make the
+    imported target available in global scope.
+
+  .. versionadded:: 3.15
+    Non-library linker options reported by ``pkg-config`` are stored in the
+    :prop_tgt:`INTERFACE_LINK_OPTIONS` target property.
+
+  .. versionchanged:: 3.18
+    Include directories specified with ``-isystem`` are stored in the
+    :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property.  Previous
+    versions of CMake left them in the :prop_tgt:`INTERFACE_COMPILE_OPTIONS`
+    property.
 
   Each ``<moduleSpec>`` can be either a bare module name or it can be a
   module name with a version constraint (operators ``=``, ``<``, ``>``,
@@ -686,6 +705,11 @@ endmacro()
   All but ``<XXX>_FOUND`` may be a :ref:`;-list <CMake Language Lists>` if the
   associated variable returned from ``pkg-config`` has multiple values.
 
+  .. versionchanged:: 3.18
+    Include directories specified with ``-isystem`` are stored in the
+    ``<XXX>_INCLUDE_DIRS`` variable.  Previous versions of CMake left them
+    in ``<XXX>_CFLAGS_OTHER``.
+
   There are some special variables whose prefix depends on the number of
   ``<moduleSpec>`` given.  When there is only one ``<moduleSpec>``,
   ``<YYY>`` will simply be ``<prefix>``, but if two or more ``<moduleSpec>``
@@ -700,6 +724,16 @@ endmacro()
   ``<YYY>_LIBDIR``
     lib directory of the module
 
+  .. versionchanged:: 3.8
+    For any given ``<prefix>``, ``pkg_check_modules()`` can be called multiple
+    times with different parameters.  Previous versions of CMake cached and
+    returned the first successful result.
+
+  .. versionchanged:: 3.16
+    If a full path to the found library can't be determined, but it's still
+    visible to the linker, pass it through as ``-l<name>``.  Previous versions
+    of CMake failed in this case.
+
   Examples:
 
   .. code-block:: cmake
@@ -771,9 +805,10 @@ endmacro()
                       [IMPORTED_TARGET [GLOBAL]]
                       <moduleSpec> [<moduleSpec>...])
 
-  If a module is found, the ``<prefix>_MODULE_NAME`` variable will contain the
-  name of the matching module. This variable can be used if you need to run
-  :command:`pkg_get_variable`.
+  .. versionadded:: 3.16
+    If a module is found, the ``<prefix>_MODULE_NAME`` variable will contain the
+    name of the matching module. This variable can be used if you need to run
+    :command:`pkg_get_variable`.
 
   Example:
 
@@ -818,6 +853,8 @@ endmacro()
 #[========================================[.rst:
 .. command:: pkg_get_variable
 
+  .. versionadded:: 3.4
+
   Retrieves the value of a pkg-config variable ``varName`` and stores it in the
   result variable ``resultVar`` in the calling scope.
 
@@ -852,10 +889,15 @@ Variables Affecting Behavior
 
   This can be set to the path of the pkg-config executable.  If not provided,
   it will be set by the module as a result of calling :command:`find_program`
-  internally.  The ``PKG_CONFIG`` environment variable can be used as a hint.
+  internally.
+
+  .. versionadded:: 3.1
+    The ``PKG_CONFIG`` environment variable can be used as a hint.
 
 .. variable:: PKG_CONFIG_USE_CMAKE_PREFIX_PATH
 
+  .. versionadded:: 3.1
+
   Specifies whether :command:`pkg_check_modules` and
   :command:`pkg_search_module` should add the paths in the
   :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_FRAMEWORK_PATH` and
index 1970b26..147071a 100644 (file)
@@ -10,6 +10,8 @@ Find the PostgreSQL installation.
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.14
+
 This module defines :prop_tgt:`IMPORTED` target ``PostgreSQL::PostgreSQL``
 if PostgreSQL has been found.
 
@@ -28,6 +30,16 @@ This module will set the following variables in your project:
   the link directories for PostgreSQL libraries
 ``PostgreSQL_VERSION_STRING``
   the version of PostgreSQL found
+``PostgreSQL_TYPE_INCLUDE_DIR``
+  the directories of the PostgreSQL server headers
+
+Components
+^^^^^^^^^^
+
+This module contains additional ``Server`` component, that forcibly checks
+for the presence of server headers. Note that ``PostgreSQL_TYPE_INCLUDE_DIR``
+is set regardless of the presence of the ``Server`` component in find_package call.
+
 #]=======================================================================]
 
 # ----------------------------------------------------------------------------
@@ -79,6 +91,9 @@ This module will set the following variables in your project:
 #
 # ----------------------------------------------------------------------------
 
+cmake_policy(PUSH)
+cmake_policy(SET CMP0057 NEW) # if IN_LIST
+
 set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include")
 set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}")
 set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.")
@@ -242,10 +257,18 @@ if (PostgreSQL_INCLUDE_DIR)
   unset(pgsql_version_str)
 endif()
 
+if("Server" IN_LIST PostgreSQL_FIND_COMPONENTS)
+  set(PostgreSQL_Server_FOUND TRUE)
+  if(NOT PostgreSQL_TYPE_INCLUDE_DIR)
+    set(PostgreSQL_Server_FOUND FALSE)
+  endif()
+endif()
+
 # Did we find anything?
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 find_package_handle_standard_args(PostgreSQL
-                                  REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR
+                                  REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR
+                                  HANDLE_COMPONENTS
                                   VERSION_VAR PostgreSQL_VERSION_STRING)
 set(PostgreSQL_FOUND  ${POSTGRESQL_FOUND})
 
@@ -269,16 +292,21 @@ endfunction()
 
 # Now try to get the include and library path.
 if(PostgreSQL_FOUND)
+  set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR})
+  if(PostgreSQL_TYPE_INCLUDE_DIR)
+    list(APPEND PostgreSQL_INCLUDE_DIRS ${PostgreSQL_TYPE_INCLUDE_DIR})
+  endif()
+  set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR})
   if (NOT TARGET PostgreSQL::PostgreSQL)
     add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED)
     set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
-      INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIR};${PostgreSQL_TYPE_INCLUDE_DIR}")
+      INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIRS}")
     __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "")
     __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "RELEASE")
     __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "DEBUG")
   endif ()
-  set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR} ${PostgreSQL_TYPE_INCLUDE_DIR} )
-  set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} )
 endif()
 
 mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR)
+
+cmake_policy(POP)
index 4bf54ef..4b1e336 100644 (file)
@@ -7,6 +7,13 @@ FindProtobuf
 
 Locate and configure the Google Protocol Buffers library.
 
+.. versionadded:: 3.6
+  Support for :command:`find_package` version checks.
+
+.. versionchanged:: 3.6
+  All input and output variables use the ``Protobuf_`` prefix.
+  Variables with ``PROTOBUF_`` prefix are still supported for compatibility.
+
 The following variables can be set and are optional:
 
 ``Protobuf_SRC_ROOT_FOLDER``
@@ -19,8 +26,12 @@ The following variables can be set and are optional:
   List of additional directories to be searched for
   imported .proto files.
 ``Protobuf_DEBUG``
+  .. versionadded:: 3.6
+
   Show debug messages.
 ``Protobuf_USE_STATIC_LIBS``
+  .. versionadded:: 3.9
+
   Set to ON to force the use of the static libraries.
   Default is OFF.
 
@@ -30,6 +41,8 @@ Defines the following variables:
   Found the Google Protocol Buffers library
   (libprotobuf & header files)
 ``Protobuf_VERSION``
+  .. versionadded:: 3.6
+
   Version of package found.
 ``Protobuf_INCLUDE_DIRS``
   Include directories for Google Protocol Buffers
@@ -40,7 +53,8 @@ Defines the following variables:
 ``Protobuf_LITE_LIBRARIES``
   The protobuf-lite libraries
 
-The following :prop_tgt:`IMPORTED` targets are also defined:
+.. versionadded:: 3.9
+  The following :prop_tgt:`IMPORTED` targets are also defined:
 
 ``protobuf::libprotobuf``
   The protobuf library.
@@ -49,7 +63,8 @@ The following :prop_tgt:`IMPORTED` targets are also defined:
 ``protobuf::libprotoc``
   The protoc library.
 ``protobuf::protoc``
-  The protoc compiler.
+  .. versionadded:: 3.10
+    The protoc compiler.
 
 The following cache variables are also available to set or use:
 
@@ -101,7 +116,8 @@ Example:
   ``HDRS``
     Variable to define with autogenerated header files
   ``DESCRIPTORS``
-    Variable to define with autogenerated descriptor files, if requested.
+    .. versionadded:: 3.10
+      Variable to define with autogenerated descriptor files, if requested.
   ``EXPORT_MACRO``
     is a macro which should expand to ``__declspec(dllexport)`` or
     ``__declspec(dllimport)`` depending on what is being compiled.
@@ -110,6 +126,8 @@ Example:
 
 .. command:: protobuf_generate_python
 
+  .. versionadded:: 3.4
+
   Add custom commands to process ``.proto`` files to Python::
 
     protobuf_generate_python (<PY> [<ARGN>...])
@@ -204,7 +222,7 @@ function(protobuf_generate)
   foreach(_proto ${protobuf_generate_PROTOS})
     get_filename_component(_abs_file ${_proto} ABSOLUTE)
     get_filename_component(_abs_dir ${_abs_file} DIRECTORY)
-    get_filename_component(_basename ${_proto} NAME_WE)
+    get_filename_component(_basename ${_proto} NAME_WLE)
     file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir})
 
     set(_possible_rel_dir)
index 5fc6a3b..a4b7a03 100644 (file)
@@ -10,25 +10,32 @@ FindPython
 Find Python interpreter, compiler and development environment (include
 directories and libraries).
 
-When a version is requested, it can be specified as a simple value or as a
-range. For a detailed description of version range usage and capabilities,
-refer to the :command:`find_package` command.
+.. versionadded:: 3.19
+  When a version is requested, it can be specified as a simple value or as a
+  range. For a detailed description of version range usage and capabilities,
+  refer to the :command:`find_package` command.
 
 The following components are supported:
 
 * ``Interpreter``: search for Python interpreter.
 * ``Compiler``: search for Python compiler. Only offered by IronPython.
 * ``Development``: search for development artifacts (include directories and
-  libraries). This component includes two sub-components which can be specified
-  independently:
+  libraries).
 
-  * ``Development.Module``: search for artifacts for Python module
-    developments.
-  * ``Development.Embed``: search for artifacts for Python embedding
-    developments.
+  .. versionadded:: 3.18
+    This component includes two sub-components which can be specified
+    independently:
+
+    * ``Development.Module``: search for artifacts for Python module
+      developments.
+    * ``Development.Embed``: search for artifacts for Python embedding
+      developments.
 
 * ``NumPy``: search for NumPy include directories.
 
+.. versionadded:: 3.14
+  Added the ``NumPy`` component.
+
 If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
 
 If component ``Development`` is specified, it implies sub-components
@@ -56,20 +63,30 @@ To manage concurrent versions 3 and 2 of Python, use :module:`FindPython3` and
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets <Imported Targets>`
-(when :prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+.. versionchanged:: 3.14
+  :ref:`Imported Targets <Imported Targets>` are only created when
+  :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.
 
 ``Python::Interpreter``
   Python interpreter. Target defined if component ``Interpreter`` is found.
 ``Python::Compiler``
   Python compiler. Target defined if component ``Compiler`` is found.
+
 ``Python::Module``
+  .. versionadded:: 3.15
+
   Python library for Python module. Target defined if component
   ``Development.Module`` is found.
+
 ``Python::Python``
   Python library for Python embedding. Target defined if component
   ``Development.Embed`` is found.
+
 ``Python::NumPy``
+  .. versionadded:: 3.14
+
   NumPy Python library. Target defined if component ``NumPy`` is found.
 
 Result Variables
@@ -116,7 +133,10 @@ This module will set the following variables in your project
   Information returned by
   ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
   or else ``sysconfig.get_path('platlib')``.
+
 ``Python_SOABI``
+  .. versionadded:: 3.17
+
   Extension suffix for modules.
 
   Information returned by
@@ -125,6 +145,7 @@ This module will set the following variables in your project
   ``python-config --extension-suffix``. If package ``distutils.sysconfig`` is
   not available, ``sysconfig.get_config_var('SOABI')`` or
   ``sysconfig.get_config_var('EXT_SUFFIX')`` are used.
+
 ``Python_Compiler_FOUND``
   System has the Python compiler.
 ``Python_COMPILER``
@@ -132,19 +153,35 @@ This module will set the following variables in your project
 ``Python_COMPILER_ID``
   A short string unique to the compiler. Possible values include:
     * IronPython
+
 ``Python_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
   The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
 ``Python_Development_FOUND``
   System has the Python development artifacts.
+
 ``Python_Development.Module_FOUND``
+  .. versionadded:: 3.18
+
   System has the Python development artifacts for Python module.
+
 ``Python_Development.Embed_FOUND``
+  .. versionadded:: 3.18
+
   System has the Python development artifacts for Python embedding.
+
 ``Python_INCLUDE_DIRS``
+
   The Python include directories.
+
 ``Python_LINK_OPTIONS``
+  .. versionadded:: 3.19
+
   The Python link options. Some configurations require specific link options
   for a correct build and execution.
+
 ``Python_LIBRARIES``
   The Python libraries.
 ``Python_LIBRARY_DIRS``
@@ -159,13 +196,25 @@ This module will set the following variables in your project
   Python minor version.
 ``Python_VERSION_PATCH``
   Python patch version.
+
 ``Python_PyPy_VERSION``
+  .. versionadded:: 3.18
+
   Python PyPy version.
+
 ``Python_NumPy_FOUND``
+  .. versionadded:: 3.14
+
   System has the NumPy.
+
 ``Python_NumPy_INCLUDE_DIRS``
+  .. versionadded:: 3.14
+
   The NumPy include directories.
+
 ``Python_NumPy_VERSION``
+  .. versionadded:: 3.14
+
   The NumPy version.
 
 Hints
@@ -181,6 +230,8 @@ Hints
   * If set to FALSE, search **only** for shared libraries.
 
 ``Python_FIND_ABI``
+  .. versionadded:: 3.16
+
   This variable defines which ABIs, as defined in
   `PEP 3149 <https://www.python.org/dev/peps/pep-3149/>`_, should be searched.
 
@@ -226,6 +277,8 @@ Hints
     each flag is ``OFF`` or ``ANY``.
 
 ``Python_FIND_STRATEGY``
+  .. versionadded:: 3.15
+
   This variable defines how lookup will be done.
   The ``Python_FIND_STRATEGY`` variable can be set to one of the following:
 
@@ -238,6 +291,8 @@ Hints
     This is the default if policy :policy:`CMP0094` is set to ``NEW``.
 
 ``Python_FIND_REGISTRY``
+  .. versionadded:: 3.13
+
   On Windows the ``Python_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
   the ``Python_FIND_REGISTRY`` variable can be set to one of the following:
@@ -248,6 +303,8 @@ Hints
   * ``NEVER``: Never try to use registry.
 
 ``Python_FIND_FRAMEWORK``
+  .. versionadded:: 3.15
+
   On macOS the ``Python_FIND_FRAMEWORK`` variable determine the order of
   preference between Apple-style and unix-style package components.
   This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
@@ -261,6 +318,8 @@ Hints
   variable will be used, if any.
 
 ``Python_FIND_VIRTUALENV``
+  .. versionadded:: 3.15
+
   This variable defines the handling of virtual environments managed by
   ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
   is active (i.e. the ``activate`` script has been evaluated). In this case, it
@@ -279,6 +338,9 @@ Hints
     ``NEVER`` to select preferably the interpreter from the virtual
     environment.
 
+  .. versionadded:: 3.17
+    Added support for ``conda`` environments.
+
   .. note::
 
     If the component ``Development`` is requested, it is **strongly**
@@ -286,6 +348,8 @@ Hints
     result.
 
 ``Python_FIND_IMPLEMENTATIONS``
+  .. versionadded:: 3.18
+
   This variable defines, in an ordered list, the different implementations
   which will be searched. The ``Python_FIND_IMPLEMENTATIONS`` variable can
   hold the following values:
@@ -318,9 +382,26 @@ Hints
     ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available
     through the ``PATH`` variable.
 
+``Python_FIND_UNVERSIONED_NAMES``
+  .. versionadded:: 3.20
+
+  This variable defines how the generic names will be searched. Currently, it
+  only applies to the generic names of the interpreter, namely, ``python3`` or
+  ``python2`` and ``python``.
+  The ``Python_FIND_UNVERSIONED_NAMES`` variable can be set to one of the
+  following values:
+
+  * ``FIRST``: The generic names are searched before the more specialized ones
+    (such as ``python2.5`` for example).
+  * ``LAST``: The generic names are searched after the more specialized ones.
+    This is the default.
+  * ``NEVER``: The generic name are not searched at all.
+
 Artifacts Specification
 ^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.16
+
 To solve special cases, it is possible to specify directly the artifacts by
 setting the following variables:
 
@@ -331,6 +412,8 @@ setting the following variables:
   The path to the compiler.
 
 ``Python_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
   The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
 
 ``Python_LIBRARY``
@@ -367,6 +450,8 @@ specification. So, to enable also interactive specification, module behavior
 can be controlled with the following variable:
 
 ``Python_ARTIFACTS_INTERACTIVE``
+  .. versionadded:: 3.18
+
   Selects the behavior of the module. This is a boolean variable:
 
   * If set to ``TRUE``: Create CMake cache entries for the above artifact
@@ -389,8 +474,9 @@ Python module naming rules::
 
 If the library type is not specified, ``MODULE`` is assumed.
 
-For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
-module suffix will include the ``Python_SOABI`` value, if any.
+.. versionadded:: 3.17
+  For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
+  module suffix will include the ``Python_SOABI`` value, if any.
 #]=======================================================================]
 
 
index 8b2d739..8e70e11 100644 (file)
@@ -337,6 +337,9 @@ function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)
 
   foreach (implementation IN LISTS _PGN_IMPLEMENTATIONS)
     if (implementation STREQUAL "CPython")
+      if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "FIRST")
+        list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)
+      endif()
       foreach (version IN LISTS _PGN_VERSION)
         if (_PGN_WIN32)
           string (REPLACE "." "" version_no_dots ${version})
@@ -386,7 +389,7 @@ function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)
           endif()
         endif()
       endforeach()
-      if (_PGN_INTERPRETER)
+      if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "LAST")
         list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)
       endif()
     elseif (implementation STREQUAL "IronPython")
@@ -1372,9 +1375,22 @@ else()
 endif()
 
 
+# Python naming handling
+if (DEFINED ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES)
+  if (NOT ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES MATCHES "^(FIRST|LAST|NEVER)$")
+    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}: invalid value for '${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES'. 'FIRST', 'LAST' or 'NEVER' expected. 'LAST' will be used instead.")
+    set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)
+  else()
+    set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES ${${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES})
+  endif()
+else()
+  set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)
+endif()
+
+
 # Compute search signature
 # This signature will be used to check validity of cached variables on new search
-set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}")
+set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}")
 if (NOT WIN32)
   string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_USE_STATIC_LIBS}:")
 endif()
@@ -3005,8 +3021,9 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
     unset(_${_PYTHON_PREFIX}_is_prefix)
     foreach (_${_PYTHON_PREFIX}_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
       foreach (_${_PYTHON_PREFIX}_framework IN LISTS _${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_implementation}_FRAMEWORKS)
-        if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^${_${_PYTHON_PREFIX}_framework}")
-          get_filename_component (_${_PYTHON_PREFIX}_framework "${_${_PYTHON_PREFIX}_framework}" DIRECTORY)
+        cmake_path (IS_PREFIX _${_PYTHON_PREFIX}_framework "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" _${_PYTHON_PREFIX}_is_prefix)
+        if (_${_PYTHON_PREFIX}_is_prefix)
+          cmake_path (GET _${_PYTHON_PREFIX}_framework PARENT_PATH _${_PYTHON_PREFIX}_framework)
           set (${_PYTHON_PREFIX}_LINK_OPTIONS "LINKER:-rpath,${_${_PYTHON_PREFIX}_framework}")
           break()
         endif()
index 9cd22e1..bb965b9 100644 (file)
@@ -10,25 +10,32 @@ FindPython2
 Find Python 2 interpreter, compiler and development environment (include
 directories and libraries).
 
-When a version is requested, it can be specified as a simple value or as a
-range. For a detailed description of version range usage and capabilities,
-refer to the :command:`find_package` command.
+.. versionadded:: 3.19
+  When a version is requested, it can be specified as a simple value or as a
+  range. For a detailed description of version range usage and capabilities,
+  refer to the :command:`find_package` command.
 
 The following components are supported:
 
 * ``Interpreter``: search for Python 2 interpreter
 * ``Compiler``: search for Python 2 compiler. Only offered by IronPython.
 * ``Development``: search for development artifacts (include directories and
-  libraries). This component includes two sub-components which can be specified
-  independently:
+  libraries).
 
-  * ``Development.Module``: search for artifacts for Python 2 module
-    developments.
-  * ``Development.Embed``: search for artifacts for Python 2 embedding
-    developments.
+  .. versionadded:: 3.18
+    This component includes two sub-components which can be specified
+    independently:
+
+    * ``Development.Module``: search for artifacts for Python 2 module
+      developments.
+    * ``Development.Embed``: search for artifacts for Python 2 embedding
+      developments.
 
 * ``NumPy``: search for NumPy include directories.
 
+.. versionadded:: 3.14
+  Added the ``NumPy`` component.
+
 If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
 
 If component ``Development`` is specified, it implies sub-components
@@ -57,20 +64,29 @@ for you.
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets <Imported Targets>`
-(when :prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+.. versionchanged:: 3.14
+  :ref:`Imported Targets <Imported Targets>` are only created when
+  :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.
 
 ``Python2::Interpreter``
   Python 2 interpreter. Target defined if component ``Interpreter`` is found.
 ``Python2::Compiler``
   Python 2 compiler. Target defined if component ``Compiler`` is found.
 ``Python2::Module``
+  .. versionadded:: 3.15
+
   Python 2 library for Python module. Target defined if component
   ``Development.Module`` is found.
+
 ``Python2::Python``
   Python 2 library for Python embedding. Target defined if component
   ``Development.Embed`` is found.
+
 ``Python2::NumPy``
+  .. versionadded:: 3.14
+
   NumPy library for Python 2. Target defined if component ``NumPy`` is found.
 
 Result Variables
@@ -124,19 +140,34 @@ This module will set the following variables in your project
 ``Python2_COMPILER_ID``
   A short string unique to the compiler. Possible values include:
     * IronPython
+
 ``Python2_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
   The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
 ``Python2_Development_FOUND``
   System has the Python 2 development artifacts.
+
 ``Python2_Development.Module_FOUND``
+  .. versionadded:: 3.18
+
   System has the Python 2 development artifacts for Python module.
+
 ``Python2_Development.Embed_FOUND``
+  .. versionadded:: 3.18
+
   System has the Python 2 development artifacts for Python embedding.
+
 ``Python2_INCLUDE_DIRS``
   The Python 2 include directories.
+
 ``Python2_LINK_OPTIONS``
+  .. versionadded:: 3.19
+
   The Python 2 link options. Some configurations require specific link options
   for a correct build and execution.
+
 ``Python2_LIBRARIES``
   The Python 2 libraries.
 ``Python2_LIBRARY_DIRS``
@@ -151,13 +182,25 @@ This module will set the following variables in your project
   Python 2 minor version.
 ``Python2_VERSION_PATCH``
   Python 2 patch version.
+
 ``Python2_PyPy_VERSION``
+  .. versionadded:: 3.18
+
   Python 2 PyPy version.
+
 ``Python2_NumPy_FOUND``
+  .. versionadded:: 3.14
+
   System has the NumPy.
+
 ``Python2_NumPy_INCLUDE_DIRS``
+  .. versionadded:: 3.14
+
   The NumPy include directories.
+
 ``Python2_NumPy_VERSION``
+  .. versionadded:: 3.14
+
   The NumPy version.
 
 Hints
@@ -173,6 +216,8 @@ Hints
   * If set to FALSE, search **only** for shared libraries.
 
 ``Python2_FIND_STRATEGY``
+  .. versionadded:: 3.15
+
   This variable defines how lookup will be done.
   The ``Python2_FIND_STRATEGY`` variable can be set to one of the following:
 
@@ -185,6 +230,8 @@ Hints
     This is the default if policy :policy:`CMP0094` is set to ``NEW``.
 
 ``Python2_FIND_REGISTRY``
+  .. versionadded:: 3.13
+
   On Windows the ``Python2_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
   the ``Python2_FIND_REGISTRY`` variable can be set to one of the following:
@@ -195,6 +242,8 @@ Hints
   * ``NEVER``: Never try to use registry.
 
 ``Python2_FIND_FRAMEWORK``
+  .. versionadded:: 3.15
+
   On macOS the ``Python2_FIND_FRAMEWORK`` variable determine the order of
   preference between Apple-style and unix-style package components.
   This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
@@ -208,6 +257,8 @@ Hints
   variable will be used, if any.
 
 ``Python2_FIND_VIRTUALENV``
+  .. versionadded:: 3.15
+
   This variable defines the handling of virtual environments managed by
   ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
   is active (i.e. the ``activate`` script has been evaluated). In this case, it
@@ -226,6 +277,9 @@ Hints
     ``NEVER`` to select preferably the interpreter from the virtual
     environment.
 
+  .. versionadded:: 3.17
+    Added support for ``conda`` environments.
+
   .. note::
 
     If the component ``Development`` is requested, it is **strongly**
@@ -233,6 +287,8 @@ Hints
     result.
 
 ``Python2_FIND_IMPLEMENTATIONS``
+  .. versionadded:: 3.18
+
   This variable defines, in an ordered list, the different implementations
   which will be searched. The ``Python2_FIND_IMPLEMENTATIONS`` variable can
   hold the following values:
@@ -265,9 +321,26 @@ Hints
     ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available
     through the ``PATH`` variable.
 
+``Python2_FIND_UNVERSIONED_NAMES``
+  .. versionadded:: 3.20
+
+  This variable defines how the generic names will be searched. Currently, it
+  only applies to the generic names of the interpreter, namely, ``python2`` and
+  ``python``.
+  The ``Python2_FIND_UNVERSIONED_NAMES`` variable can be set to one of the
+  following values:
+
+  * ``FIRST``: The generic names are searched before the more specialized ones
+    (such as ``python2.5`` for example).
+  * ``LAST``: The generic names are searched after the more specialized ones.
+    This is the default.
+  * ``NEVER``: The generic name are not searched at all.
+
 Artifacts Specification
 ^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.16
+
 To solve special cases, it is possible to specify directly the artifacts by
 setting the following variables:
 
@@ -278,6 +351,8 @@ setting the following variables:
   The path to the compiler.
 
 ``Python2_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
   The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
 
 ``Python2_LIBRARY``
@@ -314,6 +389,8 @@ specification. So, to enable also interactive specification, module behavior
 can be controlled with the following variable:
 
 ``Python2_ARTIFACTS_INTERACTIVE``
+  .. versionadded:: 3.18
+
   Selects the behavior of the module. This is a boolean variable:
 
   * If set to ``TRUE``: Create CMake cache entries for the above artifact
index c79d482..f826fcf 100644 (file)
@@ -10,25 +10,32 @@ FindPython3
 Find Python 3 interpreter, compiler and development environment (include
 directories and libraries).
 
-When a version is requested, it can be specified as a simple value or as a
-range. For a detailed description of version range usage and capabilities,
-refer to the :command:`find_package` command.
+.. versionadded:: 3.19
+  When a version is requested, it can be specified as a simple value or as a
+  range. For a detailed description of version range usage and capabilities,
+  refer to the :command:`find_package` command.
 
 The following components are supported:
 
 * ``Interpreter``: search for Python 3 interpreter
 * ``Compiler``: search for Python 3 compiler. Only offered by IronPython.
 * ``Development``: search for development artifacts (include directories and
-  libraries). This component includes two sub-components which can be specified
-  independently:
+  libraries).
 
-  * ``Development.Module``: search for artifacts for Python 3 module
-    developments.
-  * ``Development.Embed``: search for artifacts for Python 3 embedding
-    developments.
+  .. versionadded:: 3.18
+    This component includes two sub-components which can be specified
+    independently:
+
+    * ``Development.Module``: search for artifacts for Python 3 module
+      developments.
+    * ``Development.Embed``: search for artifacts for Python 3 embedding
+      developments.
 
 * ``NumPy``: search for NumPy include directories.
 
+.. versionadded:: 3.14
+  Added the ``NumPy`` component.
+
 If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
 
 If component ``Development`` is specified, it implies sub-components
@@ -57,20 +64,30 @@ for you.
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets <Imported Targets>`
-(when :prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+.. versionchanged:: 3.14
+  :ref:`Imported Targets <Imported Targets>` are only created when
+  :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.
 
 ``Python3::Interpreter``
   Python 3 interpreter. Target defined if component ``Interpreter`` is found.
 ``Python3::Compiler``
   Python 3 compiler. Target defined if component ``Compiler`` is found.
+
 ``Python3::Module``
+  .. versionadded:: 3.15
+
   Python 3 library for Python module. Target defined if component
   ``Development.Module`` is found.
+
 ``Python3::Python``
   Python 3 library for Python embedding. Target defined if component
   ``Development.Embed`` is found.
+
 ``Python3::NumPy``
+  .. versionadded:: 3.14
+
   NumPy library for Python 3. Target defined if component ``NumPy`` is found.
 
 Result Variables
@@ -117,7 +134,10 @@ This module will set the following variables in your project
   Information returned by
   ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``
   or else ``sysconfig.get_path('platlib')``.
+
 ``Python3_SOABI``
+  .. versionadded:: 3.17
+
   Extension suffix for modules.
 
   Information returned by
@@ -126,6 +146,7 @@ This module will set the following variables in your project
   ``python3-config --extension-suffix``. If package ``distutils.sysconfig`` is
   not available, ``sysconfig.get_config_var('SOABI')`` or
   ``sysconfig.get_config_var('EXT_SUFFIX')`` are used.
+
 ``Python3_Compiler_FOUND``
   System has the Python 3 compiler.
 ``Python3_COMPILER``
@@ -133,19 +154,36 @@ This module will set the following variables in your project
 ``Python3_COMPILER_ID``
   A short string unique to the compiler. Possible values include:
     * IronPython
+
 ``Python3_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
   The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
 ``Python3_Development_FOUND``
+
   System has the Python 3 development artifacts.
+
 ``Python3_Development.Module_FOUND``
+  .. versionadded:: 3.18
+
   System has the Python 3 development artifacts for Python module.
+
 ``Python3_Development.Embed_FOUND``
+  .. versionadded:: 3.18
+
   System has the Python 3 development artifacts for Python embedding.
+
 ``Python3_INCLUDE_DIRS``
+
   The Python 3 include directories.
+
 ``Python3_LINK_OPTIONS``
+  .. versionadded:: 3.19
+
   The Python 3 link options. Some configurations require specific link options
   for a correct build and execution.
+
 ``Python3_LIBRARIES``
   The Python 3 libraries.
 ``Python3_LIBRARY_DIRS``
@@ -160,13 +198,25 @@ This module will set the following variables in your project
   Python 3 minor version.
 ``Python3_VERSION_PATCH``
   Python 3 patch version.
+
 ``Python3_PyPy_VERSION``
+  .. versionadded:: 3.18
+
   Python 3 PyPy version.
+
 ``Python3_NumPy_FOUND``
+  .. versionadded:: 3.14
+
   System has the NumPy.
+
 ``Python3_NumPy_INCLUDE_DIRS``
+  .. versionadded:: 3.14
+
   The NumPy include directories.
+
 ``Python3_NumPy_VERSION``
+  .. versionadded:: 3.14
+
   The NumPy version.
 
 Hints
@@ -182,6 +232,8 @@ Hints
   * If set to FALSE, search **only** for shared libraries.
 
 ``Python3_FIND_ABI``
+  .. versionadded:: 3.16
+
   This variable defines which ABIs, as defined in
   `PEP 3149 <https://www.python.org/dev/peps/pep-3149/>`_, should be searched.
 
@@ -223,6 +275,8 @@ Hints
     each flag is ``OFF`` or ``ANY``.
 
 ``Python3_FIND_STRATEGY``
+  .. versionadded:: 3.15
+
   This variable defines how lookup will be done.
   The ``Python3_FIND_STRATEGY`` variable can be set to one of the following:
 
@@ -235,6 +289,8 @@ Hints
     This is the default if policy :policy:`CMP0094` is set to ``NEW``.
 
 ``Python3_FIND_REGISTRY``
+  .. versionadded:: 3.13
+
   On Windows the ``Python3_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
   The ``Python3_FIND_REGISTRY`` variable can be set to one of the following:
@@ -245,6 +301,8 @@ Hints
   * ``NEVER``: Never try to use registry.
 
 ``Python3_FIND_FRAMEWORK``
+  .. versionadded:: 3.15
+
   On macOS the ``Python3_FIND_FRAMEWORK`` variable determine the order of
   preference between Apple-style and unix-style package components.
   This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
@@ -258,6 +316,8 @@ Hints
   variable will be used, if any.
 
 ``Python3_FIND_VIRTUALENV``
+  .. versionadded:: 3.15
+
   This variable defines the handling of virtual environments managed by
   ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
   is active (i.e. the ``activate`` script has been evaluated). In this case, it
@@ -276,6 +336,9 @@ Hints
     ``NEVER`` to select preferably the interpreter from the virtual
     environment.
 
+  .. versionadded:: 3.17
+    Added support for ``conda`` environments.
+
   .. note::
 
     If the component ``Development`` is requested, it is **strongly**
@@ -283,6 +346,8 @@ Hints
     result.
 
 ``Python3_FIND_IMPLEMENTATIONS``
+  .. versionadded:: 3.18
+
   This variable defines, in an ordered list, the different implementations
   which will be searched. The ``Python3_FIND_IMPLEMENTATIONS`` variable can
   hold the following values:
@@ -315,9 +380,26 @@ Hints
     ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available
     through the ``PATH`` variable.
 
+``Python3_FIND_UNVERSIONED_NAMES``
+  .. versionadded:: 3.20
+
+  This variable defines how the generic names will be searched. Currently, it
+  only applies to the generic names of the interpreter, namely, ``python3`` and
+  ``python``.
+  The ``Python3_FIND_UNVERSIONED_NAMES`` variable can be set to one of the
+  following values:
+
+  * ``FIRST``: The generic names are searched before the more specialized ones
+    (such as ``python3.5`` for example).
+  * ``LAST``: The generic names are searched after the more specialized ones.
+    This is the default.
+  * ``NEVER``: The generic name are not searched at all.
+
 Artifacts Specification
 ^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.16
+
 To solve special cases, it is possible to specify directly the artifacts by
 setting the following variables:
 
@@ -328,6 +410,8 @@ setting the following variables:
   The path to the compiler.
 
 ``Python3_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
   The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
 
 ``Python3_LIBRARY``
@@ -364,6 +448,8 @@ specification. So, to enable also interactive specification, module behavior
 can be controlled with the following variable:
 
 ``Python3_ARTIFACTS_INTERACTIVE``
+  .. versionadded:: 3.18
+
   Selects the behavior of the module. This is a boolean variable:
 
   * If set to ``TRUE``: Create CMake cache entries for the above artifact
@@ -386,8 +472,9 @@ of Python module naming rules::
 
 If the library type is not specified, ``MODULE`` is assumed.
 
-For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
-module suffix will include the ``Python3_SOABI`` value, if any.
+.. versionadded:: 3.17
+  For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
+  module suffix will include the ``Python3_SOABI`` value, if any.
 #]=======================================================================]
 
 
index d6a0662..44a1f41 100644 (file)
@@ -5,14 +5,14 @@
 FindQt
 ------
 
+.. deprecated:: 3.14
+  This module is available only if policy :policy:`CMP0084` is not set to ``NEW``.
+
 Searches for all installed versions of Qt3 or Qt4.
 
 This module cannot handle Qt5 or any later versions.
 For those, see :manual:`cmake-qt(7)`.
 
-This module exists for the :command:`find_package` command only if
-policy :policy:`CMP0084` is not set to ``NEW``.
-
 This module should only be used if your project can work with multiple
 versions of Qt.  If not, you should just directly use FindQt4 or
 FindQt3.  If multiple versions of Qt are found on the machine, then
index b5bc8b1..da82e59 100644 (file)
@@ -56,7 +56,9 @@ file(GLOB GLOB_PATHS /usr/lib/qt-3*)
 foreach(GLOB_PATH ${GLOB_PATHS})
   list(APPEND GLOB_PATHS_BIN "${GLOB_PATH}/bin")
 endforeach()
-find_path(QT_INCLUDE_DIR qt.h
+find_path(QT_INCLUDE_DIR
+  NAMES qt.h
+  PATHS
   "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]/include/Qt"
   "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]/include/Qt"
   "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]/include/Qt"
@@ -179,7 +181,8 @@ if(QT_UIC_EXECUTABLE)
 endif()
 
 if (WIN32)
-  find_library(QT_QTMAIN_LIBRARY qtmain
+  find_library(QT_QTMAIN_LIBRARY
+    NAMES qtmain
     HINTS
       ENV QTDIR
       "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]"
index d12f825..ee07f83 100644 (file)
@@ -37,7 +37,8 @@ This module will set the following variables in your project:
 ``Ruby_INCLUDE_DIRS``
   include dirs to be used when using the ruby library
 ``Ruby_LIBRARIES``
-  libraries needed to use ruby from C.
+  .. versionadded:: 3.18
+    libraries needed to use ruby from C.
 ``Ruby_VERSION``
   the version of ruby which was found, e.g. "1.8.7"
 ``Ruby_VERSION_MAJOR``
@@ -47,9 +48,10 @@ This module will set the following variables in your project:
 ``Ruby_VERSION_PATCH``
   Ruby patch version.
 
-
-The following variables are also provided for compatibility reasons,
-don't use them in new code:
+.. versionchanged:: 3.18
+  Previous versions of CMake used the ``RUBY_`` prefix for all variables.
+  The following variables are provided for compatibility reasons,
+  don't use them in new code:
 
 ``RUBY_EXECUTABLE``
   same as Ruby_EXECUTABLE.
@@ -67,6 +69,8 @@ don't use them in new code:
 Hints
 ^^^^^
 
+.. versionadded:: 3.18
+
 ``Ruby_ROOT_DIR``
   Define the root directory of a Ruby installation.
 
index 59eddbb..c68e18d 100644 (file)
@@ -11,6 +11,8 @@ Locate the SDL library
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.19
+
 This module defines the following :prop_tgt:`IMPORTED` target:
 
 ``SDL::SDL``
@@ -36,6 +38,10 @@ This module will set the following variables in your project:
 ``SDL_VERSION_PATCH``
   SDL patch version
 
+.. versionadded:: 3.19
+  Added the ``SDL_INCLUDE_DIRS``, ``SDL_LIBRARIES`` and ``SDL_VERSION[_<PART>]``
+  variables.
+
 Cache variables
 ^^^^^^^^^^^^^^^
 
@@ -63,6 +69,8 @@ This module responds to the flag:
 Obsolete variables
 ^^^^^^^^^^^^^^^^^^
 
+.. deprecated:: 3.19
+
 These variables are obsolete and provided for backwards compatibility:
 
 ``SDL_VERSION_STRING``
index 87a3894..4c7ad89 100644 (file)
@@ -7,14 +7,17 @@ FindSWIG
 
 Find the Simplified Wrapper and Interface Generator (SWIG_) executable.
 
-This module finds an installed SWIG and determines its version. If a
-``COMPONENTS`` or ``OPTIONAL_COMPONENTS`` argument is given to the
-:command:`find_package` command, it will also determine supported target
-languages.
-
-When a version is requested, it can be specified as a simple value or as a
-range. For a detailed description of version range usage and capabilities,
-refer to the :command:`find_package` command.
+This module finds an installed SWIG and determines its version.
+
+.. versionadded:: 3.18
+  If a ``COMPONENTS`` or ``OPTIONAL_COMPONENTS`` argument is given to the
+  :command:`find_package` command, it will also determine supported target
+  languages.
+
+.. versionadded:: 3.19
+  When a version is requested, it can be specified as a simple value or as a
+  range. For a detailed description of version range usage and capabilities,
+  refer to the :command:`find_package` command.
 
 The module defines the following variables:
 
index 91d1410..9a17fdb 100644 (file)
@@ -47,7 +47,8 @@ to cmake using Squish >= 4.x:
      AUT targetName SUITE suiteName TEST squishTestName
      [SETTINGSGROUP group] [PRE_COMMAND command] [POST_COMMAND command] )
 
-
+.. versionchanged:: 3.18
+  In previous CMake versions, this function was named ``squish_v4_add_test``.
 
 The arguments have the following meaning:
 
index 07cb770..7a9c440 100644 (file)
@@ -31,9 +31,12 @@ If the command line client executable is found two macros are defined:
 ``Subversion_WC_INFO`` extracts information of a subversion working copy at a
 given location.  This macro defines the following variables if running
 Subversion's ``info`` command on ``<dir>`` succeeds; otherwise a
-``SEND_ERROR`` message is generated. The error can be ignored by providing the
-``IGNORE_SVN_FAILURE`` option, which causes these variables to remain
-undefined.
+``SEND_ERROR`` message is generated.
+
+.. versionadded:: 3.13
+  The error can be ignored by providing the
+  ``IGNORE_SVN_FAILURE`` option, which causes these variables to remain
+  undefined.
 
 ::
 
index 3b74c94..ed2657c 100644 (file)
@@ -17,12 +17,16 @@ imported target, as described below.
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.5
+
 This module defines the following :prop_tgt:`IMPORTED` targets:
 
 ``TIFF::TIFF``
   The TIFF library, if found.
 
 ``TIFF::CXX``
+  .. versionadded:: 3.19
+
   The C++ wrapper libtiffxx, if requested by the `COMPONENTS CXX` option,
   if the compiler is not MSVC (which includes the C++ wrapper in libtiff),
   and if found.
@@ -56,6 +60,9 @@ The following cache variables may also be set:
   the path to the TIFFXX library for release configurations
 ``TIFFXX_LIBRARY_DEBUG``
   the path to the TIFFXX library for debug configurations
+
+.. versionadded:: 3.4
+  Debug and Release variants are found separately.
 #]=======================================================================]
 
 cmake_policy(PUSH)
index e3e6591..87e88bc 100644 (file)
@@ -10,6 +10,8 @@ This module determines the thread library of the system.
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.1
+
 This module defines the following :prop_tgt:`IMPORTED` target:
 
 ``Threads::Threads``
@@ -38,6 +40,8 @@ Variables Affecting Behavior
 
 .. variable:: THREADS_PREFER_PTHREAD_FLAG
 
+  .. versionadded:: 3.1
+
   If the use of the -pthread compiler and linker flag is preferred then
   the caller can set this variable to TRUE. The compiler flag can only be
   used with the imported target. Use of both the imported target as well
index 0ec6013..ceb1921 100644 (file)
@@ -16,8 +16,9 @@ IMPORTED Targets
 This module defines :prop_tgt:`IMPORTED` target ``Vulkan::Vulkan``, if
 Vulkan has been found.
 
-This module defines :prop_tgt:`IMPORTED` target ``Vulkan::glslc``, if
-Vulkan and the GLSLC SPIR-V compiler has been found.
+.. versionadded:: 3.19
+  This module defines :prop_tgt:`IMPORTED` target ``Vulkan::glslc``, if
+  Vulkan and the GLSLC SPIR-V compiler has been found.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -37,6 +38,8 @@ The module will also define three cache variables::
 Hints
 ^^^^^
 
+.. versionadded:: 3.18
+
 The ``VULKAN_SDK`` environment variable optionally specifies the
 location of the Vulkan SDK root directory for the given
 architecture. It is typically set by sourcing the toplevel
index a865597..d480fc4 100644 (file)
@@ -17,6 +17,9 @@ Try to find X11 on UNIX systems. The following values are defined
 
 and also the following more fine grained variables and targets:
 
+.. versionadded:: 3.14
+  Imported targets.
+
 ::
 
   X11_ICE_INCLUDE_PATH,          X11_ICE_LIB,        X11_ICE_FOUND,        X11::ICE
@@ -62,6 +65,23 @@ and also the following more fine grained variables and targets:
   X11_Xshape_INCLUDE_PATH,       (in X11_Xext_LIB),  X11_Xshape_FOUND
   X11_XSync_INCLUDE_PATH,        (in X11_Xext_LIB),  X11_XSync_FOUND
   X11_Xaw_INCLUDE_PATH,          X11_Xaw_LIB         X11_Xaw_FOUND         X11::Xaw
+
+.. versionadded:: 3.14
+  Renamed ``Xxf86misc``, ``X11_Xxf86misc``, ``X11_Xxf86vm``, ``X11_xkbfile``,
+  ``X11_Xtst``, and ``X11_Xss`` libraries to match their file names.
+  Deprecated the ``X11_Xinput`` library.  Old names are still available
+  for compatibility.
+
+.. versionadded:: 3.14
+  Added the ``X11_Xext_INCLUDE_PATH`` variable.
+
+.. versionadded:: 3.18
+  Added the ``xcb``, ``X11-xcb``, ``xcb-icccm``, ``xcb-xkb``, ``xkbcommon``,
+  and ``xkbcommon-X11`` libraries.
+
+.. versionadded:: 3.19
+  Added the ``Xaw``, ``xcb_util``, and ``xcb_xfixes`` libraries.
+
 #]=======================================================================]
 
 if (UNIX)
index abe18c0..af1b0b4 100644 (file)
@@ -12,6 +12,8 @@ Find the Apache Xerces-C++ validating XML parser headers and libraries.
 Imported targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.5
+
 This module defines the following :prop_tgt:`IMPORTED` targets:
 
 ``XercesC::XercesC``
@@ -40,6 +42,9 @@ The following cache variables may also be set:
   the directory containing the Xerces headers
 ``XercesC_LIBRARY``
   the Xerces library
+
+.. versionadded:: 3.4
+  Debug and Release variants are found separately.
 #]=======================================================================]
 
 # Written by Roger Leigh <rleigh@codelibre.net>
index 79e2313..5778b03 100644 (file)
@@ -10,6 +10,8 @@ Find the native ZLIB includes and library.
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
+.. versionadded:: 3.1
+
 This module defines :prop_tgt:`IMPORTED` target ``ZLIB::ZLIB``, if
 ZLIB has been found.
 
@@ -32,6 +34,9 @@ This module defines the following variables:
   ZLIB_VERSION_PATCH  - The patch version of zlib
   ZLIB_VERSION_TWEAK  - The tweak version of zlib
 
+.. versionadded:: 3.4
+  Debug and Release variants are found separately.
+
 Backward Compatibility
 ^^^^^^^^^^^^^^^^^^^^^^
 
index eab09f1..63af9b6 100644 (file)
@@ -14,6 +14,12 @@ package:
 
 find_package(wxWidgets COMPONENTS core base ... OPTIONAL_COMPONENTS net ...)
 
+.. versionadded:: 3.4
+  Support for :command:`find_package` version argument; ``webview`` component.
+
+.. versionadded:: 3.14
+  ``OPTIONAL_COMPONENTS`` support.
+
 There are two search branches: a windows style and a unix style.  For
 windows, the following variables are searched for and set to defaults
 in case of multiple choices.  Change them if the defaults are not
@@ -82,6 +88,9 @@ and unix style:
                                "`wx-config --cxxflags`".
   wxWidgets_USE_FILE         - Convenience include file.
 
+.. versionadded:: 3.11
+  The following environment variables can be used as hints: ``WX_CONFIG``,
+  ``WXRC_CMD``.
 
 
 Sample usage:
index 547346b..733c723 100644 (file)
@@ -343,6 +343,13 @@ function(FortranCInterface_VERIFY)
     set(_desc "Verifying Fortran/${lang} Compiler Compatibility")
     message(CHECK_START "${_desc}")
 
+    cmake_policy(GET CMP0056 _FortranCInterface_CMP0056)
+    if(_FortranCInterface_CMP0056 STREQUAL "NEW")
+      set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}")
+    else()
+      set(_FortranCInterface_EXE_LINKER_FLAGS "")
+    endif()
+
     # Build a sample project which reports symbols.
     set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
     try_compile(FortranCInterface_VERIFY_${lang}_COMPILED
@@ -358,6 +365,7 @@ function(FortranCInterface_VERIFY)
                  "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}"
                  "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}"
                  "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
+                 ${_FortranCInterface_EXE_LINKER_FLAGS}
       OUTPUT_VARIABLE _output)
     file(WRITE "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" "${_output}")
 
index c75067b..998faf1 100644 (file)
@@ -26,6 +26,14 @@ unset(FortranCInterface_VERIFIED_CXX CACHE)
 
 set(_result)
 
+cmake_policy(GET CMP0056 _FortranCInterface_CMP0056)
+if(_FortranCInterface_CMP0056 STREQUAL "NEW")
+  set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}")
+else()
+  set(_FortranCInterface_EXE_LINKER_FLAGS "")
+endif()
+unset(_FortranCInterface_CMP0056)
+
 # Build a sample project which reports symbols.
 set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
 try_compile(FortranCInterface_COMPILED
@@ -38,9 +46,11 @@ try_compile(FortranCInterface_COMPILED
     "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
     "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}"
     "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
+    ${_FortranCInterface_EXE_LINKER_FLAGS}
   OUTPUT_VARIABLE FortranCInterface_OUTPUT)
 set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED})
 unset(FortranCInterface_COMPILED CACHE)
+unset(_FortranCInterface_EXE_LINKER_FLAGS)
 
 # Locate the sample project executable.
 set(FortranCInterface_EXE)
index 13d067a..37869fb 100644 (file)
@@ -46,7 +46,8 @@ where ``<dir>`` is one of:
 ``LOCALSTATEDIR``
   modifiable single-machine data (``var``)
 ``RUNSTATEDIR``
-  run-time variable data (``LOCALSTATEDIR/run``)
+  .. versionadded:: 3.9
+    run-time variable data (``LOCALSTATEDIR/run``)
 ``LIBDIR``
   object code libraries (``lib`` or ``lib64``
   or ``lib/<multiarch-tuple>`` on Debian)
@@ -73,6 +74,8 @@ used and the value will appear in the cache for editing by the user.
 Special Cases
 ^^^^^^^^^^^^^
 
+.. versionadded:: 3.4
+
 The following values of :variable:`CMAKE_INSTALL_PREFIX` are special:
 
 ``/``
@@ -113,7 +116,9 @@ Macros
 
   ::
 
-    GNUInstallDirs_get_absolute_install_dir(absvar var)
+    GNUInstallDirs_get_absolute_install_dir(absvar var dirname)
+
+  .. versionadded:: 3.7
 
   Set the given variable ``absvar`` to the absolute path contained
   within the variable ``var``.  This is to allow the computation of an
@@ -121,7 +126,12 @@ Macros
   above.  While this macro is used to compute the various
   ``CMAKE_INSTALL_FULL_<dir>`` variables, it is exposed publicly to
   allow users who create additional path variables to also compute
-  absolute paths where necessary, using the same logic.
+  absolute paths where necessary, using the same logic.  ``dirname`` is
+  the directory name to get, e.g. ``BINDIR``.
+
+  .. versionchanged:: 3.20
+    Added the ``<dirname>`` parameter.  Previous versions of CMake passed
+    this value through the variable ``${dir}``.
 #]=======================================================================]
 
 cmake_policy(PUSH)
@@ -334,13 +344,25 @@ mark_as_advanced(
   )
 
 macro(GNUInstallDirs_get_absolute_install_dir absvar var)
+  set(GGAID_extra_args ${ARGN})
+  list(LENGTH GGAID_extra_args GGAID_extra_arg_count)
+  if(GGAID_extra_arg_count GREATER 0)
+    list(GET GGAID_extra_args 0 GGAID_dir)
+  else()
+    # Historical behaviour: use ${dir} from caller's scope
+    set(GGAID_dir "${dir}")
+    message(AUTHOR_WARNING
+      "GNUInstallDirs_get_absolute_install_dir called without third argument. "
+      "Using \${dir} from the caller's scope for compatibility with CMake 3.19 and below.")
+  endif()
+
   if(NOT IS_ABSOLUTE "${${var}}")
     # Handle special cases:
     # - CMAKE_INSTALL_PREFIX == /
     # - CMAKE_INSTALL_PREFIX == /usr
     # - CMAKE_INSTALL_PREFIX == /opt/...
     if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/")
-      if("${dir}" STREQUAL "SYSCONFDIR" OR "${dir}" STREQUAL "LOCALSTATEDIR" OR "${dir}" STREQUAL "RUNSTATEDIR")
+      if("${GGAID_dir}" STREQUAL "SYSCONFDIR" OR "${GGAID_dir}" STREQUAL "LOCALSTATEDIR" OR "${GGAID_dir}" STREQUAL "RUNSTATEDIR")
         set(${absvar} "/${${var}}")
       else()
         if (NOT "${${var}}" MATCHES "^usr/")
@@ -349,13 +371,13 @@ macro(GNUInstallDirs_get_absolute_install_dir absvar var)
         set(${absvar} "/${${var}}")
       endif()
     elseif("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
-      if("${dir}" STREQUAL "SYSCONFDIR" OR "${dir}" STREQUAL "LOCALSTATEDIR" OR "${dir}" STREQUAL "RUNSTATEDIR")
+      if("${GGAID_dir}" STREQUAL "SYSCONFDIR" OR "${GGAID_dir}" STREQUAL "LOCALSTATEDIR" OR "${GGAID_dir}" STREQUAL "RUNSTATEDIR")
         set(${absvar} "/${${var}}")
       else()
         set(${absvar} "${CMAKE_INSTALL_PREFIX}/${${var}}")
       endif()
     elseif("${CMAKE_INSTALL_PREFIX}" MATCHES "^/opt/.*")
-      if("${dir}" STREQUAL "SYSCONFDIR" OR "${dir}" STREQUAL "LOCALSTATEDIR" OR "${dir}" STREQUAL "RUNSTATEDIR")
+      if("${GGAID_dir}" STREQUAL "SYSCONFDIR" OR "${GGAID_dir}" STREQUAL "LOCALSTATEDIR" OR "${GGAID_dir}" STREQUAL "RUNSTATEDIR")
         set(${absvar} "/${${var}}${CMAKE_INSTALL_PREFIX}")
       else()
         set(${absvar} "${CMAKE_INSTALL_PREFIX}/${${var}}")
@@ -366,6 +388,10 @@ macro(GNUInstallDirs_get_absolute_install_dir absvar var)
   else()
     set(${absvar} "${${var}}")
   endif()
+
+  unset(GGAID_dir)
+  unset(GGAID_extra_arg_count)
+  unset(GGAID_extra_args)
 endmacro()
 
 # Result directories
@@ -388,7 +414,7 @@ foreach(dir
     MANDIR
     DOCDIR
     )
-  GNUInstallDirs_get_absolute_install_dir(CMAKE_INSTALL_FULL_${dir} CMAKE_INSTALL_${dir})
+  GNUInstallDirs_get_absolute_install_dir(CMAKE_INSTALL_FULL_${dir} CMAKE_INSTALL_${dir} ${dir})
 endforeach()
 
 cmake_policy(POP)
index e4481f6..a9a9c59 100644 (file)
@@ -9,6 +9,9 @@ Function for generation of export macros for libraries
 
 This module provides the function ``GENERATE_EXPORT_HEADER()``.
 
+.. versionadded:: 3.12
+  Added support for C projects.  Previous versions supported C++ project only.
+
 The ``GENERATE_EXPORT_HEADER`` function can be used to generate a file
 suitable for preprocessor inclusion which contains EXPORT macros to be
 used in library classes::
@@ -27,7 +30,6 @@ used in library classes::
              [CUSTOM_CONTENT_FROM_VARIABLE <variable>]
    )
 
-
 The target properties :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>`
 and :prop_tgt:`VISIBILITY_INLINES_HIDDEN` can be used to add the appropriate
 compile flags for targets.  See the documentation of those target properties,
@@ -170,20 +172,30 @@ For example:
 
 Generates the macros ``VTK_SOMELIB_EXPORT`` etc.
 
+.. versionadded:: 3.1
+  Library target can be an ``OBJECT`` library.
+
+.. versionadded:: 3.7
+  Added the ``CUSTOM_CONTENT_FROM_VARIABLE`` option.
+
+.. versionadded:: 3.11
+  Added the ``INCLUDE_GUARD_NAME`` option.
+
 ::
 
    ADD_COMPILER_EXPORT_FLAGS( [<output_variable>] )
 
+.. deprecated:: 3.0
+  Set the target properties
+  :prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>` and
+  :prop_tgt:`VISIBILITY_INLINES_HIDDEN` instead.
+
 The ``ADD_COMPILER_EXPORT_FLAGS`` function adds ``-fvisibility=hidden`` to
 :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` if supported, and is a no-op
 on Windows which does not need extra compiler flags for exporting support.
 You may optionally pass a single argument to ``ADD_COMPILER_EXPORT_FLAGS``
 that will be populated with the ``CXX_FLAGS`` required to enable visibility
 support for the compiler/architecture in use.
-
-This function is deprecated.  Set the target properties
-:prop_tgt:`CXX_VISIBILITY_PRESET <<LANG>_VISIBILITY_PRESET>` and
-:prop_tgt:`VISIBILITY_INLINES_HIDDEN` instead.
 #]=======================================================================]
 
 include(CheckCCompilerFlag)
@@ -209,7 +221,7 @@ macro(_test_compiler_hidden_visibility)
     set(GCC_TOO_OLD TRUE)
   elseif(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2")
     set(GCC_TOO_OLD TRUE)
-  elseif(CMAKE_CXX_COMPILER_ID MATCHES Intel AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0")
+  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0")
     set(_INTEL_TOO_OLD TRUE)
   endif()
 
@@ -220,7 +232,7 @@ macro(_test_compiler_hidden_visibility)
       AND NOT WIN32
       AND NOT CYGWIN
       AND NOT CMAKE_CXX_COMPILER_ID MATCHES XL
-      AND NOT CMAKE_CXX_COMPILER_ID MATCHES PGI
+      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)
@@ -242,7 +254,7 @@ macro(_test_compiler_has_deprecated)
       OR CMAKE_CXX_COMPILER_ID MATCHES Embarcadero
       OR CMAKE_CXX_COMPILER_ID MATCHES HP
       OR GCC_TOO_OLD
-      OR CMAKE_CXX_COMPILER_ID MATCHES PGI
+      OR CMAKE_CXX_COMPILER_ID MATCHES "^(PGI|NVHPC)$"
       OR CMAKE_CXX_COMPILER_ID MATCHES Watcom)
     set(COMPILER_HAS_DEPRECATED "" CACHE INTERNAL
       "Compiler support for a deprecated attribute")
index 2d4765a..ed5c38b 100644 (file)
@@ -25,6 +25,9 @@ files:
    ldd (Linux/Unix)
    otool (Mac OSX)
 
+.. versionchanged:: 3.16
+  The tool specified by ``CMAKE_OBJDUMP`` will be used, if set.
+
 The following functions are provided by this module:
 
 ::
@@ -42,9 +45,6 @@ The following functions are provided by this module:
      (projects can override with gp_resolved_file_type_override)
    gp_file_type
 
-Requires CMake 2.6 or greater because it uses function, break, return
-and PARENT_SCOPE.
-
 ::
 
   GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
@@ -67,8 +67,9 @@ searched first when a target without any path info is given.  Then
 standard system locations are also searched: PATH, Framework
 locations, /usr/lib...
 
-The variable GET_PREREQUISITES_VERBOSE can be set to true to enable verbose
-output.
+.. versionadded:: 3.14
+  The variable GET_PREREQUISITES_VERBOSE can be set to true to enable verbose
+  output.
 
 ::
 
index 057b29d..2ea9e74 100644 (file)
@@ -101,6 +101,8 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
     with the list of discovered test cases.  This allows the caller to do
     things like manipulate test properties of the discovered tests.
 
+  Usage example:
+
   .. code-block:: cmake
 
     include(GoogleTest)
@@ -157,6 +159,8 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
                          [DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
     )
 
+  .. versionadded:: 3.10
+
   ``gtest_discover_tests()`` sets up a post-build command on the test executable
   that generates the list of tests by parsing the output from running the test
   with the ``--gtest_list_tests`` argument.  Compared to the source parsing
@@ -223,6 +227,8 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
     Note that this variable is only available in CTest.
 
   ``DISCOVERY_TIMEOUT num``
+    .. versionadded:: 3.10.3
+
     Specifies how long (in seconds) CMake will wait for the test to enumerate
     available tests.  If the test takes longer than this, discovery (and your
     build) will fail.  Most test executables will enumerate their tests very
@@ -241,6 +247,8 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
       and 3.10.2 has not been preserved.
 
   ``XML_OUTPUT_DIR dir``
+    .. versionadded:: 3.18
+
     If specified, the parameter is passed along with ``--gtest_output=xml:``
     to test executable. The actual file name is the same as the test target,
     including prefix and suffix. This should be used instead of
@@ -248,6 +256,8 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
     XML result output when using parallel test execution.
 
   ``DISCOVERY_MODE``
+    .. versionadded:: 3.18
+
     Provides greater control over when ``gtest_discover_tests()`` performs test
     discovery. By default, ``POST_BUILD`` sets up a post-build command
     to perform test discovery at build time. In certain scenarios, like
index 883e1f4..0f79c9a 100644 (file)
@@ -136,7 +136,7 @@ function(gtest_discover_tests_impl)
           ${TEST_XML_OUTPUT_PARAM}
           ${extra_args}
         )
-        if(suite MATCHES "^DISABLED" OR test MATCHES "^DISABLED")
+        if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_")
           add_command(set_tests_properties
             "${testname}"
             PROPERTIES DISABLED TRUE
index 29d1ec0..2d08e08 100644 (file)
@@ -27,14 +27,17 @@ may be set prior to including the module to adjust behavior:
   tools even if the release runtime libraries are also available.
 
 ``CMAKE_INSTALL_UCRT_LIBRARIES``
+  .. versionadded:: 3.6
+
   Set to TRUE to install the Windows Universal CRT libraries for
   app-local deployment (e.g. to Windows XP).  This is meaningful
   only with MSVC from Visual Studio 2015 or higher.
 
-  One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
-  to an absolute path to tell CMake to look for Windows 10 SDKs in
-  a custom location.  The specified directory is expected to contain
-  ``Redist/ucrt/DLLs/*`` directories.
+  .. versionadded:: 3.9
+    One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
+    to an absolute path to tell CMake to look for Windows 10 SDKs in
+    a custom location.  The specified directory is expected to contain
+    ``Redist/ucrt/DLLs/*`` directories.
 
 ``CMAKE_INSTALL_MFC_LIBRARIES``
   Set to TRUE to install the MSVC MFC runtime libraries.
@@ -53,8 +56,13 @@ may be set prior to including the module to adjust behavior:
   not provide the redistributable files.)
 
 ``CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT``
+  .. versionadded:: 3.3
+
   Specify the :command:`install(PROGRAMS)` command ``COMPONENT``
   option.  If not specified, no such option will be used.
+
+.. versionadded:: 3.10
+  Support for installing Intel compiler runtimes.
 #]=======================================================================]
 
 cmake_policy(PUSH)
@@ -63,7 +71,7 @@ cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
 set(_IRSL_HAVE_Intel FALSE)
 set(_IRSL_HAVE_MSVC FALSE)
 foreach(LANG IN ITEMS C CXX Fortran)
-  if("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Intel")
+  if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "Intel")
     if(NOT _IRSL_HAVE_Intel)
       get_filename_component(_Intel_basedir "${CMAKE_${LANG}_COMPILER}" PATH)
       if(CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -93,16 +101,18 @@ endforeach()
 if(MSVC)
   file(TO_CMAKE_PATH "$ENV{SYSTEMROOT}" SYSTEMROOT)
 
-  if(CMAKE_CL_64)
-    if(MSVC_VERSION GREATER 1599)
-      # VS 10 and later:
-      set(CMAKE_MSVC_ARCH x64)
-    else()
+  if(MSVC_C_ARCHITECTURE_ID)
+    string(TOLOWER "${MSVC_C_ARCHITECTURE_ID}" CMAKE_MSVC_ARCH)
+  elseif(MSVC_CXX_ARCHITECTURE_ID)
+    string(TOLOWER "${MSVC_CXX_ARCHITECTURE_ID}" CMAKE_MSVC_ARCH)
+  else()
+    set(CMAKE_MSVC_ARCH x86)
+  endif()
+  if(CMAKE_MSVC_ARCH STREQUAL "x64")
+    if(MSVC_VERSION LESS 1600)
       # VS 9 and earlier:
       set(CMAKE_MSVC_ARCH amd64)
     endif()
-  else()
-    set(CMAKE_MSVC_ARCH x86)
   endif()
 
   get_filename_component(devenv_dir "${CMAKE_MAKE_PROGRAM}" PATH)
@@ -627,10 +637,10 @@ if(_IRSL_HAVE_Intel)
 
       list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
     endforeach()
-    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
+    if(CMAKE_C_COMPILER_ID MATCHES Intel OR CMAKE_CXX_COMPILER_ID MATCHES Intel)
       list(APPEND __install_libs "${_Intel_redistdir}/libgfxoffload.dll")
     endif()
-    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
+    if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
       foreach(__Intel_lib IN ITEMS ifdlg100.dll libicaf.dll libifcoremd.dll libifcoremdd.dll libifcorert.dll libifcorertd.dll libifportmd.dll)
 
         list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
@@ -640,12 +650,12 @@ if(_IRSL_HAVE_Intel)
     foreach(__Intel_lib IN ITEMS libchkp.dylib libcilkrts.5.dylib libcilkrts.dylib libimf.dylib libintlc.dylib libirc.dylib libirng.dylib libsvml.dylib)
       list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
     endforeach()
-    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
+    if(CMAKE_C_COMPILER_ID MATCHES Intel OR CMAKE_CXX_COMPILER_ID MATCHES Intel)
       if(_Intel_compiler_ver VERSION_LESS 17)
         list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.dylib")
       endif()
     endif()
-    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
+    if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
       foreach(__Intel_lib IN ITEMS libifcore.dylib libifcoremt.dylib libifport.dylib libifportmt.dylib)
 
         list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
@@ -662,7 +672,7 @@ if(_IRSL_HAVE_Intel)
         list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
       endforeach()
     endif()
-    if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel)
+    if(CMAKE_C_COMPILER_ID MATCHES Intel OR CMAKE_CXX_COMPILER_ID MATCHES Intel)
       set(__install_dirs "${_Intel_redistdir}/irml")
       list(APPEND __install_libs "${_Intel_redistdir}/cilk_db.so")
       if(_Intel_compiler_ver VERSION_GREATER_EQUAL 15)
@@ -681,7 +691,7 @@ if(_IRSL_HAVE_Intel)
         list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
       endforeach()
     endif()
-    if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
+    if(CMAKE_Fortran_COMPILER_ID MATCHES Intel)
       foreach(__Intel_lib IN ITEMS libicaf.so libifcore.so libifcore.so.5 libifcoremt.so libifcoremt.so.5 libifport.so libifport.so.5)
 
         list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}")
index b7beb5d..d89d69f 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
+<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <!-- Required elements-->
         <id>@CPACK_NUGET_PACKAGE_NAME@</id>
         @_CPACK_NUGET_OWNERS_TAG@
         @_CPACK_NUGET_PROJECTURL_TAG@
         @_CPACK_NUGET_LICENSEURL_TAG@
+        @_CPACK_NUGET_LICENSE_TAG@
         @_CPACK_NUGET_ICONURL_TAG@
+        @_CPACK_NUGET_ICON_TAG@
         @_CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG@
         @_CPACK_NUGET_SUMMARY_TAG@
         @_CPACK_NUGET_RELEASENOTES_TAG@
         @_CPACK_NUGET_COPYRIGHT_TAG@
+        @_CPACK_NUGET_LANGUAGE_TAG@
         @_CPACK_NUGET_TAGS_TAG@
         @_CPACK_NUGET_DEPENDENCIES_TAG@
     </metadata>
index 431b074..2ef0489 100644 (file)
@@ -310,10 +310,23 @@ function(cpack_deb_prepare_package_vars)
           set(IGNORE_MISSING_INFO_FLAG "--ignore-missing-info")
         endif()
 
+        if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS)
+          unset(PRIVATE_SEARCH_DIR_OPTIONS)
+          # Add -l option if the tool supports it
+          if(DEFINED SHLIBDEPS_EXECUTABLE_VERSION AND SHLIBDEPS_EXECUTABLE_VERSION VERSION_GREATER_EQUAL 1.17.0)
+            foreach(dir IN LISTS CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS)
+              list(APPEND PRIVATE_SEARCH_DIR_OPTIONS "-l${dir}")
+            endforeach()
+          else()
+            message(WARNING "CPackDeb: dkpg-shlibdeps is too old. \"CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS\" is therefore ignored.")
+          endif()
+        endif()
+
         # Execute dpkg-shlibdeps
         # --ignore-missing-info : allow dpkg-shlibdeps to run even if some libs do not belong to a package
+        # -l<dir>: make dpkg-shlibdeps also search in this directory for (private) shared library dependencies
         # -O : print to STDOUT
-        execute_process(COMMAND ${SHLIBDEPS_EXECUTABLE} ${IGNORE_MISSING_INFO_FLAG} -O ${CPACK_DEB_BINARY_FILES}
+        execute_process(COMMAND ${SHLIBDEPS_EXECUTABLE} ${PRIVATE_SEARCH_DIR_OPTIONS} ${IGNORE_MISSING_INFO_FLAG} -O ${CPACK_DEB_BINARY_FILES}
           WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
           OUTPUT_VARIABLE SHLIBDEPS_OUTPUT
           RESULT_VARIABLE SHLIBDEPS_RESULT
@@ -325,7 +338,7 @@ function(cpack_deb_prepare_package_vars)
         endif()
         if(NOT SHLIBDEPS_RESULT EQUAL 0)
           message(FATAL_ERROR "CPackDeb: dpkg-shlibdeps: '${SHLIBDEPS_ERROR}';\n"
-              "executed command: '${SHLIBDEPS_EXECUTABLE} ${IGNORE_MISSING_INFO_FLAG} -O ${CPACK_DEB_BINARY_FILES}';\n"
+              "executed command: '${SHLIBDEPS_EXECUTABLE} ${PRIVATE_SEARCH_DIR_OPTIONS} ${IGNORE_MISSING_INFO_FLAG} -O ${CPACK_DEB_BINARY_FILES}';\n"
               "found files: '${INSTALL_FILE_}';\n"
               "files info: '${CPACK_DEB_INSTALL_FILES}';\n"
               "binary files: '${CPACK_DEB_BINARY_FILES}'")
@@ -768,6 +781,10 @@ function(cpack_deb_prepare_package_vars)
     set(GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DBGSYM_OUTPUT_FILE_NAME}" PARENT_SCOPE)
     list(JOIN BUILD_IDS " " BUILD_IDS)
     set(GEN_BUILD_IDS "${BUILD_IDS}" PARENT_SCOPE)
+  else()
+    unset(GEN_DBGSYMDIR PARENT_SCOPE)
+    unset(GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME PARENT_SCOPE)
+    unset(GEN_BUILD_IDS PARENT_SCOPE)
   endif()
 endfunction()
 
index 20eed2e..fb363f4 100644 (file)
@@ -107,21 +107,44 @@ endfunction()
 function(_cpack_nuget_variable_fallback_and_wrap_into_element ELEMENT NUGET_VAR_NAME)
     set(_options)
     set(_one_value_args)
-    set(_multi_value_args FALLBACK_VARS)
-    cmake_parse_arguments(PARSE_ARGV 0 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
+    set(_multi_value_args FALLBACK_VARS ATTRIBUTES)
+    cmake_parse_arguments(PARSE_ARGV 2 _args "${_options}" "${_one_value_args}" "${_multi_value_args}")
+
+    if(_args_ATTRIBUTES)
+        list(JOIN _args_ATTRIBUTES " " _attributes)
+        string(PREPEND _attributes " ")
+    endif()
 
     _cpack_nuget_variable_fallback(_value ${NUGET_VAR_NAME} ${ARGN} USE_CDATA)
 
+    string(TOUPPER "${ELEMENT}" _ELEMENT_UP)
     if(_value)
-        string(TOUPPER "${ELEMENT}" _ELEMENT_UP)
         set(
             _CPACK_NUGET_${_ELEMENT_UP}_TAG
-            "<${ELEMENT}>${_value}</${ELEMENT}>"
+            "<${ELEMENT}${_attributes}>${_value}</${ELEMENT}>"
+            PARENT_SCOPE
+          )
+    elseif(_attributes)
+        set(
+            _CPACK_NUGET_${_ELEMENT_UP}_TAG
+            "<${ELEMENT}${_attributes} />"
             PARENT_SCOPE
           )
     endif()
 endfunction()
 
+# Warn of obsolete nuspec fields, referencing CMake variables and suggested
+# replacement, if any
+function(_cpack_nuget_deprecation_warning NUGET_ELEMENT VARNAME REPLACEMENT)
+    if(${VARNAME})
+        if(REPLACEMENT)
+            message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider replacing `${VARNAME}` with `${REPLACEMENT}`")
+        else()
+            message(DEPRECATION "nuspec element `${NUGET_ELEMENT}` is deprecated in NuGet; consider removing `${VARNAME}`")
+        endif()
+    endif()
+endfunction()
+
 # Print some debug info
 _cpack_nuget_debug("---[CPack NuGet Input Variables]---")
 _cpack_nuget_debug_var(CPACK_PACKAGE_NAME)
@@ -168,6 +191,21 @@ function(_cpack_nuget_render_spec)
         set(CPACK_NUGET_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
     endif()
 
+    # Warn about deprecated nuspec elements; warnings only display if
+    # variable is set
+    # Note that while nuspec's "summary" element is deprecated, there
+    # is no suggested replacement so (for now) no deprecation warning
+    # is shown for `CPACK_NUGET_*_DESCRIPTION_SUMMARY`
+    _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_PACKAGE_LICENSEURL
+        "CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME or CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION")
+    _cpack_nuget_deprecation_warning("licenseUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSEURL
+        "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_FILE_NAME or CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_LICENSE_EXPRESSION")
+    _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_PACKAGE_ICONURL
+        "CPACK_NUGET_PACKAGE_ICON")
+    _cpack_nuget_deprecation_warning("iconUrl" CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICONURL
+        "CPACK_NUGET_${CPACK_NUGET_PACKAGE_COMPONENT}_ICON")
+
+    # Set nuspec fields
     _cpack_nuget_variable_fallback(
         CPACK_NUGET_PACKAGE_VERSION VERSION
         FALLBACK_VARS
@@ -207,8 +245,35 @@ function(_cpack_nuget_render_spec)
         FALLBACK_VARS
             CPACK_PACKAGE_HOMEPAGE_URL
       )
+
+    # "licenseUrl" is deprecated in favor of "license"
     _cpack_nuget_variable_fallback_and_wrap_into_element(licenseUrl LICENSEURL)
+
+    # "iconUrl" is deprecated in favor of "icon"
     _cpack_nuget_variable_fallback_and_wrap_into_element(iconUrl ICONURL)
+
+    # "license" takes a "type" attribute of either "file" or "expression"
+    # "file" refers to a file path of a .txt or .md file relative to the installation root
+    # "expression" refers to simple or compound expression of license identifiers
+    # listed at https://spdx.org/licenses/
+    # Note that only one of CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME and
+    # CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION may be specified. If both are specified,
+    # CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME takes precedence and CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION is ignored.
+    if(CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME)
+        _cpack_nuget_variable_fallback_and_wrap_into_element(
+            license LICENSE_FILE_NAME
+            ATTRIBUTES [[type="file"]]
+          )
+    elseif(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION)
+        _cpack_nuget_variable_fallback_and_wrap_into_element(
+            license LICENSE_EXPRESSION
+            ATTRIBUTES [[type="expression"]]
+          )
+    endif()
+
+    # "icon" refers to a file path relative to the installation root
+    _cpack_nuget_variable_fallback_and_wrap_into_element(icon ICON)
+    # "summary" is deprecated in favor of "description"
     _cpack_nuget_variable_fallback_and_wrap_into_element(
         summary DESCRIPTION_SUMMARY
         FALLBACK_VARS
@@ -222,7 +287,12 @@ function(_cpack_nuget_render_spec)
     endif()
     _cpack_nuget_variable_fallback_and_wrap_into_element(releaseNotes RELEASE_NOTES)
     _cpack_nuget_variable_fallback_and_wrap_into_element(copyright COPYRIGHT)
+    # "language" is a locale identifier such as "en_CA"
+    _cpack_nuget_variable_fallback_and_wrap_into_element(language LANGUAGE)
     _cpack_nuget_variable_fallback_and_wrap_into_element(tags TAGS LIST_GLUE " ")
+    # "repository" holds repository metadata consisting of four optional
+    # attributes: "type", "url", "branch", and "commit". While all fields are
+    # considered optional, they are not independent. Currently unsupported.
 
     # Handle dependencies
     _cpack_nuget_variable_fallback(_deps DEPENDENCIES)
@@ -262,7 +332,7 @@ endfunction()
 function(_cpack_nuget_make_files_tag)
     set(_files)
     foreach(_comp IN LISTS ARGN)
-        string(APPEND _files "        <file src=\"${_comp}\\**\" target=\".\" />\n")
+        string(APPEND _files "        <file src=\"${_comp}/**\" target=\".\" />\n")
     endforeach()
     set(_CPACK_NUGET_FILES_TAG "<files>\n${_files}    </files>" PARENT_SCOPE)
 endfunction()
index 6009ce0..e6439ad 100644 (file)
@@ -1,4 +1,4 @@
-; CPack install script designed for a nmake build
+; CPack install script designed for a nmake build
 
 ;--------------------------------
 ; You must define these values
@@ -42,6 +42,7 @@
 
 @CPACK_NSIS_DEFINES@
 @CPACK_NSIS_MANIFEST_DPI_AWARE_CODE@
+@CPACK_NSIS_BRANDING_TEXT_CODE@
 
   !include Sections.nsh
 
index ca60b57..8fdc264 100644 (file)
@@ -5,26 +5,25 @@
 MacroAddFileDependencies
 ------------------------
 
-MACRO_ADD_FILE_DEPENDENCIES(<_file> depend_files...)
+.. deprecated:: 3.14
 
-Using the macro MACRO_ADD_FILE_DEPENDENCIES() is discouraged.  There
-are usually better ways to specify the correct dependencies.
+::
+
+  MACRO_ADD_FILE_DEPENDENCIES(<source> <files>...)
+
+Do not use this command in new code.  It is just a wrapper around:
+
+.. code-block:: cmake
+
+  set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+
+Instead use the :command:`set_property` command to append to the
+:prop_sf:`OBJECT_DEPENDS` source file property directly.
 
-MACRO_ADD_FILE_DEPENDENCIES(<_file> depend_files...) is just a
-convenience wrapper around the OBJECT_DEPENDS source file property.
-You can just use set_property(SOURCE <file> APPEND PROPERTY
-OBJECT_DEPENDS depend_files) instead.
 #]=======================================================================]
 
 macro (MACRO_ADD_FILE_DEPENDENCIES _file)
 
-  get_source_file_property(_deps ${_file} OBJECT_DEPENDS)
-  if (_deps)
-    set(_deps ${_deps} ${ARGN})
-  else ()
-    set(_deps ${ARGN})
-  endif ()
-
-  set_source_files_properties(${_file} PROPERTIES OBJECT_DEPENDS "${_deps}")
+  set_property(SOURCE "${_file}" APPEND PROPERTY OBJECT_DEPENDS "${ARGN}")
 
 endmacro ()
index 160eada..3a279ca 100644 (file)
@@ -7,6 +7,23 @@ if(__ANDROID_COMPILER_CLANG)
 endif()
 set(__ANDROID_COMPILER_CLANG 1)
 
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android-Clang.cmake OPTIONAL)
+endif()
+
+# Load flags from NDK. This file may provides the following variables:
+#   _ANDROID_NDK_INIT_CFLAGS
+#   _ANDROID_NDK_INIT_CFLAGS_DEBUG
+#   _ANDROID_NDK_INIT_CFLAGS_RELEASE
+#   _ANDROID_NDK_INIT_LDFLAGS
+#   _ANDROID_NDK_INIT_LDFLAGS_EXE
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/flags.cmake OPTIONAL
+          RESULT_VARIABLE _INCLUDED_FLAGS)
+endif()
+
 # Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
 # implemented in the CMake VS IDE generators.  Avoid interfering with
 # that functionality for now.  Later we may try to integrate this.
@@ -34,20 +51,29 @@ endif()
 
 include(Platform/Android-Common)
 
-# The NDK toolchain configuration files at:
-#
-#   <ndk>/[build/core/]toolchains/*-clang*/setup.mk
-#
-# contain logic to set LLVM_TRIPLE for Clang-based toolchains for each target.
-# We need to produce the same target here to produce compatible binaries.
-include(Platform/Android/abi-${CMAKE_ANDROID_ARCH_ABI}-Clang)
+if(_INCLUDED_FLAGS)
+  # NDK provides the flags.
+  set(_ANDROID_ABI_INIT_CFLAGS "${_ANDROID_NDK_INIT_CFLAGS}")
+  set(_ANDROID_ABI_INIT_CFLAGS_DEBUG "${_ANDROID_NDK_INIT_CFLAGS_DEBUG}")
+  set(_ANDROID_ABI_INIT_CFLAGS_RELEASE "${_ANDROID_NDK_INIT_CFLAGS_RELEASE}")
+  set(_ANDROID_ABI_INIT_LDFLAGS "${_ANDROID_NDK_INIT_LDFLAGS}")
+  set(_ANDROID_ABI_INIT_EXE_LDFLAGS "${_ANDROID_NDK_INIT_LDFLAGS_EXE}")
+else()
+  # The NDK toolchain configuration files at:
+  #
+  #   <ndk>/[build/core/]toolchains/*-clang*/setup.mk
+  #
+  # contain logic to set LLVM_TRIPLE for Clang-based toolchains for each target.
+  # We need to produce the same target here to produce compatible binaries.
+  include(Platform/Android/abi-${CMAKE_ANDROID_ARCH_ABI}-Clang)
+endif()
 
 macro(__android_compiler_clang lang)
   if(NOT "x${lang}" STREQUAL "xASM")
     __android_compiler_common(${lang})
   endif()
   if(NOT CMAKE_${lang}_COMPILER_TARGET)
-    set(CMAKE_${lang}_COMPILER_TARGET "${_ANDROID_ABI_CLANG_TARGET}")
+    set(CMAKE_${lang}_COMPILER_TARGET "${CMAKE_ANDROID_ARCH_LLVM_TRIPLE}")
     if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
       string(APPEND CMAKE_${lang}_COMPILER_TARGET "${CMAKE_SYSTEM_VERSION}")
     endif()
@@ -57,3 +83,9 @@ macro(__android_compiler_clang lang)
     set(_ANDROID_STL_NOSTDLIBXX 1)
   endif()
 endmacro()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android-Clang.cmake OPTIONAL)
+endif()
index 581fde4..39da933 100644 (file)
@@ -53,6 +53,12 @@ if(CMAKE_ANDROID_STL_TYPE)
       set(_ANDROID_STL_RTTI 0)
       macro(__android_stl lang)
         string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libstdc++")
+        if(_ANDROID_STL_EXCEPTIONS OR _ANDROID_STL_RTTI)
+          string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -lc++abi")
+          if(CMAKE_SYSTEM_VERSION LESS 21)
+            list(APPEND CMAKE_${lang}_STANDARD_LIBRARIES "-landroid_support")
+          endif()
+        endif()
       endmacro()
     elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_static")
       set(_ANDROID_STL_EXCEPTIONS 1)
@@ -81,6 +87,12 @@ if(CMAKE_ANDROID_STL_TYPE)
         "Android: STL '${CMAKE_ANDROID_STL_TYPE}' not supported by this NDK."
         )
     endif()
+    if(DEFINED CMAKE_ANDROID_RTTI)
+      set(_ANDROID_STL_RTTI ${CMAKE_ANDROID_RTTI})
+    endif()
+    if(DEFINED CMAKE_ANDROID_EXCEPTIONS)
+      set(_ANDROID_STL_EXCEPTIONS ${CMAKE_ANDROID_EXCEPTIONS})
+    endif()
   elseif(CMAKE_ANDROID_NDK)
 
     macro(__android_stl_inc lang dir req)
index bc66ba1..2d2cd5c 100644 (file)
@@ -5,6 +5,12 @@
 # This module detects platform-wide information about the Android target
 # in order to store it in "CMakeSystem.cmake".
 
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android-Determine.cmake OPTIONAL)
+endif()
+
 # Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
 # implemented in the CMake VS IDE generators.  Avoid interfering with
 # that functionality for now.
@@ -209,9 +215,55 @@ if(CMAKE_ANDROID_NDK)
   # NDK >= 18 has abis.cmake. It provides:
   #   NDK_KNOWN_DEVICE_ABI32S
   #   NDK_KNOWN_DEVICE_ABI64S
+  # NDK >= 23 also provides:
+  #   NDK_KNOWN_DEVICE_ABIS
+  #   NDK_ABI_<abi>_PROC
+  #   NDK_ABI_<abi>_ARCH
+  #   NDK_ABI_<abi>_TRIPLE
+  #   NDK_ABI_<abi>_LLVM_TRIPLE
+  #   NDK_PROC_<processor>_ABI
+  #   NDK_ARCH_<arch>_ABI
   include("${CMAKE_ANDROID_NDK}/build/cmake/abis.cmake" OPTIONAL RESULT_VARIABLE _INCLUDED_ABIS)
 endif()
 
+if(CMAKE_ANDROID_NDK AND EXISTS "${CMAKE_ANDROID_NDK}/source.properties")
+  # Android NDK revision
+  # Possible formats:
+  # * r16, build 1234: 16.0.1234
+  # * r16b, build 1234: 16.1.1234
+  # * r16 beta 1, build 1234: 16.0.1234-beta1
+  #
+  # Canary builds are not specially marked.
+  file(READ "${CMAKE_ANDROID_NDK}/source.properties" _ANDROID_NDK_SOURCE_PROPERTIES)
+
+  set(_ANDROID_NDK_REVISION_REGEX
+    "^Pkg\\.Desc = Android NDK\nPkg\\.Revision = ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-beta([0-9]+))?")
+  if(NOT _ANDROID_NDK_SOURCE_PROPERTIES MATCHES "${_ANDROID_NDK_REVISION_REGEX}")
+    string(REPLACE "\n" "\n  " _ANDROID_NDK_SOURCE_PROPERTIES "${_ANDROID_NDK_SOURCE_PROPERTIES}")
+    message(FATAL_ERROR
+      "Android: Failed to parse NDK revision from:\n"
+      " ${CMAKE_ANDROID_NDK}/source.properties\n"
+      "with content:\n"
+      "  ${_ANDROID_NDK_SOURCE_PROPERTIES}")
+  endif()
+
+  set(_ANDROID_NDK_MAJOR "${CMAKE_MATCH_1}")
+  set(_ANDROID_NDK_MINOR "${CMAKE_MATCH_2}")
+  set(_ANDROID_NDK_BUILD "${CMAKE_MATCH_3}")
+  set(_ANDROID_NDK_BETA "${CMAKE_MATCH_5}")
+  if(_ANDROID_NDK_BETA STREQUAL "")
+    set(_ANDROID_NDK_BETA "0")
+  endif()
+  set(CMAKE_ANDROID_NDK_VERSION "${_ANDROID_NDK_MAJOR}.${_ANDROID_NDK_MINOR}")
+
+  unset(_ANDROID_NDK_SOURCE_PROPERTIES)
+  unset(_ANDROID_NDK_REVISION_REGEX)
+  unset(_ANDROID_NDK_MAJOR)
+  unset(_ANDROID_NDK_MINOR)
+  unset(_ANDROID_NDK_BUILD)
+  unset(_ANDROID_NDK_BETA)
+endif()
+
 if(CMAKE_ANDROID_NDK)
   # Identify the host platform.
   if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
@@ -247,60 +299,75 @@ else()
 endif()
 
 if(_INCLUDED_ABIS)
-  set(_ANDROID_KNOWN_ABIS ${NDK_KNOWN_DEVICE_ABI32S} ${NDK_KNOWN_DEVICE_ABI64S})
+  if(NDK_KNOWN_DEVICE_ABIS)
+    set(_ANDROID_KNOWN_ABIS ${NDK_KNOWN_DEVICE_ABIS})
+  else()
+    set(_ANDROID_KNOWN_ABIS ${NDK_KNOWN_DEVICE_ABI32S} ${NDK_KNOWN_DEVICE_ABI64S})
+  endif()
 endif()
 
-# https://developer.android.com/ndk/guides/abis.html
-
-set(_ANDROID_ABI_arm64-v8a_PROC     "aarch64")
-set(_ANDROID_ABI_arm64-v8a_ARCH     "arm64")
-set(_ANDROID_ABI_arm64-v8a_TRIPLE   "aarch64-linux-android")
-set(_ANDROID_ABI_armeabi-v7a_PROC   "armv7-a")
-set(_ANDROID_ABI_armeabi-v7a_ARCH   "arm")
-set(_ANDROID_ABI_armeabi-v7a_TRIPLE "arm-linux-androideabi")
-set(_ANDROID_ABI_armeabi-v6_PROC    "armv6")
-set(_ANDROID_ABI_armeabi-v6_ARCH    "arm")
-set(_ANDROID_ABI_armeabi-v6_TRIPLE  "arm-linux-androideabi")
-set(_ANDROID_ABI_armeabi_PROC       "armv5te")
-set(_ANDROID_ABI_armeabi_ARCH       "arm")
-set(_ANDROID_ABI_armeabi_TRIPLE     "arm-linux-androideabi")
-set(_ANDROID_ABI_mips_PROC          "mips")
-set(_ANDROID_ABI_mips_ARCH          "mips")
-set(_ANDROID_ABI_mips_TRIPLE        "mipsel-linux-android")
-set(_ANDROID_ABI_mips64_PROC        "mips64")
-set(_ANDROID_ABI_mips64_ARCH        "mips64")
-set(_ANDROID_ABI_mips64_TRIPLE      "mips64el-linux-android")
-set(_ANDROID_ABI_x86_PROC           "i686")
-set(_ANDROID_ABI_x86_ARCH           "x86")
-set(_ANDROID_ABI_x86_TRIPLE         "i686-linux-android")
-set(_ANDROID_ABI_x86_64_PROC        "x86_64")
-set(_ANDROID_ABI_x86_64_ARCH        "x86_64")
-set(_ANDROID_ABI_x86_64_TRIPLE      "x86_64-linux-android")
-
-set(_ANDROID_PROC_aarch64_ARCH_ABI "arm64-v8a")
-set(_ANDROID_PROC_armv7-a_ARCH_ABI "armeabi-v7a")
-set(_ANDROID_PROC_armv6_ARCH_ABI   "armeabi-v6")
-set(_ANDROID_PROC_armv5te_ARCH_ABI "armeabi")
-set(_ANDROID_PROC_i686_ARCH_ABI    "x86")
-set(_ANDROID_PROC_mips_ARCH_ABI    "mips")
-set(_ANDROID_PROC_mips64_ARCH_ABI  "mips64")
-set(_ANDROID_PROC_x86_64_ARCH_ABI  "x86_64")
-
-set(_ANDROID_ARCH_arm64_ABI  "arm64-v8a")
-set(_ANDROID_ARCH_arm_ABI    "armeabi")
-set(_ANDROID_ARCH_mips_ABI   "mips")
-set(_ANDROID_ARCH_mips64_ABI "mips64")
-set(_ANDROID_ARCH_x86_ABI    "x86")
-set(_ANDROID_ARCH_x86_64_ABI "x86_64")
+if(NOT DEFINED NDK_KNOWN_DEVICE_ABIS)
+  # The NDK is not new enough to provide ABI information.
+  # https://developer.android.com/ndk/guides/abis.html
+
+  set(NDK_ABI_arm64-v8a_PROC           "aarch64")
+  set(NDK_ABI_arm64-v8a_ARCH           "arm64")
+  set(NDK_ABI_arm64-v8a_TRIPLE         "aarch64-linux-android")
+  set(NDK_ABI_arm64-v8a_LLVM_TRIPLE    "aarch64-none-linux-android")
+  set(NDK_ABI_armeabi-v7a_PROC         "armv7-a")
+  set(NDK_ABI_armeabi-v7a_ARCH         "arm")
+  set(NDK_ABI_armeabi-v7a_TRIPLE       "arm-linux-androideabi")
+  set(NDK_ABI_armeabi-v7a_LLVM_TRIPLE  "armv7-none-linux-androideabi")
+  set(NDK_ABI_armeabi-v6_PROC          "armv6")
+  set(NDK_ABI_armeabi-v6_ARCH          "arm")
+  set(NDK_ABI_armeabi-v6_TRIPLE        "arm-linux-androideabi")
+  set(NDK_ABI_armeabi-v6_LLVM_TRIPLE   "armv6-none-linux-androideabi")
+  set(NDK_ABI_armeabi_PROC             "armv5te")
+  set(NDK_ABI_armeabi_ARCH             "arm")
+  set(NDK_ABI_armeabi_TRIPLE           "arm-linux-androideabi")
+  set(NDK_ABI_armeabi_LLVM_TRIPLE      "armv5te-none-linux-androideabi")
+  set(NDK_ABI_mips_PROC                "mips")
+  set(NDK_ABI_mips_ARCH                "mips")
+  set(NDK_ABI_mips_TRIPLE              "mipsel-linux-android")
+  set(NDK_ABI_mips_LLVM_TRIPLE         "mipsel-none-linux-android")
+  set(NDK_ABI_mips64_PROC              "mips64")
+  set(NDK_ABI_mips64_ARCH              "mips64")
+  set(NDK_ABI_mips64_TRIPLE            "mips64el-linux-android")
+  set(NDK_ABI_mips64_LLVM_TRIPLE       "mips64el-none-linux-android")
+  set(NDK_ABI_x86_PROC                 "i686")
+  set(NDK_ABI_x86_ARCH                 "x86")
+  set(NDK_ABI_x86_TRIPLE               "i686-linux-android")
+  set(NDK_ABI_x86_LLVM_TRIPLE          "i686-none-linux-android")
+  set(NDK_ABI_x86_64_PROC              "x86_64")
+  set(NDK_ABI_x86_64_ARCH              "x86_64")
+  set(NDK_ABI_x86_64_TRIPLE            "x86_64-linux-android")
+  set(NDK_ABI_x86_64_LLVM_TRIPLE       "x86_64-none-linux-android")
+
+  set(NDK_PROC_aarch64_ABI "arm64-v8a")
+  set(NDK_PROC_armv7-a_ABI "armeabi-v7a")
+  set(NDK_PROC_armv6_ABI   "armeabi-v6")
+  set(NDK_PROC_armv5te_ABI "armeabi")
+  set(NDK_PROC_i686_ABI    "x86")
+  set(NDK_PROC_mips_ABI    "mips")
+  set(NDK_PROC_mips64_ABI  "mips64")
+  set(NDK_PROC_x86_64_ABI  "x86_64")
+
+  set(NDK_ARCH_arm64_ABI  "arm64-v8a")
+  set(NDK_ARCH_arm_ABI    "armeabi")
+  set(NDK_ARCH_mips_ABI   "mips")
+  set(NDK_ARCH_mips64_ABI "mips64")
+  set(NDK_ARCH_x86_ABI    "x86")
+  set(NDK_ARCH_x86_64_ABI "x86_64")
+endif()
 
 # Validate inputs.
-if(CMAKE_ANDROID_ARCH_ABI AND NOT DEFINED "_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC")
+if(CMAKE_ANDROID_ARCH_ABI AND NOT DEFINED "NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC")
   message(FATAL_ERROR "Android: Unknown ABI CMAKE_ANDROID_ARCH_ABI='${CMAKE_ANDROID_ARCH_ABI}'.")
 endif()
-if(CMAKE_SYSTEM_PROCESSOR AND NOT DEFINED "_ANDROID_PROC_${CMAKE_SYSTEM_PROCESSOR}_ARCH_ABI")
+if(CMAKE_SYSTEM_PROCESSOR AND NOT DEFINED "NDK_PROC_${CMAKE_SYSTEM_PROCESSOR}_ABI")
   message(FATAL_ERROR "Android: Unknown processor CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}'.")
 endif()
-if(_ANDROID_SYSROOT_ARCH AND NOT DEFINED "_ANDROID_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI")
+if(_ANDROID_SYSROOT_ARCH AND NOT DEFINED "NDK_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI")
   message(FATAL_ERROR
     "Android: Unknown architecture '${_ANDROID_SYSROOT_ARCH}' specified in CMAKE_SYSROOT:\n"
     "  ${CMAKE_SYSROOT}"
@@ -310,9 +377,9 @@ endif()
 # Select an ABI.
 if(NOT CMAKE_ANDROID_ARCH_ABI)
   if(CMAKE_SYSTEM_PROCESSOR)
-    set(CMAKE_ANDROID_ARCH_ABI "${_ANDROID_PROC_${CMAKE_SYSTEM_PROCESSOR}_ARCH_ABI}")
+    set(CMAKE_ANDROID_ARCH_ABI "${NDK_PROC_${CMAKE_SYSTEM_PROCESSOR}_ABI}")
   elseif(_ANDROID_SYSROOT_ARCH)
-    set(CMAKE_ANDROID_ARCH_ABI "${_ANDROID_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI}")
+    set(CMAKE_ANDROID_ARCH_ABI "${NDK_ARCH_${_ANDROID_SYSROOT_ARCH}_ABI}")
   elseif(_INCLUDED_ABIS)
     # Default to the oldest ARM ABI.
     foreach(abi armeabi armeabi-v7a arm64-v8a)
@@ -368,7 +435,7 @@ if(_INCLUDED_ABIS AND NOT CMAKE_ANDROID_ARCH_ABI IN_LIST _ANDROID_KNOWN_ABIS)
     "Supported ABIS: ${_ANDROID_KNOWN_ABIS}."
   )
 endif()
-set(CMAKE_ANDROID_ARCH "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_ARCH}")
+set(CMAKE_ANDROID_ARCH "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_ARCH}")
 if(_ANDROID_SYSROOT_ARCH AND NOT "x${_ANDROID_SYSROOT_ARCH}" STREQUAL "x${CMAKE_ANDROID_ARCH}")
   message(FATAL_ERROR
     "Android: Architecture '${_ANDROID_SYSROOT_ARCH}' specified in CMAKE_SYSROOT:\n"
@@ -376,15 +443,17 @@ if(_ANDROID_SYSROOT_ARCH AND NOT "x${_ANDROID_SYSROOT_ARCH}" STREQUAL "x${CMAKE_
     "does not match architecture '${CMAKE_ANDROID_ARCH}' for the ABI '${CMAKE_ANDROID_ARCH_ABI}'."
     )
 endif()
-set(CMAKE_ANDROID_ARCH_TRIPLE "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_TRIPLE}")
+set(CMAKE_ANDROID_ARCH_TRIPLE "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_TRIPLE}")
+set(CMAKE_ANDROID_ARCH_LLVM_TRIPLE
+    "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_LLVM_TRIPLE}")
 
 # Select a processor.
 if(NOT CMAKE_SYSTEM_PROCESSOR)
-  set(CMAKE_SYSTEM_PROCESSOR "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC}")
+  set(CMAKE_SYSTEM_PROCESSOR "${NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC}")
 endif()
 
 # If the user specified both an ABI and a processor then they might not match.
-if(NOT _ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC STREQUAL CMAKE_SYSTEM_PROCESSOR)
+if(NOT NDK_ABI_${CMAKE_ANDROID_ARCH_ABI}_PROC STREQUAL CMAKE_SYSTEM_PROCESSOR)
   message(FATAL_ERROR "Android: The specified CMAKE_ANDROID_ARCH_ABI='${CMAKE_ANDROID_ARCH_ABI}' and CMAKE_SYSTEM_PROCESSOR='${CMAKE_SYSTEM_PROCESSOR}' is not a valid combination.")
 endif()
 
@@ -491,6 +560,8 @@ set(CMAKE_ANDROID_ARCH_ABI \"${CMAKE_ANDROID_ARCH_ABI}\")
 if(CMAKE_ANDROID_NDK)
   string(APPEND CMAKE_SYSTEM_CUSTOM_CODE
     "set(CMAKE_ANDROID_ARCH_TRIPLE \"${CMAKE_ANDROID_ARCH_TRIPLE}\")\n"
+    "set(CMAKE_ANDROID_ARCH_LLVM_TRIPLE \"${CMAKE_ANDROID_ARCH_LLVM_TRIPLE}\")\n"
+    "set(CMAKE_ANDROID_NDK_VERSION \"${CMAKE_ANDROID_NDK_VERSION}\")\n"
     "set(CMAKE_ANDROID_NDK_DEPRECATED_HEADERS \"${CMAKE_ANDROID_NDK_DEPRECATED_HEADERS}\")\n"
     "set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG \"${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}\")\n"
     "set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED \"${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}\")\n"
@@ -528,3 +599,9 @@ endif()
 message(STATUS "Android: Targeting API '${CMAKE_SYSTEM_VERSION}' with architecture '${CMAKE_ANDROID_ARCH}', ABI '${CMAKE_ANDROID_ARCH_ABI}', and processor '${CMAKE_SYSTEM_PROCESSOR}'")
 
 cmake_policy(POP)
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android-Determine.cmake OPTIONAL)
+endif()
index 5019c28..6116ae1 100644 (file)
@@ -4,6 +4,12 @@
 # When CMAKE_SYSTEM_NAME is "Android", CMakeSystemSpecificInitialize loads this
 # module.
 
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android-Initialize.cmake OPTIONAL)
+endif()
+
 # Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
 # implemented in the CMake VS IDE generators.  Avoid interfering with
 # that functionality for now.
@@ -17,7 +23,7 @@ if(CMAKE_SYSTEM_VERSION EQUAL 1)
   return()
 endif()
 
-set(CMAKE_BUILD_TYPE_INIT Debug)
+set(CMAKE_BUILD_TYPE_INIT "RelWithDebInfo")
 
 # Skip sysroot selection if the NDK has a unified toolchain.
 if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
@@ -53,3 +59,9 @@ else()
     "Android: No CMAKE_SYSROOT was selected."
     )
 endif()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android-Initialize.cmake OPTIONAL)
+endif()
index 8ffa1b2..e4b9a09 100644 (file)
@@ -1,3 +1,9 @@
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Android.cmake OPTIONAL)
+endif()
+
 include(Platform/Linux)
 
 set(ANDROID 1)
@@ -22,3 +28,65 @@ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "")
 if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")
   set(CMAKE_LINK_LIBRARY_FLAG "")
 endif()
+
+# Commonly used Android toolchain files that pre-date CMake upstream support
+# set CMAKE_SYSTEM_VERSION to 1.  Avoid interfering with them.
+if(CMAKE_SYSTEM_VERSION EQUAL 1)
+  return()
+endif()
+
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+  # Tell CMake not to search host sysroots for headers/libraries.
+
+  # All paths added to CMAKE_SYSTEM_*_PATH below will be rerooted under
+  # CMAKE_FIND_ROOT_PATH. This is set because:
+  # 1. Users may structure their libraries in a way similar to NDK. When they do that,
+  #    they can simply append another path to CMAKE_FIND_ROOT_PATH.
+  # 2. CMAKE_FIND_ROOT_PATH must be non-empty for CMAKE_FIND_ROOT_PATH_MODE_* == ONLY
+  #    to be meaningful. https://github.com/android-ndk/ndk/issues/890
+  list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/sysroot")
+
+  # Allow users to override these values in case they want more strict behaviors.
+  # For example, they may want to prevent the NDK's libz from being picked up so
+  # they can use their own.
+  # https://github.com/android-ndk/ndk/issues/517
+  if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PROGRAM)
+    set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+  endif()
+
+  if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
+    set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+  endif()
+
+  if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_INCLUDE)
+    set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+  endif()
+
+  if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE)
+    set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+  endif()
+
+  # Don't search paths in PATH environment variable.
+  if(NOT DEFINED CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH)
+    set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF)
+  endif()
+
+  # Allows CMake to find headers in the architecture-specific include directories.
+  set(CMAKE_LIBRARY_ARCHITECTURE "${CMAKE_ANDROID_ARCH_TRIPLE}")
+
+  # Instructs CMake to search the correct API level for libraries.
+  # Besides the paths like <root>/<prefix>/lib/<arch>, cmake also searches <root>/<prefix>.
+  # So we can add the API level specific directory directly.
+  # https://github.com/android/ndk/issues/929
+  list(PREPEND CMAKE_SYSTEM_PREFIX_PATH
+    "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${CMAKE_SYSTEM_VERSION}"
+    )
+
+  list(APPEND CMAKE_SYSTEM_PROGRAM_PATH "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin")
+endif()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Android.cmake OPTIONAL)
+endif()
index f9c2d89..f8eae62 100644 (file)
@@ -7,6 +7,12 @@ if(__ANDROID_DETERMINE_COMPILER)
 endif()
 set(__ANDROID_DETERMINE_COMPILER 1)
 
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/pre/Determine-Compiler.cmake OPTIONAL)
+endif()
+
 # Support for NVIDIA Nsight Tegra Visual Studio Edition was previously
 # implemented in the CMake VS IDE generators.  Avoid interfering with
 # that functionality for now.  Later we may try to integrate this.
@@ -83,3 +89,9 @@ set(CMAKE_${lang}_ANDROID_TOOLCHAIN_SUFFIX \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_S
 ")
   endif()
 endmacro()
+
+# Include the NDK hook.
+# It can be used by NDK to inject necessary fixes for an earlier cmake.
+if(CMAKE_ANDROID_NDK)
+  include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/post/Determine-Compiler.cmake OPTIONAL)
+endif()
index f4717d5..c18c0a2 100644 (file)
@@ -1,6 +1,3 @@
-# <ndk>/build/core/toolchains/aarch64-linux-android-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "aarch64-none-linux-android")
-
 # Suppress -Wl,-z,nocopyreloc flag on arm64-v8a
 set(_ANDROID_ABI_INIT_EXE_LDFLAGS_NO_nocopyreloc 1)
 
index b857bd3..2b1de03 100644 (file)
@@ -1,6 +1,3 @@
-# <ndk>/build/core/toolchains/arm-linux-androideabi-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "armv5te-none-linux-androideabi")
-
 string(APPEND _ANDROID_ABI_INIT_CFLAGS
   " -march=armv5te"
   )
index a7412f5..bb176ae 100644 (file)
@@ -1,6 +1,3 @@
-# <ndk>/build/core/toolchains/arm-linux-androideabi-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "armv6-none-linux-androideabi")
-
 string(APPEND _ANDROID_ABI_INIT_CFLAGS
   " -march=armv6"
   )
index e2ab58b..6feeef6 100644 (file)
@@ -1,6 +1,3 @@
-# <ndk>/build/core/toolchains/arm-linux-androideabi-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "armv7-none-linux-androideabi")
-
 string(APPEND _ANDROID_ABI_INIT_CFLAGS
   " -march=armv7-a"
   )
index 73addde..7df6a36 100644 (file)
@@ -1,4 +1 @@
-# <ndk>/build/core/toolchains/mipsel-linux-android-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "mipsel-none-linux-android")
-
 include(Platform/Android/abi-common-Clang)
index 603f1b2..7df6a36 100644 (file)
@@ -1,4 +1 @@
-# <ndk>/build/core/toolchains/mips64el-linux-android-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "mips64el-none-linux-android")
-
 include(Platform/Android/abi-common-Clang)
index fe7eace..7df6a36 100644 (file)
@@ -1,4 +1 @@
-# <ndk>/build/core/toolchains/x86-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "i686-none-linux-android")
-
 include(Platform/Android/abi-common-Clang)
index 3cbcd49..7df6a36 100644 (file)
@@ -1,4 +1 @@
-# <ndk>/build/core/toolchains/x86_64-clang/setup.mk
-set(_ANDROID_ABI_CLANG_TARGET "x86_64-none-linux-android")
-
 include(Platform/Android/abi-common-Clang)
diff --git a/Modules/Platform/Apple-IntelLLVM-C.cmake b/Modules/Platform/Apple-IntelLLVM-C.cmake
new file mode 100644 (file)
index 0000000..8e74729
--- /dev/null
@@ -0,0 +1,2 @@
+include(Platform/Apple-IntelLLVM)
+__apple_compiler_intel_llvm(C)
diff --git a/Modules/Platform/Apple-IntelLLVM-CXX.cmake b/Modules/Platform/Apple-IntelLLVM-CXX.cmake
new file mode 100644 (file)
index 0000000..38640e1
--- /dev/null
@@ -0,0 +1,2 @@
+include(Platform/Apple-IntelLLVM)
+__apple_compiler_intel_llvm(CXX)
diff --git a/Modules/Platform/Apple-IntelLLVM-Fortran.cmake b/Modules/Platform/Apple-IntelLLVM-Fortran.cmake
new file mode 100644 (file)
index 0000000..d0486ed
--- /dev/null
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+include(Platform/Apple-IntelLLVM)
+__apple_compiler_intel_llvm(Fortran)
+
+set(CMAKE_Fortran_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set(CMAKE_Fortran_OSX_CURRENT_VERSION_FLAG "-current_version ")
diff --git a/Modules/Platform/Apple-IntelLLVM.cmake b/Modules/Platform/Apple-IntelLLVM.cmake
new file mode 100644 (file)
index 0000000..2f9f0ca
--- /dev/null
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__apple_compiler_intel_llvm lang)
+  set(CMAKE_${lang}_VERBOSE_FLAG "-v -Wl,-v") # also tell linker to print verbose output
+  set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
+  set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
+
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+  set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+endmacro()
diff --git a/Modules/Platform/Linux-IntelLLVM-C.cmake b/Modules/Platform/Linux-IntelLLVM-C.cmake
new file mode 100644 (file)
index 0000000..5356c4f
--- /dev/null
@@ -0,0 +1,3 @@
+include(Platform/Linux-IntelLLVM)
+__linux_compiler_intel_llvm(C)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ")
diff --git a/Modules/Platform/Linux-IntelLLVM-CXX.cmake b/Modules/Platform/Linux-IntelLLVM-CXX.cmake
new file mode 100644 (file)
index 0000000..44ce0e8
--- /dev/null
@@ -0,0 +1,3 @@
+include(Platform/Linux-IntelLLVM)
+__linux_compiler_intel_llvm(CXX)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem ")
diff --git a/Modules/Platform/Linux-IntelLLVM-Fortran.cmake b/Modules/Platform/Linux-IntelLLVM-Fortran.cmake
new file mode 100644 (file)
index 0000000..1cd9b1f
--- /dev/null
@@ -0,0 +1,4 @@
+include(Platform/Linux-IntelLLVM)
+__linux_compiler_intel_llvm(Fortran)
+string(APPEND CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS " -nofor-main")
+set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "")
diff --git a/Modules/Platform/Linux-IntelLLVM.cmake b/Modules/Platform/Linux-IntelLLVM.cmake
new file mode 100644 (file)
index 0000000..1363b44
--- /dev/null
@@ -0,0 +1,55 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_INTEL_LLVM)
+  return()
+endif()
+set(__LINUX_COMPILER_INTEL_LLVM 1)
+
+if(NOT XIAR)
+  set(_intel_xiar_hints)
+  foreach(lang C CXX Fortran)
+    if(IS_ABSOLUTE "${CMAKE_${lang}_COMPILER}")
+      get_filename_component(_hint "${CMAKE_${lang}_COMPILER}" PATH)
+      list(APPEND _intel_xiar_hints ${_hint})
+    endif()
+  endforeach()
+  find_program(XIAR NAMES xiar HINTS ${_intel_xiar_hints})
+  mark_as_advanced(XIAR)
+endif()
+
+macro(__linux_compiler_intel_llvm lang)
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+  set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
+  set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
+  set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} "-pie")
+  set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "-no-pie")
+  set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+  set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+
+  # We pass this for historical reasons.  Projects may have
+  # executables that use dlopen but do not set ENABLE_EXPORTS.
+  set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
+
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+  set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
+
+  if(XIAR)
+    # INTERPROCEDURAL_OPTIMIZATION
+    set(CMAKE_${lang}_COMPILE_OPTIONS_IPO -ipo)
+    set(CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO
+      "${XIAR} cr <TARGET> <LINK_FLAGS> <OBJECTS> "
+      "${XIAR} -s <TARGET> ")
+    set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+    set(_CMAKE_${lang}_IPO_LEGACY_BEHAVIOR YES)
+  else()
+    set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
+  endif()
+
+  set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+endmacro()
diff --git a/Modules/Platform/Linux-NVHPC-C.cmake b/Modules/Platform/Linux-NVHPC-C.cmake
new file mode 100644 (file)
index 0000000..4aab327
--- /dev/null
@@ -0,0 +1,2 @@
+include(Platform/Linux-NVHPC)
+__linux_compiler_nvhpc(C)
diff --git a/Modules/Platform/Linux-NVHPC-CXX.cmake b/Modules/Platform/Linux-NVHPC-CXX.cmake
new file mode 100644 (file)
index 0000000..57380eb
--- /dev/null
@@ -0,0 +1,2 @@
+include(Platform/Linux-NVHPC)
+__linux_compiler_nvhpc(CXX)
diff --git a/Modules/Platform/Linux-NVHPC-Fortran.cmake b/Modules/Platform/Linux-NVHPC-Fortran.cmake
new file mode 100644 (file)
index 0000000..c68430c
--- /dev/null
@@ -0,0 +1,2 @@
+include(Platform/Linux-NVHPC)
+__linux_compiler_nvhpc(Fortran)
diff --git a/Modules/Platform/Linux-NVHPC.cmake b/Modules/Platform/Linux-NVHPC.cmake
new file mode 100644 (file)
index 0000000..aad17f1
--- /dev/null
@@ -0,0 +1,15 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_NVIDIA)
+  return()
+endif()
+set(__LINUX_COMPILER_NVIDIA 1)
+
+include(Platform/Linux-PGI)
+
+macro(__linux_compiler_nvhpc lang)
+  __linux_compiler_pgi(${lang})
+endmacro()
index b5d5464..23b48bd 100644 (file)
@@ -48,6 +48,7 @@ endif()
 
 # Match multiarch library directory names.
 set(CMAKE_LIBRARY_ARCHITECTURE_REGEX "[a-z0-9_]+(-[a-z0-9_]+)?-linux-gnu[a-z0-9_]*")
+set(CMAKE_LIBRARY_ARCHITECTURE_REGEX_VERSIONED "gcc/[a-z0-9_]+(-[a-z0-9_]+)?-linux(-gnu)?/[0-9]+(\\.[0-9]+\\.[0-9]+)*")
 
 include(Platform/UnixPaths)
 
index d007105..322e3fb 100644 (file)
@@ -1,2 +1,18 @@
 include(Platform/Windows-Clang)
 __windows_compiler_clang(C)
+
+if("x${MAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_C)
+    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+  endif()
+elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_C)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_C_DEPFILE_FORMAT gcc)
+    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+  endif()
+endif()
index f1d40f2..b4aaf1e 100644 (file)
@@ -1,3 +1,19 @@
 include(Platform/Windows-Clang)
 set(_COMPILE_CXX_MSVC " -TP")
 __windows_compiler_clang(CXX)
+
+if("x${MAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_CXX)
+    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+  endif()
+elseif("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+      AND CMAKE_DEPFILE_FLAGS_CXX)
+    # dependencies are computed by the compiler itself
+    set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+  endif()
+endif()
index 7697407..c508ac1 100644 (file)
@@ -27,7 +27,7 @@ macro(__windows_compiler_clang_gnu lang)
   set(CMAKE_SHARED_MODULE_SUFFIX  ".dll")
   set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
   if(NOT "${lang}" STREQUAL "ASM")
-    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>")
+    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <DEP_TARGET> -MF <DEP_FILE>")
   endif()
 
   set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
@@ -71,6 +71,9 @@ macro(__windows_compiler_clang_gnu lang)
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
 
+  set(CMAKE_CREATE_WIN32_EXE "-Xlinker /subsystem:windows")
+  set(CMAKE_CREATE_CONSOLE_EXE "-Xlinker /subsystem:console")
+
   if(NOT "${lang}" STREQUAL "ASM")
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmt)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -D_DLL -D_MT -Xclang --dependent-lib=msvcrt)
@@ -114,8 +117,10 @@ macro(__enable_llvm_rc_preprocessing clang_option_prefix extra_pp_flags)
       set(CMAKE_RC_PREPROCESSOR CMAKE_CXX_COMPILER)
     endif()
     if(DEFINED CMAKE_RC_PREPROCESSOR)
-      set(CMAKE_DEPFILE_FLAGS_RC "${clang_option_prefix}-MD ${clang_option_prefix}-MF ${clang_option_prefix}<DEPFILE>")
-      set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_COMMAND> -E cmake_llvm_rc <SOURCE> <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> ${extra_pp_flags} -E -- <SOURCE> ++ <CMAKE_RC_COMPILER> <DEFINES> -I <SOURCE_DIR> <INCLUDES> /fo <OBJECT> <OBJECT>.pp")
+      set(CMAKE_DEPFILE_FLAGS_RC "${clang_option_prefix}-MD ${clang_option_prefix}-MF ${clang_option_prefix}<DEP_FILE>")
+      # The <FLAGS> are passed to the preprocess and the resource compiler to pick
+      # up the eventual -D / -C options passed through the CMAKE_RC_FLAGS.
+      set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_COMMAND> -E cmake_llvm_rc <SOURCE> <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> ${extra_pp_flags} -E -- <SOURCE> ++ <CMAKE_RC_COMPILER> <DEFINES> -I <SOURCE_DIR> <INCLUDES> <FLAGS> /fo <OBJECT> <OBJECT>.pp")
       if(CMAKE_GENERATOR MATCHES "Ninja")
         set(CMAKE_NINJA_CMCLDEPS_RC 0)
         set(CMAKE_NINJA_DEP_TYPE_RC gcc)
index 59f3ca5..8f1d024 100644 (file)
@@ -35,8 +35,8 @@ else()
   set(_tR "-tR") # Target uses the dynamic RTL
   set(_tW "-tW") # Target is a Windows application
 endif()
-set(_COMPILE_C "-c")
-set(_COMPILE_CXX "-P -c")
+set(_COMPILE_C "")
+set(_COMPILE_CXX " -P")
 
 set(CMAKE_LIBRARY_PATH_FLAG "-L")
 set(CMAKE_LINK_LIBRARY_FLAG "")
@@ -87,7 +87,7 @@ macro(__embarcadero_language lang)
   # place <DEFINES> outside the response file because Borland refuses
   # to parse quotes from the response file.
   set(CMAKE_${lang}_COMPILE_OBJECT
-    "<CMAKE_${lang}_COMPILER> ${_tR} -DWIN32 <DEFINES> <INCLUDES> <FLAGS> -o<OBJECT> ${_COMPILE_${lang}} <SOURCE>"
+    "<CMAKE_${lang}_COMPILER> ${_tR} -DWIN32 <DEFINES> <INCLUDES> <FLAGS> -o<OBJECT>${_COMPILE_${lang}} -c <SOURCE>"
     )
 
   set(CMAKE_${lang}_LINK_EXECUTABLE
@@ -98,7 +98,7 @@ macro(__embarcadero_language lang)
   # place <DEFINES> outside the response file because Borland refuses
   # to parse quotes from the response file.
   set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE
-    "cpp32 -DWIN32 <DEFINES> <INCLUDES> <FLAGS> -o<PREPROCESSED_SOURCE> ${_COMPILE_${lang}} <SOURCE>"
+    "cpp32 -DWIN32 <DEFINES> <INCLUDES> <FLAGS> -o<PREPROCESSED_SOURCE>${_COMPILE_${lang}} -c <SOURCE>"
     )
   # Borland >= 5.6 allows -P option for cpp32, <= 5.5 does not
 
index 06d8f50..152b27c 100644 (file)
@@ -1,4 +1,27 @@
 include(Platform/Windows-Intel)
 __windows_compiler_intel(C)
-set(CMAKE_NINJA_DEPTYPE_C intel) # special value handled by CMake
-set(CMAKE_DEPFILE_FLAGS_C "-QMMD -QMT <OBJECT> -QMF <DEPFILE>")
+
+set(CMAKE_DEPFILE_FLAGS_C "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+set(CMAKE_C_DEPFILE_FORMAT gcc)
+
+if(CMAKE_GENERATOR MATCHES "^Ninja")
+  if(_CMAKE_NINJA_VERSION VERSION_LESS 1.9)
+    # This ninja version is too old to support the Intel depfile format.
+    # Fall back to msvc depfile format.
+    set(CMAKE_DEPFILE_FLAGS_C "/showIncludes")
+    set(CMAKE_C_DEPFILE_FORMAT msvc)
+  endif()
+endif()
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  # dependencies are computed by the compiler itself
+  set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+if("${CMAKE_SOURCE_DIR}${CMAKE_BINARY_DIR}" MATCHES " ")
+  # The Intel compiler does not properly escape spaces in a depfile.
+  # Fall back to msvc depfile format.
+  set(CMAKE_DEPFILE_FLAGS_C "/showIncludes")
+  set(CMAKE_C_DEPFILE_FORMAT msvc)
+endif()
index 666de6e..ce33ae1 100644 (file)
@@ -1,5 +1,28 @@
 include(Platform/Windows-Intel)
 set(_COMPILE_CXX " /TP")
 __windows_compiler_intel(CXX)
-set(CMAKE_NINJA_DEPTYPE_CXX intel) # special value handled by CMake
-set(CMAKE_DEPFILE_FLAGS_CXX "-QMMD -QMT <OBJECT> -QMF <DEPFILE>")
+
+set(CMAKE_DEPFILE_FLAGS_CXX "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+
+if(CMAKE_GENERATOR MATCHES "^Ninja")
+  if(_CMAKE_NINJA_VERSION VERSION_LESS 1.9)
+    # This ninja version is too old to support the Intel depfile format.
+    # Fall back to msvc depfile format.
+    set(CMAKE_DEPFILE_FLAGS_CXX "/showIncludes")
+    set(CMAKE_CXX_DEPFILE_FORMAT msvc)
+  endif()
+endif()
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  # dependencies are computed by the compiler itself
+ set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
+
+if("${CMAKE_SOURCE_DIR}${CMAKE_BINARY_DIR}" MATCHES " ")
+  # The Intel compiler does not properly escape spaces in a depfile.
+  # Fall back to msvc depfile format.
+  set(CMAKE_DEPFILE_FLAGS_CXX "/showIncludes")
+  set(CMAKE_CXX_DEPFILE_FORMAT msvc)
+endif()
index 5d8f7fc..01f8dd0 100644 (file)
@@ -8,6 +8,20 @@ if(__WINDOWS_INTEL)
 endif()
 set(__WINDOWS_INTEL 1)
 
+
+if (CMAKE_GENERATOR MATCHES "^Ninja")
+  # retrieve ninja version to enable dependencies configuration
+  # against Ninja capabilities
+  execute_process(COMMAND "${CMAKE_MAKE_PROGRAM}" --version
+    RESULT_VARIABLE _CMAKE_NINJA_RESULT
+    OUTPUT_VARIABLE _CMAKE_NINJA_VERSION
+    ERROR_VARIABLE _CMAKE_NINJA_VERSION)
+  if (NOT _CMAKE_NINJA_RESULT AND _CMAKE_NINJA_VERSION MATCHES "[0-9]+(\\.[0-9]+)*")
+    set (_CMAKE_NINJA_VERSION "${CMAKE_MATCH_0}")
+  endif()
+  unset(_CMAKE_NINJA_RESULT)
+endif()
+
 include(Platform/Windows-MSVC)
 macro(__windows_compiler_intel lang)
   __windows_compiler_msvc(${lang})
diff --git a/Modules/Platform/Windows-IntelLLVM-ASM.cmake b/Modules/Platform/Windows-IntelLLVM-ASM.cmake
new file mode 100644 (file)
index 0000000..f355e49
--- /dev/null
@@ -0,0 +1,2 @@
+include(Platform/Windows-IntelLLVM)
+__windows_compiler_intel(ASM)
diff --git a/Modules/Platform/Windows-IntelLLVM-C.cmake b/Modules/Platform/Windows-IntelLLVM-C.cmake
new file mode 100644 (file)
index 0000000..93c3364
--- /dev/null
@@ -0,0 +1,2 @@
+include(Platform/Windows-IntelLLVM)
+__windows_compiler_intel(C)
diff --git a/Modules/Platform/Windows-IntelLLVM-CXX.cmake b/Modules/Platform/Windows-IntelLLVM-CXX.cmake
new file mode 100644 (file)
index 0000000..4667895
--- /dev/null
@@ -0,0 +1,3 @@
+include(Platform/Windows-IntelLLVM)
+set(_COMPILE_CXX " /TP")
+__windows_compiler_intel(CXX)
diff --git a/Modules/Platform/Windows-IntelLLVM-Fortran.cmake b/Modules/Platform/Windows-IntelLLVM-Fortran.cmake
new file mode 100644 (file)
index 0000000..06d0a00
--- /dev/null
@@ -0,0 +1,44 @@
+include(Platform/Windows-IntelLLVM)
+set(CMAKE_BUILD_TYPE_INIT Debug)
+set(_COMPILE_Fortran " /fpp")
+set(CMAKE_Fortran_MODDIR_FLAG "-module:")
+set(CMAKE_Fortran_STANDARD_LIBRARIES_INIT "user32.lib")
+__windows_compiler_intel(Fortran)
+if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+  set(_LIBSDLL "")
+  set(_DBGLIBS "")
+  set(_THREADS "")
+else()
+  set(_LIBSDLL " /libs:dll")
+  set(_DBGLIBS " /dbglibs")
+  set(_THREADS " /threads")
+endif()
+
+cmake_policy(GET CMP0092 _cmp0092)
+if(NOT _cmp0092 STREQUAL "NEW")
+  string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1")
+endif()
+unset(_cmp0092)
+
+string(APPEND CMAKE_Fortran_FLAGS_INIT " /nologo /fpp${_LIBSDLL}${_THREADS}")
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " /Od /debug:full${_DBGLIBS}")
+string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " /O1 /DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " /O2 /DNDEBUG")
+string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " /O2 /debug:full /DNDEBUG")
+unset(_LIBSDLL)
+unset(_DBGLIBS)
+unset(_THREADS)
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -threads -libs:static)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -threads -libs:dll)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -threads -libs:static -dbglibs)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -threads -libs:dll    -dbglibs)
+
+# Intel Fortran for Windows supports single-threaded RTL but it is
+# not implemented by the Visual Studio integration.
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+  set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreaded                 -libs:static)
+  set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDLL              -libs:dll)
+  set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebug            -libs:static -dbglibs)
+  set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebugDLL         -libs:dll    -dbglibs)
+endif()
diff --git a/Modules/Platform/Windows-IntelLLVM.cmake b/Modules/Platform/Windows-IntelLLVM.cmake
new file mode 100644 (file)
index 0000000..b9ea037
--- /dev/null
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__WINDOWS_INTEL)
+  return()
+endif()
+set(__WINDOWS_INTEL 1)
+
+include(Platform/Windows-MSVC)
+macro(__windows_compiler_intel lang)
+  __windows_compiler_msvc(${lang})
+
+  set(CMAKE_DEPFILE_FLAGS_${lang} "-QMMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")
+  set(CMAKE_${lang}_DEPFILE_FORMAT gcc)
+endmacro()
index cbe1586..67b6827 100644 (file)
@@ -3,3 +3,10 @@ if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 18.0)
   set(_FS_C " /FS")
 endif()
 __windows_compiler_msvc(C)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_C)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
+endif()
index 0e85005..6fea617 100644 (file)
@@ -4,3 +4,10 @@ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
   set(_FS_CXX " /FS")
 endif()
 __windows_compiler_msvc(CXX)
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_CXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
+endif()
index bd08718..e384af4 100644 (file)
@@ -154,7 +154,9 @@ set(CMAKE_BUILD_TYPE_INIT Debug)
 # Compute an architecture family from the architecture id.
 foreach(lang C CXX)
   set(_MSVC_${lang}_ARCHITECTURE_FAMILY "${MSVC_${lang}_ARCHITECTURE_ID}")
-  if(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^ARM64")
+  if(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^ARM64EC")
+    set(_MSVC_${lang}_ARCHITECTURE_FAMILY "ARM64EC")
+  elseif(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^ARM64")
     set(_MSVC_${lang}_ARCHITECTURE_FAMILY "ARM64")
   elseif(_MSVC_${lang}_ARCHITECTURE_FAMILY MATCHES "^ARM")
     set(_MSVC_${lang}_ARCHITECTURE_FAMILY "ARM")
@@ -163,6 +165,14 @@ foreach(lang C CXX)
   endif()
 endforeach()
 
+cmake_policy(GET CMP0117 __WINDOWS_MSVC_CMP0117)
+if(__WINDOWS_MSVC_CMP0117 STREQUAL "NEW")
+  set(_GR "")
+else()
+  set(_GR " /GR")
+endif()
+unset(__WINDOWS_MSVC_CMP0117)
+
 if(WINCE)
   foreach(lang C CXX)
     string(TOUPPER "${_MSVC_${lang}_ARCHITECTURE_FAMILY}" _MSVC_${lang}_ARCHITECTURE_FAMILY_UPPER)
@@ -182,7 +192,7 @@ if(WINCE)
 
   set(_RTC1 "")
   set(_FLAGS_C "")
-  set(_FLAGS_CXX " /GR /EHsc")
+  set(_FLAGS_CXX "${_GR} /EHsc")
 
   foreach(lang C CXX)
     if(_MSVC_${lang}_ARCHITECTURE_FAMILY STREQUAL "ARM")
@@ -204,7 +214,7 @@ if(WINCE)
 elseif(WINDOWS_PHONE OR WINDOWS_STORE)
   set(_PLATFORM_DEFINES "/DWIN32")
   set(_FLAGS_C " /DUNICODE /D_UNICODE")
-  set(_FLAGS_CXX " /DUNICODE /D_UNICODE /GR /EHsc")
+  set(_FLAGS_CXX " /DUNICODE /D_UNICODE${_GR} /EHsc")
   if(WINDOWS_STORE AND MSVC_VERSION GREATER 1899)
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "WindowsApp.lib")
   elseif(WINDOWS_PHONE)
@@ -216,7 +226,9 @@ elseif(WINDOWS_PHONE OR WINDOWS_STORE)
   endif()
 else()
   set(_PLATFORM_DEFINES "/DWIN32")
-
+  if((_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") OR (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC"))
+    set(_PLATFORM_DEFINES "${_PLATFORM_DEFINES} /D_AMD64_ /DAMD64 /D_ARM64EC_ /DARM64EC /D_ARM64EC_WORKAROUND_")
+  endif()
   if(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM")
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib")
   elseif(MSVC_VERSION GREATER 1310)
@@ -226,12 +238,12 @@ else()
       set(_FLAGS_CXX " -frtti -fexceptions")
     else()
       set(_RTC1 "/RTC1")
-      set(_FLAGS_CXX " /GR /EHsc")
+      set(_FLAGS_CXX "${_GR} /EHsc")
     endif()
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib")
   else()
     set(_RTC1 "/GZ")
-    set(_FLAGS_CXX " /GR /GX")
+    set(_FLAGS_CXX "${_GR} /GX")
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib")
   endif()
 
@@ -241,6 +253,8 @@ else()
   endif()
 endif()
 
+unset(_GR)
+
 set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
 
 # executable linker flags
@@ -251,6 +265,8 @@ if(MSVC_C_ARCHITECTURE_ID)
     set(_MACHINE_ARCH_FLAG "/machine:THUMB")
   elseif(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64")
     set(_MACHINE_ARCH_FLAG "/machine:ARM64")
+  elseif(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC")
+    set(_MACHINE_ARCH_FLAG "/machine:ARM64EC")
   elseif(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM")
     set(_MACHINE_ARCH_FLAG "/machine:ARM")
   else()
@@ -261,6 +277,8 @@ elseif(MSVC_CXX_ARCHITECTURE_ID)
     set(_MACHINE_ARCH_FLAG "/machine:THUMB")
   elseif(_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64")
     set(_MACHINE_ARCH_FLAG "/machine:ARM64")
+  elseif(_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC")
+    set(_MACHINE_ARCH_FLAG "/machine:ARM64EC")
   elseif(_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM")
     set(_MACHINE_ARCH_FLAG "/machine:ARM")
   else()
@@ -295,7 +313,11 @@ foreach(t EXE SHARED MODULE)
   string(APPEND CMAKE_${t}_LINKER_FLAGS_RELEASE_INIT " /INCREMENTAL:NO")
 endforeach()
 
-string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+if((_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") OR (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC"))
+  string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " /machine:ARM64X")
+else()
+  string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+endif()
 unset(_MACHINE_ARCH_FLAG)
 
 cmake_policy(GET CMP0091 __WINDOWS_MSVC_CMP0091)
@@ -425,8 +447,14 @@ macro(__windows_compiler_msvc lang)
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -MDd)
   endif()
   set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON)
-  set(CMAKE_NINJA_DEPTYPE_${lang} msvc)
+
   __windows_compiler_msvc_enable_rc("${_PLATFORM_DEFINES} ${_PLATFORM_DEFINES_${lang}}")
+
+  # define generic information about compiler dependencies
+  if (MSVC_VERSION GREATER 1300)
+    set(CMAKE_DEPFILE_FLAGS_${lang} "/showIncludes")
+    set(CMAKE_${lang}_DEPFILE_FORMAT msvc)
+  endif()
 endmacro()
 
 macro(__windows_compiler_msvc_enable_rc flags)
index 43ec889..bda23ab 100644 (file)
@@ -15,6 +15,9 @@ Otherwise it is set to 0.  Currently this functionality is implemented
 for AIX, cygwin, FreeBSD, HPUX, Linux, macOS, QNX, Sun and
 Windows.
 
+.. versionchanged:: 3.15
+  On Linux, returns the container CPU count instead of the host CPU count.
+
 This function is guaranteed to return a positive integer (>=1) if it
 succeeds.  It returns 0 if there's a problem determining the processor
 count.
index 8a769b7..ea8ca73 100644 (file)
@@ -5,19 +5,41 @@
 TestBigEndian
 -------------
 
-Define macro to determine endian type
+.. deprecated:: 3.20
 
-Check if the system is big endian or little endian
+  Supserseded by the :variable:`CMAKE_<LANG>_BYTE_ORDER` variable.
 
-::
+Check if the target architecture is big endian or little endian.
+
+.. command:: test_big_endian
+
+  .. code-block:: cmake
+
+    test_big_endian(<var>)
+
+  Stores in variable ``<var>`` either 1 or 0 indicating whether the
+  target architecture is big or little endian.
 
-  TEST_BIG_ENDIAN(VARIABLE)
-  VARIABLE - variable to store the result to
 #]=======================================================================]
+include_guard()
 
 include(CheckTypeSize)
 
-macro(TEST_BIG_ENDIAN VARIABLE)
+function(TEST_BIG_ENDIAN VARIABLE)
+  if(";${CMAKE_C_BYTE_ORDER};${CMAKE_CXX_BYTE_ORDER};${CMAKE_CUDA_BYTE_ORDER};${CMAKE_OBJC_BYTE_ORDER};${CMAKE_OBJCXX_BYTE_ORDER};" MATCHES ";(BIG_ENDIAN|LITTLE_ENDIAN);")
+    set(order "${CMAKE_MATCH_1}")
+    if(order STREQUAL "BIG_ENDIAN")
+      set("${VARIABLE}" 1 PARENT_SCOPE)
+    else()
+      set("${VARIABLE}" 0 PARENT_SCOPE)
+    endif()
+  else()
+    __TEST_BIG_ENDIAN_LEGACY_IMPL(is_big)
+    set("${VARIABLE}" "${is_big}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+macro(__TEST_BIG_ENDIAN_LEGACY_IMPL VARIABLE)
   if(NOT DEFINED HAVE_${VARIABLE})
     message(CHECK_START "Check if the system is big endian")
     message(CHECK_START "Searching 16 bit integer")
@@ -119,5 +141,3 @@ macro(TEST_BIG_ENDIAN VARIABLE)
       endif()
   endif()
 endmacro()
-
-
index db3fb95..120a54c 100644 (file)
@@ -23,7 +23,8 @@ Creating And Installing JARs
           [VERSION <version>]
           [OUTPUT_NAME <name>]
           [OUTPUT_DIR <dir>]
-          [GENERATE_NATIVE_HEADERS <target> [DESTINATION <dir>]]
+          [GENERATE_NATIVE_HEADERS <target>
+                             [DESTINATION (<dir>|INSTALL <dir> [BUILD <dir>])]]
           )
 
 This command creates a ``<target_name>.jar``.  It compiles the given
@@ -36,17 +37,27 @@ compiling the java sources and also to the dependencies of the target.
 For backwards compatibility, jar files listed as sources are ignored (as
 they have been since the first version of this module).
 
+.. versionadded:: 3.4
+  Support for response files (prefixed by ``@``) in the ``SOURCES`` list.
+
 The default ``OUTPUT_DIR`` can also be changed by setting the variable
 ``CMAKE_JAVA_TARGET_OUTPUT_DIR``.
 
-Optionally, using option ``GENERATE_NATIVE_HEADERS``, native header files can
-be generated for methods declared as native.  These files provide the
-connective glue that allow your Java and C code to interact.  An INTERFACE
-target will be created for an easy usage of generated files.  Sub-option
-``DESTINATION`` can be used to specify the output directory for generated
-header files.
+.. versionadded:: 3.11
+  Optionally, using option ``GENERATE_NATIVE_HEADERS``, native header files can
+  be generated for methods declared as native.  These files provide the
+  connective glue that allow your Java and C code to interact.  An INTERFACE
+  target will be created for an easy usage of generated files.  Sub-option
+  ``DESTINATION`` can be used to specify the output directory for generated
+  header files.
+
+  ``GENERATE_NATIVE_HEADERS`` option requires, at least, version 1.8 of the JDK.
 
-``GENERATE_NATIVE_HEADERS`` option requires, at least, version 1.8 of the JDK.
+.. versionadded:: 3.20
+  ``DESTINATION`` sub-option now supports the possibility to specify different
+  output directories for ``BUILD`` and ``INSTALL`` steps. This is required to
+  export the interface target generated by ``GENERATE_NATIVE_HEADERS`` option.
+  If ``BUILD`` directory is not specified, a default directory will be used.
 
 The ``add_jar()`` function sets the following target properties on
 ``<target_name>``:
@@ -62,6 +73,11 @@ The ``add_jar()`` function sets the following target properties on
   The directory where the class files can be found.  For example to use them
   with ``javah``.
 
+.. versionadded:: 3.20
+  The target generated by option ``GENERATE_NATIVE_HEADERS`` has the property
+  ``NATIVE_HEADERS_DIRECTORY`` which specify the directory holding the native
+  headers.
+
 .. code-block:: cmake
 
  install_jar(<target_name> <destination>)
@@ -77,6 +93,9 @@ described above, and is used by ``install_jar_exports()``.  You can get this
 information with :command:`get_property` and the ``INSTALL_DESTINATION``
 property key.
 
+.. versionadded:: 3.4
+  The second signature with ``DESTINATION`` and ``COMPONENT`` options.
+
 .. code-block:: cmake
 
  install_jni_symlink(<target_name> <destination>)
@@ -86,6 +105,14 @@ This command installs the ``<target_name>`` JNI symlinks to the given
 ``<destination>``.  It should be called in the same scope as ``add_jar()`` or
 it will fail.
 
+.. versionadded:: 3.4
+  The second signature with ``DESTINATION`` and ``COMPONENT`` options.
+
+Exporting JAR Targets
+^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.7
+
 .. code-block:: cmake
 
  install_jar_exports(TARGETS <jars>...
@@ -97,6 +124,9 @@ This command installs a target export file ``<filename>`` for the named jar
 targets to the given ``<destination>`` directory.  Its function is similar to
 that of :command:`install(EXPORTS)`.
 
+.. versionadded:: 3.9
+  The ``NAMESPACE`` option.
+
 .. code-block:: cmake
 
  export_jars(TARGETS <jars>...
@@ -106,6 +136,9 @@ that of :command:`install(EXPORTS)`.
 This command writes a target export file ``<filename>`` for the named ``<jars>``
 targets.  Its function is similar to that of :command:`export`.
 
+.. versionadded:: 3.9
+  The ``NAMESPACE`` option.
+
 
 Examples
 """"""""
@@ -196,6 +229,18 @@ native headers can then be used to compile C/C++ sources with the
   add_library(bar bar.cpp)
   target_link_libraries(bar PRIVATE foo-native)
 
+.. versionadded:: 3.20
+  It is now possible to export the target generated by
+  ``GENERATE_NATIVE_HEADERS`` option.
+
+  .. code-block:: cmake
+
+    add_jar(foo foo.java GENERATE_NATIVE_HEADERS foo-native
+                                                 DESTINATION INSTALL include)
+    install(TARGETS foo-native EXPORT native)
+    install(DIRECTORY "$<TARGET_PROPERTY:foo-native,NATIVE_HEADERS_DIRECTORY>/"
+            DESTINATION include)
+    install(EXPORT native DESTINATION /to/export NAMESPACE foo)
 
 Finding JARs
 ^^^^^^^^^^^^
@@ -316,17 +361,16 @@ Header Generation
               [OUTPUT_NAME <path>|OUTPUT_DIR <path>]
               )
 
-Create C header files from java classes. These files provide the connective glue
-that allow your Java and C code to interact.
+.. versionadded:: 3.4
 
 .. deprecated:: 3.11
-
-.. note::
-
   This command will no longer be supported starting with version 10 of the JDK
   due to the `suppression of javah tool <http://openjdk.java.net/jeps/313>`_.
   The ``add_jar(GENERATE_NATIVE_HEADERS)`` command should be used instead.
 
+Create C header files from java classes. These files provide the connective glue
+that allow your Java and C code to interact.
+
 There are two main signatures for ``create_javah()``.  The first signature
 returns generated files through variable specified by the ``GENERATED_FILES``
 option.  For example:
@@ -406,8 +450,8 @@ function(__java_export_jar VAR TARGET PATH)
 endfunction()
 
 # define helper scripts
-set(_JAVA_EXPORT_TARGETS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/javaTargets.cmake.in)
-set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
+set(_JAVA_EXPORT_TARGETS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJava/javaTargets.cmake.in)
+set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJava/Symlinks.cmake)
 
 if (CMAKE_HOST_WIN32 AND NOT CYGWIN AND CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
     set(_UseJava_PATH_SEP "$<SEMICOLON>")
@@ -473,7 +517,10 @@ function(add_jar _TARGET_NAME)
       if (Java_VERSION VERSION_LESS 1.8)
         message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS is not supported with this version of Java.")
       endif()
-      cmake_parse_arguments (_add_jar_GENERATE_NATIVE_HEADERS "" "DESTINATION" "" ${_add_jar_GENERATE_NATIVE_HEADERS})
+
+      unset (_GENERATE_NATIVE_HEADERS_OUTPUT_DESC)
+
+      cmake_parse_arguments (_add_jar_GENERATE_NATIVE_HEADERS "" "" "DESTINATION" ${_add_jar_GENERATE_NATIVE_HEADERS})
       if (NOT _add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS)
         message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: missing required argument.")
       endif()
@@ -484,11 +531,30 @@ function(add_jar _TARGET_NAME)
       endif()
       if (NOT _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION)
         set (_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir/native_headers")
+      else()
+        list (LENGTH _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION length)
+        if (NOT length EQUAL 1)
+          cmake_parse_arguments (_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION "" "BUILD;INSTALL" "" "${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION}")
+          if (_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_UNPARSED_ARGUMENTS)
+            message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: DESTINATION: ${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_UNPARSED_ARGUMENTS}: unexpected argument(s).")
+          endif()
+          if (NOT _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_INSTALL)
+            message (FATAL_ERROR "ADD_JAR: GENERATE_NATIVE_HEADERS: DESTINATION: INSTALL sub-option is required.")
+          endif()
+          if (NOT _add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD)
+            set(_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir/native_headers")
+          endif()
+          set(_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION "${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD}")
+          set(_GENERATE_NATIVE_HEADERS_OUTPUT_DESC "$<BUILD_INTERFACE:${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_BUILD}>" "$<INSTALL_INTERFACE:${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION_INSTALL}>")
+        endif()
       endif()
 
       set (_GENERATE_NATIVE_HEADERS_TARGET ${_add_jar_GENERATE_NATIVE_HEADERS_UNPARSED_ARGUMENTS})
       set (_GENERATE_NATIVE_HEADERS_OUTPUT_DIR "${_add_jar_GENERATE_NATIVE_HEADERS_DESTINATION}")
       set (_GENERATE_NATIVE_HEADERS -h "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+      if(NOT _GENERATE_NATIVE_HEADERS_OUTPUT_DESC)
+        set(_GENERATE_NATIVE_HEADERS_OUTPUT_DESC "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
+      endif()
     endif()
 
     if (LIBRARY_OUTPUT_PATH)
@@ -636,7 +702,7 @@ function(add_jar _TARGET_NAME)
             COMMAND ${CMAKE_COMMAND}
                 -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
                 -DCMAKE_JAR_CLASSES_PREFIX=${CMAKE_JAR_CLASSES_PREFIX}
-                -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJavaClassFilelist.cmake
+                -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJava/ClassFilelist.cmake
             DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             VERBATIM
@@ -742,8 +808,9 @@ function(add_jar _TARGET_NAME)
     # create an INTERFACE library encapsulating include directory for generated headers
     add_library (${_GENERATE_NATIVE_HEADERS_TARGET} INTERFACE)
     target_include_directories (${_GENERATE_NATIVE_HEADERS_TARGET} INTERFACE
-      "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}"
+      "${_GENERATE_NATIVE_HEADERS_OUTPUT_DESC}"
       ${JNI_INCLUDE_DIRS})
+    set_property(TARGET ${_GENERATE_NATIVE_HEADERS_TARGET} PROPERTY NATIVE_HEADERS_DIRECTORY "${_GENERATE_NATIVE_HEADERS_OUTPUT_DIR}")
     # this INTERFACE library depends on jar generation
     add_dependencies (${_GENERATE_NATIVE_HEADERS_TARGET} ${_TARGET_NAME})
 
similarity index 80%
rename from Modules/UseJavaClassFilelist.cmake
rename to Modules/UseJava/ClassFilelist.cmake
index 1c4baa9..aa9e35d 100644 (file)
@@ -1,18 +1,9 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-#[=======================================================================[.rst:
-UseJavaClassFilelist
---------------------
-
-
-
-
-
-This script create a list of compiled Java class files to be added to
-a jar file.  This avoids including cmake files which get created in
-the binary directory.
-#]=======================================================================]
+# This script creates a list of compiled Java class files to be added to
+# a jar file.  This avoids including cmake files which get created in
+# the binary directory.
 
 if (CMAKE_JAVA_CLASS_OUTPUT_PATH)
     if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
similarity index 72%
rename from Modules/UseJavaSymlinks.cmake
rename to Modules/UseJava/Symlinks.cmake
index 3969f54..2788195 100644 (file)
@@ -1,16 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-#[=======================================================================[.rst:
-UseJavaSymlinks
----------------
-
-
-
-
-
-Helper script for UseJava.cmake
-#]=======================================================================]
+# Helper script for UseJava.cmake
 
 if (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
     if (_JAVA_TARGET_OUTPUT_NAME)
similarity index 96%
rename from Modules/javaTargets.cmake.in
rename to Modules/UseJava/javaTargets.cmake.in
index c5f9c78..6e14256 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 cmake_policy(PUSH)
 cmake_policy(VERSION 2.8)
 
index 757e539..7d7f737 100644 (file)
@@ -12,6 +12,8 @@ Defines the following command for use with ``SWIG``:
 
 .. command:: swig_add_library
 
+  .. versionadded:: 3.8
+
   Define swig module with given name and specified language::
 
     swig_add_library(<name>
@@ -28,13 +30,16 @@ Defines the following command for use with ``SWIG``:
   those targets can be used with any command expecting a target (e.g.
   :command:`target_link_libraries`).
 
-  .. note::
-
+  .. versionchanged:: 3.13
     This command creates a target with the specified ``<name>`` when
     policy :policy:`CMP0078` is set to ``NEW``.  Otherwise, the legacy
     behavior will choose a different target name and store it in the
     ``SWIG_MODULE_<name>_REAL_NAME`` variable.
 
+  .. versionchanged:: 3.15
+    Alternate library name (set with the :prop_tgt:`OUTPUT_NAME` property,
+    for example) will be passed on to Python and CSharp wrapper libraries.
+
   .. note::
 
     For multi-config generators, this module does not support
@@ -43,11 +48,12 @@ Defines the following command for use with ``SWIG``:
 
   .. note::
 
-    For Make-based generators, ``swig_add_library`` does not track file
-    dependencies, so depending on the ``<name>_swig_compilation`` custom target
-    is required for targets which require the ``swig``-generated files to
-    exist. Other generators may depend on the source files that would be
-    generated by SWIG.
+    For :ref:`Makefile Generators`, if, for some sources, the
+    ``USE_SWIG_DEPENDENCIES`` property is ``FALSE``, ``swig_add_library`` does
+    not track file dependencies, so depending on the ``<name>_swig_compilation``
+    custom target is required for targets which require the ``swig``-generated
+    files to exist. Other generators may depend on the source files that would
+    be generated by SWIG.
 
   ``TYPE``
     ``SHARED``, ``MODULE`` and ``STATIC`` have the same semantic as for the
@@ -59,10 +65,23 @@ Defines the following command for use with ``SWIG``:
   ``LANGUAGE``
     Specify the target language.
 
+    .. versionadded:: 3.1
+      Go and Lua language support.
+
+    .. versionadded:: 3.2
+      R language support.
+
+    .. versionadded:: 3.18
+      Fortran language support.
+
   ``NO_PROXY``
+    .. versionadded:: 3.12
+
     Prevent the generation of the wrapper layer (swig ``-noproxy`` option).
 
   ``OUTPUT_DIR``
+    .. versionadded:: 3.12
+
     Specify where to write the language specific files (swig ``-outdir``
     option). If not given, the ``CMAKE_SWIG_OUTDIR`` variable will be used.
     If neither is specified, the default depends on the value of the
@@ -75,6 +94,8 @@ Defines the following command for use with ``SWIG``:
       ``SWIG_SUPPORT_FILES_DIRECTORY`` target property.
 
   ``OUTFILE_DIR``
+    .. versionadded:: 3.12
+
     Specify an output directory name where the generated source file will be
     placed (swig ``-o`` option). If not specified, the ``SWIG_OUTFILE_DIR``
     variable will be used. If neither is specified, ``OUTPUT_DIR`` or
@@ -83,8 +104,11 @@ Defines the following command for use with ``SWIG``:
   ``SOURCES``
     List of sources for the library. Files with extension ``.i`` will be
     identified as sources for the ``SWIG`` tool. Other files will be handled in
-    the standard way. This behavior can be overridden by specifying the variable
-    ``SWIG_SOURCE_FILE_EXTENSIONS``.
+    the standard way.
+
+    .. versionadded:: 3.14
+      This behavior can be overridden by specifying the variable
+      ``SWIG_SOURCE_FILE_EXTENSIONS``.
 
   .. note::
 
@@ -122,12 +146,22 @@ ensure generated files will receive the required settings.
     set_property(SOURCE mymod.i PROPERTY CPLUSPLUS ON)
     swig_add_library(mymod LANGUAGE python SOURCES mymod.i)
 
+``SWIG_FLAGS``
+  .. deprecated:: 3.12
+    Replaced with the fine-grained properties that follow.
+
+  Pass custom flags to the SWIG executable.
+
 ``INCLUDE_DIRECTORIES``, ``COMPILE_DEFINITIONS`` and ``COMPILE_OPTIONS``
+  .. versionadded:: 3.12
+
   Add custom flags to SWIG compiler and have same semantic as properties
   :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and
   :prop_sf:`COMPILE_OPTIONS`.
 
 ``USE_TARGET_INCLUDE_DIRECTORIES``
+  .. versionadded:: 3.13
+
   If set to ``TRUE``, contents of target property
   :prop_tgt:`INCLUDE_DIRECTORIES` will be forwarded to ``SWIG`` compiler.
   If set to ``FALSE`` target property :prop_tgt:`INCLUDE_DIRECTORIES` will be
@@ -135,13 +169,25 @@ ensure generated files will receive the required settings.
   will be considered.
 
 ``GENERATED_INCLUDE_DIRECTORIES``, ``GENERATED_COMPILE_DEFINITIONS`` and ``GENERATED_COMPILE_OPTIONS``
+  .. versionadded:: 3.12
+
   Add custom flags to the C/C++ generated source. They will fill, respectively,
   properties :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and
   :prop_sf:`COMPILE_OPTIONS` of generated C/C++ file.
 
 ``DEPENDS``
+  .. versionadded:: 3.12
+
   Specify additional dependencies to the source file.
 
+``USE_SWIG_DEPENDENCIES``
+  .. versionadded:: 3.20
+
+  If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
+  itself. This property is only meaningful for
+  :ref:`Makefile <Makefile Generators>` and
+  :ref:`Ninja <Ninja Generators>` generators. Default value is ``FALSE``.
+
 ``SWIG_MODULE_NAME``
   Specify the actual import name of the module in the target language.
   This is required if it cannot be scanned automatically from source
@@ -151,18 +197,21 @@ ensure generated files will receive the required settings.
 
     set_property(SOURCE mymod.i PROPERTY SWIG_MODULE_NAME mymod_realname)
 
-  .. note::
-
+  .. versionchanged:: 3.14
     If policy :policy:`CMP0086` is set to ``NEW``, ``-module <module_name>``
     is passed to ``SWIG`` compiler.
 
 ``OUTPUT_DIR``
+  .. versionadded:: 3.19
+
   Specify where to write the language specific files (swig ``-outdir`` option)
   for the considered source file. If not specified, the other ways to define
   the output directory applies (see ``OUTPUT_DIR`` option of
   ``swig_add_library()`` command).
 
 ``OUTFILE_DIR``
+  .. versionadded:: 3.19
+
   Specify an output directory where the generated source file will be placed
   (swig ``-o`` option) for the considered source file. If not specified,
   ``OUTPUT_DIR`` source property will be used. If neither are specified, the
@@ -173,6 +222,8 @@ Target library properties can be set to apply same configuration to all SWIG
 input files.
 
 ``SWIG_INCLUDE_DIRECTORIES``, ``SWIG_COMPILE_DEFINITIONS`` and ``SWIG_COMPILE_OPTIONS``
+  .. versionadded:: 3.12
+
   These properties will be applied to all SWIG input files and have same
   semantic as target properties :prop_tgt:`INCLUDE_DIRECTORIES`,
   :prop_tgt:`COMPILE_DEFINITIONS` and :prop_tgt:`COMPILE_OPTIONS`.
@@ -185,6 +236,8 @@ input files.
     set_property(TARGET mymod PROPERTY SWIG_COMPILE_OPTIONS -bla -blb)
 
 ``SWIG_USE_TARGET_INCLUDE_DIRECTORIES``
+  .. versionadded:: 3.13
+
   If set to ``TRUE``, contents of target property
   :prop_tgt:`INCLUDE_DIRECTORIES` will be forwarded to ``SWIG`` compiler.
   If set to ``FALSE`` or not defined, target property
@@ -192,17 +245,23 @@ input files.
   overridden by specifying source property ``USE_TARGET_INCLUDE_DIRECTORIES``.
 
 ``SWIG_GENERATED_INCLUDE_DIRECTORIES``, ``SWIG_GENERATED_COMPILE_DEFINITIONS`` and ``SWIG_GENERATED_COMPILE_OPTIONS``
+  .. versionadded:: 3.12
+
   These properties will populate, respectively, properties
   :prop_sf:`INCLUDE_DIRECTORIES`, :prop_sf:`COMPILE_DEFINITIONS` and
   :prop_sf:`COMPILE_FLAGS` of all generated C/C++ files.
 
 ``SWIG_DEPENDS``
+  .. versionadded:: 3.12
+
   Add dependencies to all SWIG input files.
 
 The following target properties are output properties and can be used to get
 information about support files generated by ``SWIG`` interface compilation.
 
 ``SWIG_SUPPORT_FILES``
+  .. versionadded:: 3.12
+
   This output property list of wrapper files generated during SWIG compilation.
 
   .. code-block:: cmake
@@ -219,6 +278,8 @@ information about support files generated by ``SWIG`` interface compilation.
     ``SWIG_SUPPORT_FILES_DIRECTORY`` property to handle support files.
 
 ``SWIG_SUPPORT_FILES_DIRECTORY``
+  .. versionadded:: 3.12
+
   This output property specifies the directory where support files will be
   generated.
 
@@ -231,6 +292,8 @@ Some variables can be set to customize the behavior of ``swig_add_library``
 as well as ``SWIG``:
 
 ``UseSWIG_MODULE_VERSION``
+  .. versionadded:: 3.12
+
   Specify different behaviors for ``UseSWIG`` module.
 
   * Set to 1 or undefined: Legacy behavior is applied.
@@ -244,6 +307,8 @@ as well as ``SWIG``:
   Specify where to write the language specific files (swig ``-outdir`` option).
 
 ``SWIG_OUTFILE_DIR``
+  .. versionadded:: 3.8
+
   Specify an output directory name where the generated source file will be
   placed.  If not specified, ``CMAKE_SWIG_OUTDIR`` is used.
 
@@ -251,6 +316,8 @@ as well as ``SWIG``:
   Specify extra dependencies for the generated module for ``<name>``.
 
 ``SWIG_SOURCE_FILE_EXTENSIONS``
+  .. versionadded:: 3.14
+
   Specify a list of source file extensions to override the default
   behavior of considering only ``.i`` files as sources for the ``SWIG``
   tool. For example:
@@ -258,6 +325,17 @@ as well as ``SWIG``:
   .. code-block:: cmake
 
     set(SWIG_SOURCE_FILE_EXTENSIONS ".i" ".swg")
+
+``SWIG_USE_SWIG_DEPENDENCIES``
+  .. versionadded:: 3.20
+
+  If set to ``TRUE``, implicit dependencies are generated by the ``swig`` tool
+  itself. This property is only meaningful for
+  :ref:`Makefile <Makefile Generators>` and
+  :ref:`Ninja <Ninja Generators>` generators. Default value is ``FALSE``.
+
+  Source file property ``USE_SWIG_DEPENDENCIES``, if not defined, will be
+  initialized with the value of this variable.
 #]=======================================================================]
 
 cmake_policy(GET CMP0078 target_name_policy)
@@ -428,6 +506,14 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
     set(target_name ${name})
   endif()
 
+  set (use_swig_dependencies ${SWIG_USE_SWIG_DEPENDENCIES})
+  if (CMAKE_GENERATOR MATCHES "Make|Ninja")
+    get_property(use_swig_dependencies_set SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES SET)
+    if (use_swig_dependencies_set)
+      get_property(use_swig_dependencies SOURCE "${infile}" PROPERTY USE_SWIG_DEPENDENCIES)
+    endif()
+  endif()
+
   set (swig_source_file_flags ${CMAKE_SWIG_FLAGS})
   # handle various swig compile flags properties
   get_source_file_property (include_directories "${infile}" INCLUDE_DIRECTORIES)
@@ -533,7 +619,7 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
   list (APPEND swig_extra_flags ${SWIG_MODULE_${name}_EXTRA_FLAGS})
 
   # dependencies
-  set (swig_dependencies ${SWIG_MODULE_${name}_EXTRA_DEPS} $<TARGET_PROPERTY:${target_name},SWIG_DEPENDS>)
+  set (swig_dependencies DEPENDS ${SWIG_MODULE_${name}_EXTRA_DEPS} $<TARGET_PROPERTY:${target_name},SWIG_DEPENDS>)
   get_source_file_property(file_depends "${infile}" DEPENDS)
   if (file_depends)
     list (APPEND swig_dependencies ${file_depends})
@@ -551,10 +637,11 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
     unset (swig_copy_command)
   endif()
 
-  # IMPLICIT_DEPENDS below can not handle situations where a dependent file is
-  # removed. We need an extra step with timestamp and custom target, see #16830
-  # As this is needed only for Makefile generator do it conditionally
-  if(CMAKE_GENERATOR MATCHES "Make")
+  set(swig_depends_flags)
+  if(NOT use_swig_dependencies AND CMAKE_GENERATOR MATCHES "Make")
+    # IMPLICIT_DEPENDS can not handle situations where a dependent file is
+    # removed. We need an extra step with timestamp and custom target, see #16830
+    # As this is needed only for Makefile generator do it conditionally
     __swig_compute_timestamp(${name} ${SWIG_MODULE_${name}_LANGUAGE}
       "${infile}" "${workingdir}" swig_generated_timestamp)
     set(swig_custom_output "${swig_generated_timestamp}")
@@ -562,11 +649,19 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
       BYPRODUCTS "${swig_generated_file_fullname}" ${swig_extra_generated_files})
     set(swig_timestamp_command
       COMMAND ${CMAKE_COMMAND} -E touch "${swig_generated_timestamp}")
+    list(APPEND swig_dependencies IMPLICIT_DEPENDS CXX "${swig_source_file_fullname}")
   else()
+    set(swig_generated_timestamp)
     set(swig_custom_output
       "${swig_generated_file_fullname}" ${swig_extra_generated_files})
     set(swig_custom_products)
     set(swig_timestamp_command)
+    if (use_swig_dependencies)
+      cmake_path(GET infile FILENAME swig_depends_filename)
+      set(swig_depends_filename "${workingdir}/${swig_depends_filename}.d")
+      list(APPEND swig_dependencies DEPFILE "${swig_depends_filename}")
+      set(swig_depends_flags -MF "${swig_depends_filename}" -MD)
+    endif()
   endif()
   add_custom_command(
     OUTPUT ${swig_custom_output}
@@ -581,13 +676,13 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
     -outdir "${swig_file_outdir}"
     ${swig_special_flags}
     ${swig_extra_flags}
+    ${swig_depends_flags}
     "${swig_include_dirs}"
     -o "${swig_generated_file_fullname}"
     "${swig_source_file_fullname}"
     ${swig_copy_command}
     MAIN_DEPENDENCY "${swig_source_file_fullname}"
-    DEPENDS ${swig_dependencies}
-    IMPLICIT_DEPENDS CXX "${swig_source_file_fullname}"
+    ${swig_dependencies}
     COMMENT "Swig compile ${infile} for ${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
     COMMAND_EXPAND_LISTS)
   set_source_files_properties("${swig_generated_file_fullname}" ${swig_extra_generated_files}
@@ -608,6 +703,7 @@ function(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
   endif()
 
   set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files} PARENT_SCOPE)
+  set(swig_timestamp "${swig_generated_timestamp}" PARENT_SCOPE)
 
   # legacy support
   set (swig_generated_file_fullname "${swig_generated_file_fullname}" PARENT_SCOPE)
@@ -736,6 +832,15 @@ function(SWIG_ADD_LIBRARY name)
     set(SWIG_SOURCE_FILE_EXTENSIONS ".i")
   endif()
 
+  if (CMAKE_GENERATOR MATCHES "Make|Ninja")
+    # For Makefiles and Ninja generators, use SWIG generated dependencies
+    if (NOT DEFINED SWIG_USE_SWIG_DEPENDENCIES)
+        set (SWIG_USE_SWIG_DEPENDENCIES OFF)
+    endif()
+  else()
+    set (SWIG_USE_SWIG_DEPENDENCIES OFF)
+  endif()
+
   # Generate a regex out of file extensions.
   string(REGEX REPLACE "([$^.*+?|()-])" "\\\\\\1" swig_source_ext_regex "${SWIG_SOURCE_FILE_EXTENSIONS}")
   list (JOIN swig_source_ext_regex "|" swig_source_ext_regex)
@@ -763,9 +868,7 @@ function(SWIG_ADD_LIBRARY name)
   foreach(swig_it IN LISTS swig_dot_i_sources)
     SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source "${swig_it}")
     list (APPEND swig_generated_sources "${swig_generated_source}")
-    if(CMAKE_GENERATOR MATCHES "Make")
-      __swig_compute_timestamp(${name} ${SWIG_MODULE_${name}_LANGUAGE} "${swig_it}"
-        "${workingdir}" swig_timestamp)
+    if(swig_timestamp)
       list (APPEND swig_generated_timestamps "${swig_timestamp}")
     endif()
     get_source_file_property(swig_source_file_outdir "${swig_it}" OUTPUT_DIR)
@@ -784,7 +887,7 @@ function(SWIG_ADD_LIBRARY name)
     ${_SAM_TYPE}
     ${swig_generated_sources}
     ${swig_other_sources})
-  if(CMAKE_GENERATOR MATCHES "Make")
+  if(swig_generated_timestamps)
     # see IMPLICIT_DEPENDS above
     add_custom_target(${name}_swig_compilation DEPENDS ${swig_generated_timestamps})
     add_dependencies(${target_name} ${name}_swig_compilation)
index 5100035..5e6828f 100644 (file)
@@ -5,6 +5,10 @@
 WriteCompilerDetectionHeader
 ----------------------------
 
+.. deprecated:: 3.20
+  This module is available only if policy :policy:`CMP0120`
+  is not set to ``NEW``.  Do not use it in new code.
+
 .. versionadded:: 3.1
 
 This module provides the function ``write_compiler_detection_header()``.
@@ -80,19 +84,28 @@ Possible compiler identifiers are documented with the
 Available features in this version of CMake are listed in the
 :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
 :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties.
-The ``{c,cxx}_std_*`` meta-features are ignored if requested.
-
 See the :manual:`cmake-compile-features(7)` manual for information on
 compile features.
 
-``BARE_FEATURES`` will define the compatibility macros with the name used in
-newer versions of the language standard, so the code can use the new feature
-name unconditionally.
+.. versionadded:: 3.2
+  Added ``MSVC`` and ``AppleClang`` compiler support.
+
+.. versionadded:: 3.6
+  Added ``Intel`` compiler support.
+
+.. versionchanged:: 3.8
+  The ``{c,cxx}_std_*`` meta-features are ignored if requested.
 
-``ALLOW_UNKNOWN_COMPILERS`` and ``ALLOW_UNKNOWN_COMPILER_VERSIONS`` cause
-the module to generate conditions that treat unknown compilers as simply
-lacking all features.  Without these options the default behavior is to
-generate a ``#error`` for unknown compilers and versions.
+.. versionadded:: 3.8
+  ``ALLOW_UNKNOWN_COMPILERS`` and ``ALLOW_UNKNOWN_COMPILER_VERSIONS`` cause
+  the module to generate conditions that treat unknown compilers as simply
+  lacking all features.  Without these options the default behavior is to
+  generate a ``#error`` for unknown compilers and versions.
+
+.. versionadded:: 3.12
+  ``BARE_FEATURES`` will define the compatibility macros with the name used in
+  newer versions of the language standard, so the code can use the new feature
+  name unconditionally.
 
 Feature Test Macros
 ===================
@@ -234,6 +247,18 @@ library:
   )
 #]=======================================================================]
 
+# Guard against inclusion by absolute path.
+cmake_policy(GET CMP0120 _WCDH_policy)
+if(_WCDH_policy STREQUAL "NEW")
+  message(FATAL_ERROR "The WriteCompilerDetectionHeader module has been removed by policy CMP0120.")
+elseif(_WCDH_policy STREQUAL "")
+  message(AUTHOR_WARNING
+    "The WriteCompilerDetectionHeader module will be removed by policy CMP0120.  "
+    "Projects should be ported away from the module, perhaps by bundling a copy "
+    "of the generated header or using a third-party alternative."
+    )
+endif()
+
 include(${CMAKE_CURRENT_LIST_DIR}/CMakeCompilerIdDetection.cmake)
 
 function(_load_compiler_variables CompilerId lang)
index ca56d3a..6adc9cf 100644 (file)
@@ -19,7 +19,7 @@ else()
   CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H)
 endif()
 if(HAVE_ELF_H)
-  set(CMAKE_USE_ELF_PARSER 1)
+  set(CMake_USE_ELF_PARSER 1)
 elseif(HAIKU)
   # On Haiku, we need to include elf32.h from the private headers
   set(CMake_HAIKU_INCLUDE_DIRS
@@ -32,13 +32,13 @@ elseif(HAIKU)
   unset(CMAKE_REQUIRED_INCLUDES)
 
   if(HAVE_ELF32_H)
-    set(CMAKE_USE_ELF_PARSER 1)
+    set(CMake_USE_ELF_PARSER 1)
   else()
     unset(CMake_HAIKU_INCLUDE_DIRS)
-    set(CMAKE_USE_ELF_PARSER)
+    set(CMake_USE_ELF_PARSER)
   endif()
 else()
-  set(CMAKE_USE_ELF_PARSER)
+  set(CMake_USE_ELF_PARSER)
 endif()
 
 if(NOT CMake_DEFAULT_RECURSION_LIMIT)
@@ -46,13 +46,19 @@ if(NOT CMake_DEFAULT_RECURSION_LIMIT)
     set(CMake_DEFAULT_RECURSION_LIMIT 100)
   elseif(MINGW)
     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)
+  set(CMake_USE_MACH_PARSER 1)
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+  set(CMake_USE_XCOFF_PARSER 1)
 endif()
 
 set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR})
@@ -106,15 +112,20 @@ include_directories(
   )
 
 # Check if we can build the ELF parser.
-if(CMAKE_USE_ELF_PARSER)
+if(CMake_USE_ELF_PARSER)
   set(ELF_SRCS cmELF.h cmELF.cxx)
 endif()
 
 # Check if we can build the Mach-O parser.
-if(CMAKE_USE_MACH_PARSER)
+if(CMake_USE_MACH_PARSER)
   set(MACH_SRCS cmMachO.h cmMachO.cxx)
 endif()
 
+# Check if we can build the XCOFF parser.
+if(CMake_USE_XCOFF_PARSER)
+  set(XCOFF_SRCS cmXCOFF.h cmXCOFF.cxx)
+endif()
+
 #
 # Sources for CMakeLib
 #
@@ -181,8 +192,6 @@ set(SRCS
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
   cmCacheManager.cxx
   cmCacheManager.h
-  cmCheckCustomOutputs.h
-  cmCheckCustomOutputs.cxx
   cmCLocaleEnvironmentScope.h
   cmCLocaleEnvironmentScope.cxx
   cmCMakePath.h
@@ -227,6 +236,8 @@ set(SRCS
   cmDependsJava.h
   cmDependsJavaParserHelper.cxx
   cmDependsJavaParserHelper.h
+  cmDependsCompiler.cxx
+  cmDependsCompiler.h
   cmDocumentation.cxx
   cmDocumentationFormatter.cxx
   cmDocumentationSection.cxx
@@ -268,6 +279,8 @@ set(SRCS
   cmFileAPICodemodel.h
   cmFileAPICMakeFiles.cxx
   cmFileAPICMakeFiles.h
+  cmFileAPIToolchains.cxx
+  cmFileAPIToolchains.h
   cmFileCopier.cxx
   cmFileCopier.h
   cmFileInstaller.cxx
@@ -444,6 +457,8 @@ set(SRCS
   cmTest.h
   cmTestGenerator.cxx
   cmTestGenerator.h
+  cmTransformDepfile.cxx
+  cmTransformDepfile.h
   cmUuid.cxx
   cmUVHandlePtr.cxx
   cmUVHandlePtr.h
@@ -459,6 +474,7 @@ set(SRCS
   cmWorkerPool.h
   cmWorkingDirectory.cxx
   cmWorkingDirectory.h
+  ${XCOFF_SRCS}
   cmXMLParser.cxx
   cmXMLParser.h
   cmXMLSafe.cxx
@@ -508,6 +524,8 @@ set(SRCS
   cmCMakeLanguageCommand.h
   cmCMakeMinimumRequired.cxx
   cmCMakeMinimumRequired.h
+  cmCMakePathCommand.h
+  cmCMakePathCommand.cxx
   cmCMakePolicyCommand.cxx
   cmCMakePolicyCommand.h
   cmConditionEvaluator.cxx
@@ -833,6 +851,7 @@ endif()
 
 # Ninja support
 set(SRCS ${SRCS}
+  cmScanDepFormat.cxx
   cmGlobalNinjaGenerator.cxx
   cmGlobalNinjaGenerator.h
   cmNinjaTypes.h
@@ -1157,20 +1176,6 @@ add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE})
 list(APPEND _tools cmake)
 target_link_libraries(cmake CMakeLib)
 
-add_library(CMakeServerLib
-  cmConnection.h cmConnection.cxx
-  cmFileMonitor.cxx cmFileMonitor.h
-  cmJsonObjectDictionary.h
-  cmJsonObjects.h
-  cmJsonObjects.cxx
-  cmPipeConnection.cxx cmPipeConnection.h
-  cmServer.cxx cmServer.h
-  cmServerConnection.cxx cmServerConnection.h
-  cmServerProtocol.cxx cmServerProtocol.h
-  )
-target_link_libraries(CMakeServerLib CMakeLib)
-target_link_libraries(cmake CMakeServerLib)
-
 # Build CTest executable
 add_executable(ctest ctest.cxx ${MANIFEST_FILE})
 list(APPEND _tools ctest)
index c1db62b..a0713ba 100644 (file)
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
-set(CMake_VERSION_MINOR 19)
-set(CMake_VERSION_PATCH 8)
+set(CMake_VERSION_MINOR 20)
+set(CMake_VERSION_PATCH 0)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
@@ -21,7 +21,7 @@ endif()
 
 if(NOT CMake_VERSION_NO_GIT)
   # If this source was exported by 'git archive', use its commit info.
-  set(git_info [==[c9b27dace7 CMake 3.19.8]==])
+  set(git_info [==[b7b0fb4303 CMake 3.20.0]==])
 
   # Otherwise, try to identify the current development source version.
   if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* "
index 20d392d..87ebbfe 100644 (file)
@@ -44,7 +44,7 @@ bool cmCPackIFWCommon::IsSetToEmpty(const std::string& op) const
                          : false;
 }
 
-bool cmCPackIFWCommon::IsVersionLess(const char* version)
+bool cmCPackIFWCommon::IsVersionLess(const char* version) const
 {
   if (!this->Generator) {
     return false;
@@ -54,7 +54,7 @@ bool cmCPackIFWCommon::IsVersionLess(const char* version)
     cmSystemTools::OP_LESS, this->Generator->FrameworkVersion.data(), version);
 }
 
-bool cmCPackIFWCommon::IsVersionGreater(const char* version)
+bool cmCPackIFWCommon::IsVersionGreater(const char* version) const
 {
   if (!this->Generator) {
     return false;
@@ -65,7 +65,7 @@ bool cmCPackIFWCommon::IsVersionGreater(const char* version)
     version);
 }
 
-bool cmCPackIFWCommon::IsVersionEqual(const char* version)
+bool cmCPackIFWCommon::IsVersionEqual(const char* version) const
 {
   if (!this->Generator) {
     return false;
@@ -118,7 +118,7 @@ void cmCPackIFWCommon::ExpandListArgument(
   }
 }
 
-void cmCPackIFWCommon::WriteGeneratedByToStrim(cmXMLWriter& xout)
+void cmCPackIFWCommon::WriteGeneratedByToStrim(cmXMLWriter& xout) const
 {
   if (!this->Generator) {
     return;
index 95ed213..42deda4 100644 (file)
@@ -34,17 +34,17 @@ public:
   /**
    * Compare \a version with QtIFW framework version
    */
-  bool IsVersionLess(const char* version);
+  bool IsVersionLess(const char* version) const;
 
   /**
    * Compare \a version with QtIFW framework version
    */
-  bool IsVersionGreater(const char* version);
+  bool IsVersionGreater(const char* version) const;
 
   /**
    * Compare \a version with QtIFW framework version
    */
-  bool IsVersionEqual(const char* version);
+  bool IsVersionEqual(const char* version) const;
 
   /** Expand the list argument containing the map of the key-value pairs.
    *  If the number of elements is odd, then the first value is used as the
@@ -64,7 +64,7 @@ public:
   cmCPackIFWGenerator* Generator;
 
 protected:
-  void WriteGeneratedByToStrim(cmXMLWriter& xout);
+  void WriteGeneratedByToStrim(cmXMLWriter& xout) const;
 };
 
 #define cmCPackIFWLogger(logType, msg)                                        \
index 4bad598..bf8b457 100644 (file)
@@ -66,7 +66,7 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
         this->GetOption("CPACK_IFW_PACKAGE_PUBLISHER")) {
     this->Publisher = optIFW_PACKAGE_PUBLISHER;
   } else if (const char* optPACKAGE_VENDOR =
-               GetOption("CPACK_PACKAGE_VENDOR")) {
+               this->GetOption("CPACK_PACKAGE_VENDOR")) {
     this->Publisher = optPACKAGE_VENDOR;
   }
 
@@ -174,6 +174,35 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
     this->WizardDefaultHeight = option;
   }
 
+  // WizardShowPageList
+  if (const char* option =
+        this->GetOption("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
+    if (!this->IsVersionLess("4.0")) {
+      if (this->IsSetToOff("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
+        this->WizardShowPageList = "false";
+      } else if (this->IsOn("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) {
+        this->WizardShowPageList = "true";
+      } else {
+        this->WizardShowPageList.clear();
+      }
+    } else {
+      std::string currentVersionMsg;
+      if (this->Generator) {
+        currentVersionMsg =
+          "QtIFW version " + this->Generator->FrameworkVersion;
+      } else {
+        currentVersionMsg = "an older QtIFW version";
+      }
+      cmCPackIFWLogger(
+        WARNING,
+        "Option CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST is set to \""
+          << option
+          << "\", but it is only supported with QtIFW version 4.0 or later. "
+             "It is being ignored because you are using "
+          << currentVersionMsg << std::endl);
+    }
+  }
+
   // TitleColor
   if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_TITLE_COLOR")) {
     this->TitleColor = option;
@@ -184,7 +213,7 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
         this->GetOption("CPACK_IFW_PACKAGE_START_MENU_DIRECTORY")) {
     this->StartMenuDir = optIFW_START_MENU_DIR;
   } else {
-    this->StartMenuDir = Name;
+    this->StartMenuDir = this->Name;
   }
 
   // Default target directory for installation
@@ -255,9 +284,8 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
 class cmCPackIFWResourcesParser : public cmXMLParser
 {
 public:
-  cmCPackIFWResourcesParser(cmCPackIFWInstaller* i)
+  explicit cmCPackIFWResourcesParser(cmCPackIFWInstaller* i)
     : installer(i)
-    , file(false)
   {
     this->path = i->Directory + "/resources";
   }
@@ -276,14 +304,16 @@ public:
   }
 
   cmCPackIFWInstaller* installer;
-  bool file, hasFiles, hasErrors;
+  bool file = false;
+  bool hasFiles = false;
+  bool hasErrors = false;
   std::string path, basePath;
 
 protected:
   void StartElement(const std::string& name, const char** /*atts*/) override
   {
     this->file = name == "file";
-    if (file) {
+    if (this->file) {
       this->hasFiles = true;
     }
   }
@@ -317,7 +347,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile()
 
   xout.StartDocument();
 
-  WriteGeneratedByToStrim(xout);
+  this->WriteGeneratedByToStrim(xout);
 
   xout.StartElement("Installer");
 
@@ -408,6 +438,11 @@ void cmCPackIFWInstaller::GenerateInstallerFile()
     xout.Element("WizardDefaultHeight", this->WizardDefaultHeight);
   }
 
+  // WizardShowPageList
+  if (!this->IsVersionLess("4.0") && !this->WizardShowPageList.empty()) {
+    xout.Element("WizardShowPageList", this->WizardShowPageList);
+  }
+
   // TitleColor
   if (!this->TitleColor.empty()) {
     xout.Element("TitleColor", this->TitleColor);
@@ -510,7 +545,7 @@ void cmCPackIFWInstaller::GeneratePackageFiles()
       package.ConfigureFromGroup(option);
       std::string forcedOption = "CPACK_IFW_COMPONENT_GROUP_" +
         cmsys::SystemTools::UpperCase(option) + "_FORCED_INSTALLATION";
-      if (!GetOption(forcedOption)) {
+      if (!this->GetOption(forcedOption)) {
         package.ForcedInstallation = "true";
       }
     } else {
index 6f398e3..a031fc2 100644 (file)
@@ -80,6 +80,10 @@ public:
   /// Wizard height
   std::string WizardDefaultHeight;
 
+  /// Set to false if the widget listing installer pages on the left side
+  /// of the wizard should not be shown
+  std::string WizardShowPageList;
+
   /// Title color
   std::string TitleColor;
 
index 56a74c5..c4bd7f1 100644 (file)
@@ -337,7 +337,7 @@ int cmCPackIFWPackage::ConfigureFromGroup(const std::string& groupName)
 
   group.Name = groupName;
 
-  if (Generator) {
+  if (this->Generator) {
     this->Name = this->Generator->GetGroupPackageName(&group);
   } else {
     this->Name = group.Name;
@@ -530,7 +530,7 @@ void cmCPackIFWPackage::GeneratePackageFile()
 
   xout.StartDocument();
 
-  WriteGeneratedByToStrim(xout);
+  this->WriteGeneratedByToStrim(xout);
 
   xout.StartElement("Package");
 
@@ -577,7 +577,7 @@ void cmCPackIFWPackage::GeneratePackageFile()
   }
 
   // User Interfaces (copy to meta dir)
-  std::vector<std::string> userInterfaces = UserInterfaces;
+  std::vector<std::string> userInterfaces = this->UserInterfaces;
   for (std::string& userInterface : userInterfaces) {
     std::string name = cmSystemTools::GetFilenameName(userInterface);
     std::string path = this->Directory + "/meta/" + name;
@@ -593,7 +593,7 @@ void cmCPackIFWPackage::GeneratePackageFile()
   }
 
   // Translations (copy to meta dir)
-  std::vector<std::string> translations = Translations;
+  std::vector<std::string> translations = this->Translations;
   for (std::string& translation : translations) {
     std::string name = cmSystemTools::GetFilenameName(translation);
     std::string path = this->Directory + "/meta/" + name;
index dbd5540..0cc6f2f 100644 (file)
@@ -53,7 +53,7 @@ public:
 
     bool operator<(const DependenceStruct& other) const
     {
-      return Name < other.Name;
+      return this->Name < other.Name;
     }
   };
 
index f5e8744..7ec2256 100644 (file)
@@ -46,9 +46,9 @@ bool cmCPackIFWRepository::ConfigureFromOptions()
   // Update
   if (this->IsOn(prefix + "ADD")) {
     this->Update = cmCPackIFWRepository::Add;
-  } else if (IsOn(prefix + "REMOVE")) {
+  } else if (this->IsOn(prefix + "REMOVE")) {
     this->Update = cmCPackIFWRepository::Remove;
-  } else if (IsOn(prefix + "REPLACE")) {
+  } else if (this->IsOn(prefix + "REPLACE")) {
     this->Update = cmCPackIFWRepository::Replace;
   } else {
     this->Update = cmCPackIFWRepository::None;
@@ -199,7 +199,7 @@ bool cmCPackIFWRepository::PatchUpdatesXml()
   return cmSystemTools::RenameFile(updatesPatchXml, updatesXml);
 }
 
-void cmCPackIFWRepository::WriteRepositoryConfig(cmXMLWriter& xout)
+void cmCPackIFWRepository::WriteRepositoryConfig(cmXMLWriter& xout) const
 {
   xout.StartElement("Repository");
 
@@ -225,7 +225,7 @@ void cmCPackIFWRepository::WriteRepositoryConfig(cmXMLWriter& xout)
   xout.EndElement();
 }
 
-void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout)
+void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout) const
 {
   xout.StartElement("Repository");
 
@@ -247,7 +247,7 @@ void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout)
   if (this->Update == cmCPackIFWRepository::Add ||
       this->Update == cmCPackIFWRepository::Remove) {
     xout.Attribute("url", this->Url);
-  } else if (Update == cmCPackIFWRepository::Replace) {
+  } else if (this->Update == cmCPackIFWRepository::Replace) {
     xout.Attribute("oldUrl", this->OldUrl);
     xout.Attribute("newUrl", this->NewUrl);
   }
index 21afd8b..0153452 100644 (file)
@@ -76,8 +76,8 @@ public:
 
   bool PatchUpdatesXml();
 
-  void WriteRepositoryConfig(cmXMLWriter& xout);
-  void WriteRepositoryUpdate(cmXMLWriter& xout);
+  void WriteRepositoryConfig(cmXMLWriter& xout) const;
+  void WriteRepositoryUpdate(cmXMLWriter& xout) const;
   void WriteRepositoryUpdates(cmXMLWriter& xout);
 
   RepositoriesVector RepositoryUpdate;
index 967cc60..7fd12dd 100644 (file)
@@ -80,10 +80,10 @@ std::string cmCPackArchiveGenerator::GetArchiveComponentFileName(
     packageFileName +=
       this->GetOption("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME");
   } else if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
-    packageFileName += GetComponentPackageFileName(
+    packageFileName += this->GetComponentPackageFileName(
       this->GetOption("CPACK_ARCHIVE_FILE_NAME"), component, isGroupName);
   } else {
-    packageFileName += GetComponentPackageFileName(
+    packageFileName += this->GetComponentPackageFileName(
       this->GetOption("CPACK_PACKAGE_FILE_NAME"), component, isGroupName);
   }
 
@@ -181,7 +181,7 @@ int cmCPackArchiveGenerator::addOneComponentToArchive(
 
 int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
 {
-  packageFileNames.clear();
+  this->packageFileNames.clear();
   // The default behavior is to have one package by component group
   // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
   if (!ignoreGroup) {
@@ -189,7 +189,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
       cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                     "Packaging component group: " << compG.first << std::endl);
       // Begin the archive for this group
-      std::string packageFileName = std::string(toplevel) + "/" +
+      std::string packageFileName = std::string(this->toplevel) + "/" +
         this->GetArchiveComponentFileName(compG.first, true);
 
       // open a block in order to automatically close archive
@@ -199,11 +199,11 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
         // now iterate over the component of this group
         for (cmCPackComponent* comp : (compG.second).Components) {
           // Add the files of this component to the archive
-          addOneComponentToArchive(archive, comp);
+          this->addOneComponentToArchive(archive, comp);
         }
       }
       // add the generated package to package file names list
-      packageFileNames.push_back(std::move(packageFileName));
+      this->packageFileNames.push_back(std::move(packageFileName));
     }
     // Handle Orphan components (components not belonging to any groups)
     for (auto& comp : this->Components) {
@@ -217,7 +217,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
             << std::endl);
         std::string localToplevel(
           this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
-        std::string packageFileName = std::string(toplevel);
+        std::string packageFileName = std::string(this->toplevel);
 
         localToplevel += "/" + comp.first;
         packageFileName +=
@@ -226,10 +226,10 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
         {
           DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
           // Add the files of this component to the archive
-          addOneComponentToArchive(archive, &(comp.second));
+          this->addOneComponentToArchive(archive, &(comp.second));
         }
         // add the generated package to package file names list
-        packageFileNames.push_back(std::move(packageFileName));
+        this->packageFileNames.push_back(std::move(packageFileName));
       }
     }
   }
@@ -238,7 +238,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
   else {
     for (auto& comp : this->Components) {
       std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
-      std::string packageFileName = std::string(toplevel);
+      std::string packageFileName = std::string(this->toplevel);
 
       localToplevel += "/" + comp.first;
       packageFileName +=
@@ -247,10 +247,10 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
       {
         DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
         // Add the files of this component to the archive
-        addOneComponentToArchive(archive, &(comp.second));
+        this->addOneComponentToArchive(archive, &(comp.second));
       }
       // add the generated package to package file names list
-      packageFileNames.push_back(std::move(packageFileName));
+      this->packageFileNames.push_back(std::move(packageFileName));
     }
   }
   return 1;
@@ -259,17 +259,17 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
 int cmCPackArchiveGenerator::PackageComponentsAllInOne()
 {
   // reset the package file names
-  packageFileNames.clear();
-  packageFileNames.emplace_back(toplevel);
-  packageFileNames[0] += "/";
+  this->packageFileNames.clear();
+  this->packageFileNames.emplace_back(this->toplevel);
+  this->packageFileNames[0] += "/";
 
   if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
-    packageFileNames[0] += this->GetOption("CPACK_ARCHIVE_FILE_NAME");
+    this->packageFileNames[0] += this->GetOption("CPACK_ARCHIVE_FILE_NAME");
   } else {
-    packageFileNames[0] += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+    this->packageFileNames[0] += this->GetOption("CPACK_PACKAGE_FILE_NAME");
   }
 
-  packageFileNames[0] += this->GetOutputExtension();
+  this->packageFileNames[0] += this->GetOutputExtension();
 
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                 "Packaging all groups in one package..."
@@ -280,7 +280,7 @@ int cmCPackArchiveGenerator::PackageComponentsAllInOne()
   // The ALL COMPONENTS in ONE package case
   for (auto& comp : this->Components) {
     // Add the files of this component to the archive
-    addOneComponentToArchive(archive, &(comp.second));
+    this->addOneComponentToArchive(archive, &(comp.second));
   }
 
   // archive goes out of scope so it will finalized and closed.
@@ -289,41 +289,42 @@ int cmCPackArchiveGenerator::PackageComponentsAllInOne()
 
 int cmCPackArchiveGenerator::PackageFiles()
 {
-  cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+  cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                "Toplevel: " << this->toplevel << std::endl);
 
-  if (WantsComponentInstallation()) {
+  if (this->WantsComponentInstallation()) {
     // CASE 1 : COMPONENT ALL-IN-ONE package
     // If ALL COMPONENTS in ONE package has been requested
     // then the package file is unique and should be open here.
-    if (componentPackageMethod == ONE_PACKAGE) {
-      return PackageComponentsAllInOne();
+    if (this->componentPackageMethod == ONE_PACKAGE) {
+      return this->PackageComponentsAllInOne();
     }
     // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
     // There will be 1 package for each component group
     // however one may require to ignore component group and
     // in this case you'll get 1 package for each component.
-    return PackageComponents(componentPackageMethod ==
-                             ONE_PACKAGE_PER_COMPONENT);
+    return this->PackageComponents(this->componentPackageMethod ==
+                                   ONE_PACKAGE_PER_COMPONENT);
   }
 
   // CASE 3 : NON COMPONENT package.
   DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
-  cmWorkingDirectory workdir(toplevel);
+  cmWorkingDirectory workdir(this->toplevel);
   if (workdir.Failed()) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Failed to change working directory to "
-                    << toplevel << " : "
+                    << this->toplevel << " : "
                     << std::strerror(workdir.GetLastResult()) << std::endl);
     return 0;
   }
-  for (std::string const& file : files) {
+  for (std::string const& file : this->files) {
     // Get the relative path to the file
-    std::string rp = cmSystemTools::RelativePath(toplevel, file);
+    std::string rp = cmSystemTools::RelativePath(this->toplevel, file);
     archive.Add(rp, 0, nullptr, false);
     if (!archive) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Problem while adding file <"
-                      << file << "> to archive <" << packageFileNames[0]
+                      << file << "> to archive <" << this->packageFileNames[0]
                       << ">, ERROR = " << archive.GetError() << std::endl);
       return 0;
     }
@@ -342,7 +343,7 @@ bool cmCPackArchiveGenerator::SupportsComponentInstallation() const
   // The Component installation support should only
   // be activated if explicitly requested by the user
   // (for backward compatibility reason)
-  return IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL");
+  return this->IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL");
 }
 
 bool cmCPackArchiveGenerator::SetArchiveOptions(cmArchiveWrite* archive)
@@ -352,8 +353,12 @@ bool cmCPackArchiveGenerator::SetArchiveOptions(cmArchiveWrite* archive)
   // cause spurious errors to be raised from `strtoull`.
   if (this->Compress == cmArchiveWrite::CompressXZ) {
     const char* threads = "1";
+
+    // CPACK_ARCHIVE_THREADS overrides CPACK_THREADS
     if (this->IsSet("CPACK_ARCHIVE_THREADS")) {
       threads = this->GetOption("CPACK_ARCHIVE_THREADS");
+    } else if (this->IsSet("CPACK_THREADS")) {
+      threads = this->GetOption("CPACK_THREADS");
     }
 
     if (!archive->SetFilterOption("xz", "threads", threads)) {
index d40e5fc..4305c7e 100644 (file)
@@ -25,6 +25,6 @@ unsigned long cmCPackComponent::GetInstalledSize(
 unsigned long cmCPackComponent::GetInstalledSizeInKbytes(
   const std::string& installDir) const
 {
-  unsigned long result = (GetInstalledSize(installDir) + 512) / 1024;
+  unsigned long result = (this->GetInstalledSize(installDir) + 512) / 1024;
   return result ? result : 1;
 }
index 560e5c1..e7bcfac 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCPackDebGenerator.h"
 
+#include <cstdlib>
 #include <cstring>
 #include <map>
 #include <ostream>
@@ -28,7 +29,7 @@ class DebGenerator
 public:
   DebGenerator(cmCPackLog* logger, std::string outputName, std::string workDir,
                std::string topLevelDir, std::string temporaryDir,
-               const char* debianCompressionType,
+               const char* debianCompressionType, const char* numThreads,
                const char* debianArchiveType,
                std::map<std::string, std::string> controlValues,
                bool genShLibs, std::string shLibsFilename, bool genPostInst,
@@ -53,6 +54,7 @@ private:
   const std::string TopLevelDir;
   const std::string TemporaryDir;
   const char* DebianArchiveType;
+  int NumThreads;
   const std::map<std::string, std::string> ControlValues;
   const bool GenShLibs;
   const std::string ShLibsFilename;
@@ -69,7 +71,8 @@ private:
 DebGenerator::DebGenerator(
   cmCPackLog* logger, std::string outputName, std::string workDir,
   std::string topLevelDir, std::string temporaryDir,
-  const char* debianCompressionType, const char* debianArchiveType,
+  const char* debianCompressionType, const char* numThreads,
+  const char* debianArchiveType,
   std::map<std::string, std::string> controlValues, bool genShLibs,
   std::string shLibsFilename, bool genPostInst, std::string postInst,
   bool genPostRm, std::string postRm, const char* controlExtra,
@@ -96,45 +99,62 @@ DebGenerator::DebGenerator(
   }
 
   if (!strcmp(debianCompressionType, "lzma")) {
-    CompressionSuffix = ".lzma";
-    TarCompressionType = cmArchiveWrite::CompressLZMA;
+    this->CompressionSuffix = ".lzma";
+    this->TarCompressionType = cmArchiveWrite::CompressLZMA;
   } else if (!strcmp(debianCompressionType, "xz")) {
-    CompressionSuffix = ".xz";
-    TarCompressionType = cmArchiveWrite::CompressXZ;
+    this->CompressionSuffix = ".xz";
+    this->TarCompressionType = cmArchiveWrite::CompressXZ;
   } else if (!strcmp(debianCompressionType, "bzip2")) {
-    CompressionSuffix = ".bz2";
-    TarCompressionType = cmArchiveWrite::CompressBZip2;
+    this->CompressionSuffix = ".bz2";
+    this->TarCompressionType = cmArchiveWrite::CompressBZip2;
   } else if (!strcmp(debianCompressionType, "gzip")) {
-    CompressionSuffix = ".gz";
-    TarCompressionType = cmArchiveWrite::CompressGZip;
+    this->CompressionSuffix = ".gz";
+    this->TarCompressionType = cmArchiveWrite::CompressGZip;
   } else if (!strcmp(debianCompressionType, "none")) {
-    CompressionSuffix.clear();
-    TarCompressionType = cmArchiveWrite::CompressNone;
+    this->CompressionSuffix.clear();
+    this->TarCompressionType = cmArchiveWrite::CompressNone;
   } else {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error unrecognized compression type: "
                     << debianCompressionType << std::endl);
   }
+
+  if (numThreads == nullptr) {
+    numThreads = "1";
+  }
+
+  char* endptr;
+  this->NumThreads = static_cast<int>(strtol(numThreads, &endptr, 10));
+  if (numThreads != endptr && *endptr != '\0') {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Unrecognized number of threads: " << numThreads
+                                                     << std::endl);
+  }
+
+  if (this->NumThreads < 0) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Number of threads cannot be negative" << std::endl);
+  }
 }
 
 bool DebGenerator::generate() const
 {
-  generateDebianBinaryFile();
-  generateControlFile();
-  if (!generateDataTar()) {
+  this->generateDebianBinaryFile();
+  this->generateControlFile();
+  if (!this->generateDataTar()) {
     return false;
   }
-  std::string md5Filename = generateMD5File();
-  if (!generateControlTar(md5Filename)) {
+  std::string md5Filename = this->generateMD5File();
+  if (!this->generateControlTar(md5Filename)) {
     return false;
   }
-  return generateDeb();
+  return this->generateDeb();
 }
 
 void DebGenerator::generateDebianBinaryFile() const
 {
   // debian-binary file
-  const std::string dbfilename = WorkDir + "/debian-binary";
+  const std::string dbfilename = this->WorkDir + "/debian-binary";
   cmGeneratedFileStream out;
   out.Open(dbfilename, false, true);
   out << "2.0\n"; // required for valid debian package
@@ -142,18 +162,18 @@ void DebGenerator::generateDebianBinaryFile() const
 
 void DebGenerator::generateControlFile() const
 {
-  std::string ctlfilename = WorkDir + "/control";
+  std::string ctlfilename = this->WorkDir + "/control";
 
   cmGeneratedFileStream out;
   out.Open(ctlfilename, false, true);
-  for (auto const& kv : ControlValues) {
+  for (auto const& kv : this->ControlValues) {
     out << kv.first << ": " << kv.second << "\n";
   }
 
   unsigned long totalSize = 0;
   {
-    std::string dirName = cmStrCat(TemporaryDir, '/');
-    for (std::string const& file : PackageFiles) {
+    std::string dirName = cmStrCat(this->TemporaryDir, '/');
+    for (std::string const& file : this->PackageFiles) {
       totalSize += cmSystemTools::FileLength(file);
     }
   }
@@ -162,7 +182,8 @@ void DebGenerator::generateControlFile() const
 
 bool DebGenerator::generateDataTar() const
 {
-  std::string filename_data_tar = WorkDir + "/data.tar" + CompressionSuffix;
+  std::string filename_data_tar =
+    this->WorkDir + "/data.tar" + this->CompressionSuffix;
   cmGeneratedFileStream fileStream_data_tar;
   fileStream_data_tar.Open(filename_data_tar, false, true);
   if (!fileStream_data_tar) {
@@ -171,8 +192,8 @@ bool DebGenerator::generateDataTar() const
                     << filename_data_tar << "\" for writing" << std::endl);
     return false;
   }
-  cmArchiveWrite data_tar(fileStream_data_tar, TarCompressionType,
-                          DebianArchiveType);
+  cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType,
+                          this->DebianArchiveType, 0, this->NumThreads);
   data_tar.Open();
 
   // uid/gid should be the one of the root user, and this root user has
@@ -184,16 +205,16 @@ bool DebGenerator::generateDataTar() const
   // collect all top level install dirs for that
   // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
   // give /usr and /opt
-  size_t topLevelLength = WorkDir.length();
+  size_t topLevelLength = this->WorkDir.length();
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                "WDIR: \"" << WorkDir << "\", length = " << topLevelLength
-                           << std::endl);
+                "WDIR: \"" << this->WorkDir
+                           << "\", length = " << topLevelLength << std::endl);
   std::set<std::string> orderedFiles;
 
   // we have to reconstruct the parent folders as well
 
-  for (std::string currentPath : PackageFiles) {
-    while (currentPath != WorkDir) {
+  for (std::string currentPath : this->PackageFiles) {
+    while (currentPath != this->WorkDir) {
       // the last one IS WorkDir, but we do not want this one:
       // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
       // should not add XXX/application
@@ -235,7 +256,7 @@ bool DebGenerator::generateDataTar() const
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Problem adding file to tar:"
                       << std::endl
-                      << "#top level directory: " << WorkDir << std::endl
+                      << "#top level directory: " << this->WorkDir << std::endl
                       << "#file: " << file << std::endl
                       << "#error:" << data_tar.GetError() << std::endl);
       return false;
@@ -246,13 +267,13 @@ bool DebGenerator::generateDataTar() const
 
 std::string DebGenerator::generateMD5File() const
 {
-  std::string md5filename = WorkDir + "/md5sums";
+  std::string md5filename = this->WorkDir + "/md5sums";
 
   cmGeneratedFileStream out;
   out.Open(md5filename, false, true);
 
-  std::string topLevelWithTrailingSlash = cmStrCat(TemporaryDir, '/');
-  for (std::string const& file : PackageFiles) {
+  std::string topLevelWithTrailingSlash = cmStrCat(this->TemporaryDir, '/');
+  for (std::string const& file : this->PackageFiles) {
     // hash only regular files
     if (cmSystemTools::FileIsDirectory(file) ||
         cmSystemTools::FileIsSymlink(file)) {
@@ -281,7 +302,7 @@ std::string DebGenerator::generateMD5File() const
 
 bool DebGenerator::generateControlTar(std::string const& md5Filename) const
 {
-  std::string filename_control_tar = WorkDir + "/control.tar.gz";
+  std::string filename_control_tar = this->WorkDir + "/control.tar.gz";
 
   cmGeneratedFileStream fileStream_control_tar;
   fileStream_control_tar.Open(filename_control_tar, false, true);
@@ -292,7 +313,8 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
     return false;
   }
   cmArchiveWrite control_tar(fileStream_control_tar,
-                             cmArchiveWrite::CompressGZip, DebianArchiveType);
+                             cmArchiveWrite::CompressGZip,
+                             this->DebianArchiveType);
   control_tar.Open();
 
   // sets permissions and uid/gid for the files
@@ -314,24 +336,25 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
   control_tar.SetPermissions(permission644);
 
   // adds control and md5sums
-  if (!control_tar.Add(md5Filename, WorkDir.length(), ".") ||
-      !control_tar.Add(WorkDir + "/control", WorkDir.length(), ".")) {
+  if (!control_tar.Add(md5Filename, this->WorkDir.length(), ".") ||
+      !control_tar.Add(this->WorkDir + "/control", this->WorkDir.length(),
+                       ".")) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error adding file to tar:"
                     << std::endl
-                    << "#top level directory: " << WorkDir << std::endl
+                    << "#top level directory: " << this->WorkDir << std::endl
                     << "#file: \"control\" or \"md5sums\"" << std::endl
                     << "#error:" << control_tar.GetError() << std::endl);
     return false;
   }
 
   // adds generated shlibs file
-  if (GenShLibs) {
-    if (!control_tar.Add(ShLibsFilename, WorkDir.length(), ".")) {
+  if (this->GenShLibs) {
+    if (!control_tar.Add(this->ShLibsFilename, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Error adding file to tar:"
                       << std::endl
-                      << "#top level directory: " << WorkDir << std::endl
+                      << "#top level directory: " << this->WorkDir << std::endl
                       << "#file: \"shlibs\"" << std::endl
                       << "#error:" << control_tar.GetError() << std::endl);
       return false;
@@ -339,13 +362,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
   }
 
   // adds LDCONFIG related files
-  if (GenPostInst) {
+  if (this->GenPostInst) {
     control_tar.SetPermissions(permission755);
-    if (!control_tar.Add(PostInst, WorkDir.length(), ".")) {
+    if (!control_tar.Add(this->PostInst, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Error adding file to tar:"
                       << std::endl
-                      << "#top level directory: " << WorkDir << std::endl
+                      << "#top level directory: " << this->WorkDir << std::endl
                       << "#file: \"postinst\"" << std::endl
                       << "#error:" << control_tar.GetError() << std::endl);
       return false;
@@ -353,13 +376,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
     control_tar.SetPermissions(permission644);
   }
 
-  if (GenPostRm) {
+  if (this->GenPostRm) {
     control_tar.SetPermissions(permission755);
-    if (!control_tar.Add(PostRm, WorkDir.length(), ".")) {
+    if (!control_tar.Add(this->PostRm, this->WorkDir.length(), ".")) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "Error adding file to tar:"
                       << std::endl
-                      << "#top level directory: " << WorkDir << std::endl
+                      << "#top level directory: " << this->WorkDir << std::endl
                       << "#file: \"postinst\"" << std::endl
                       << "#error:" << control_tar.GetError() << std::endl);
       return false;
@@ -370,7 +393,7 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
   // for the other files, we use
   // -either the original permission on the files
   // -either a permission strictly defined by the Debian policies
-  if (ControlExtra) {
+  if (this->ControlExtra) {
     // permissions are now controlled by the original file permissions
 
     static const char* strictFiles[] = { "config", "postinst", "postrm",
@@ -381,19 +404,29 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const
     // default
     control_tar.ClearPermissions();
 
-    std::vector<std::string> controlExtraList = cmExpandedList(ControlExtra);
+    std::vector<std::string> controlExtraList =
+      cmExpandedList(this->ControlExtra);
     for (std::string const& i : controlExtraList) {
       std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
-      std::string localcopy = WorkDir + "/" + filenamename;
+      std::string localcopy = this->WorkDir + "/" + filenamename;
 
-      if (PermissionStrictPolicy) {
+      if (this->PermissionStrictPolicy) {
         control_tar.SetPermissions(
           setStrictFiles.count(filenamename) ? permission755 : permission644);
       }
 
       // if we can copy the file, it means it does exist, let's add it:
+      if (!cmsys::SystemTools::FileExists(i)) {
+        cmCPackLogger(cmCPackLog::LOG_WARNING,
+                      "Adding file to tar:" << std::endl
+                                            << "#top level directory: "
+                                            << this->WorkDir << std::endl
+                                            << "#missing file: " << i
+                                            << std::endl);
+      }
+
       if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
-        control_tar.Add(localcopy, WorkDir.length(), ".");
+        control_tar.Add(localcopy, this->WorkDir.length(), ".");
       }
     }
   }
@@ -408,8 +441,8 @@ bool DebGenerator::generateDeb() const
   // difference is that debian uses the BSD ar style archive whereas most
   // Linux distro have a GNU ar.
   // See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
-  std::string const outputPath = TopLevelDir + "/" + OutputName;
-  std::string const tlDir = WorkDir + "/";
+  std::string const outputPath = this->TopLevelDir + "/" + this->OutputName;
+  std::string const tlDir = this->WorkDir + "/";
   cmGeneratedFileStream debStream;
   debStream.Open(outputPath, false, true);
   cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
@@ -422,12 +455,13 @@ bool DebGenerator::generateDeb() const
 
   if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
       !deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
-      !deb.Add(tlDir + "data.tar" + CompressionSuffix, tlDir.length())) {
+      !deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error creating debian package:"
                     << std::endl
-                    << "#top level directory: " << TopLevelDir << std::endl
-                    << "#file: " << OutputName << std::endl
+                    << "#top level directory: " << this->TopLevelDir
+                    << std::endl
+                    << "#file: " << this->OutputName << std::endl
                     << "#error:" << deb.GetError() << std::endl);
     return false;
   }
@@ -455,7 +489,8 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
   int retval = 1;
   // Begin the archive for this pack
   std::string localToplevel(initialTopLevel);
-  std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+  std::string packageFileName(
+    cmSystemTools::GetParentDirectory(this->toplevel));
   std::string outputFileName(
     std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + "-" +
     packageName + this->GetOutputExtension());
@@ -495,19 +530,20 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
                       << std::endl);
       return 0;
     }
-    packageFiles = gl.GetFiles();
+    this->packageFiles = gl.GetFiles();
   }
 
-  int res = createDeb();
+  int res = this->createDeb();
   if (res != 1) {
     retval = 0;
   }
   // add the generated package to package file names list
   packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
                              this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
-  packageFileNames.push_back(std::move(packageFileName));
+  this->packageFileNames.push_back(std::move(packageFileName));
 
-  if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE")) {
+  if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") &&
+      this->GetOption("GEN_DBGSYMDIR")) {
     cmsys::Glob gl;
     std::string findExpr(this->GetOption("GEN_DBGSYMDIR"));
     findExpr += "/*";
@@ -520,9 +556,9 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
                       << std::endl);
       return 0;
     }
-    packageFiles = gl.GetFiles();
+    this->packageFiles = gl.GetFiles();
 
-    res = createDbgsymDDeb();
+    res = this->createDbgsymDDeb();
     if (res != 1) {
       retval = 0;
     }
@@ -530,7 +566,7 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
     packageFileName =
       cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
                this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"));
-    packageFileNames.push_back(std::move(packageFileName));
+    this->packageFileNames.push_back(std::move(packageFileName));
   }
 
   return retval;
@@ -541,7 +577,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
   int retval = 1;
   /* Reset package file name list it will be populated during the
    * component packaging run*/
-  packageFileNames.clear();
+  this->packageFileNames.clear();
   std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
 
   // The default behavior is to have one package by component group
@@ -551,7 +587,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
       cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                     "Packaging component group: " << compG.first << std::endl);
       // Begin the archive for this group
-      retval &= PackageOnePack(initialTopLevel, compG.first);
+      retval &= this->PackageOnePack(initialTopLevel, compG.first);
     }
     // Handle Orphan components (components not belonging to any groups)
     for (auto const& comp : this->Components) {
@@ -564,7 +600,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
             << "> does not belong to any group, package it separately."
             << std::endl);
         // Begin the archive for this orphan component
-        retval &= PackageOnePack(initialTopLevel, comp.first);
+        retval &= this->PackageOnePack(initialTopLevel, comp.first);
       }
     }
   }
@@ -572,7 +608,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
   // We build 1 package per component
   else {
     for (auto const& comp : this->Components) {
-      retval &= PackageOnePack(initialTopLevel, comp.first);
+      retval &= this->PackageOnePack(initialTopLevel, comp.first);
     }
   }
   return retval;
@@ -585,7 +621,7 @@ int cmCPackDebGenerator::PackageComponentsAllInOne(
   int retval = 1;
   /* Reset package file name list it will be populated during the
    * component packaging run*/
-  packageFileNames.clear();
+  this->packageFileNames.clear();
   std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
 
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
@@ -595,7 +631,8 @@ int cmCPackDebGenerator::PackageComponentsAllInOne(
 
   // The ALL GROUPS in ONE package case
   std::string localToplevel(initialTopLevel);
-  std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+  std::string packageFileName(
+    cmSystemTools::GetParentDirectory(this->toplevel));
   std::string outputFileName(
     std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
     this->GetOutputExtension());
@@ -640,38 +677,38 @@ int cmCPackDebGenerator::PackageComponentsAllInOne(
                     << std::endl);
     return 0;
   }
-  packageFiles = gl.GetFiles();
+  this->packageFiles = gl.GetFiles();
 
-  int res = createDeb();
+  int res = this->createDeb();
   if (res != 1) {
     retval = 0;
   }
   // add the generated package to package file names list
   packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/',
                              this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"));
-  packageFileNames.push_back(std::move(packageFileName));
+  this->packageFileNames.push_back(std::move(packageFileName));
   return retval;
 }
 
 int cmCPackDebGenerator::PackageFiles()
 {
   /* Are we in the component packaging case */
-  if (WantsComponentInstallation()) {
+  if (this->WantsComponentInstallation()) {
     // CASE 1 : COMPONENT ALL-IN-ONE package
     // If ALL GROUPS or ALL COMPONENTS in ONE package has been requested
     // then the package file is unique and should be open here.
-    if (componentPackageMethod == ONE_PACKAGE) {
-      return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+    if (this->componentPackageMethod == ONE_PACKAGE) {
+      return this->PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
     }
     // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
     // There will be 1 package for each component group
     // however one may require to ignore component group and
     // in this case you'll get 1 package for each component.
-    return PackageComponents(componentPackageMethod ==
-                             ONE_PACKAGE_PER_COMPONENT);
+    return this->PackageComponents(this->componentPackageMethod ==
+                                   ONE_PACKAGE_PER_COMPONENT);
   }
   // CASE 3 : NON COMPONENT package.
-  return PackageComponentsAllInOne("");
+  return this->PackageComponentsAllInOne("");
 }
 
 int cmCPackDebGenerator::createDeb()
@@ -786,16 +823,17 @@ int cmCPackDebGenerator::createDeb()
   }
 
   DebGenerator gen(
-    Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR,
+    this->Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR,
     this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
     this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
     this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+    this->GetOption("CPACK_THREADS"),
     this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, gen_shibs,
     shlibsfilename, this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST"), postinst,
     this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM"), postrm,
     this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"),
     this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
-    packageFiles);
+    this->packageFiles);
 
   if (!gen.generate()) {
     return 0;
@@ -841,16 +879,17 @@ int cmCPackDebGenerator::createDbgsymDDeb()
   }
 
   DebGenerator gen(
-    Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
+    this->Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
     this->GetOption("GEN_DBGSYMDIR"),
 
     this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
     this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
     this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+    this->GetOption("CPACK_THREADS"),
     this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, false, "",
     false, "", false, "", nullptr,
     this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
-    packageFiles);
+    this->packageFiles);
 
   if (!gen.generate()) {
     return 0;
@@ -860,25 +899,25 @@ int cmCPackDebGenerator::createDbgsymDDeb()
 
 bool cmCPackDebGenerator::SupportsComponentInstallation() const
 {
-  return IsOn("CPACK_DEB_COMPONENT_INSTALL");
+  return this->IsOn("CPACK_DEB_COMPONENT_INSTALL");
 }
 
 std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
   const std::string& componentName)
 {
-  if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+  if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
     return componentName;
   }
 
-  if (componentPackageMethod == ONE_PACKAGE) {
+  if (this->componentPackageMethod == ONE_PACKAGE) {
     return std::string("ALL_COMPONENTS_IN_ONE");
   }
   // We have to find the name of the COMPONENT GROUP
   // the current COMPONENT belongs to.
   std::string groupVar =
     "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
-  if (nullptr != GetOption(groupVar)) {
-    return std::string(GetOption(groupVar));
+  if (nullptr != this->GetOption(groupVar)) {
+    return std::string(this->GetOption(groupVar));
   }
   return componentName;
 }
index 0bc8456..e3521a0 100644 (file)
@@ -95,7 +95,7 @@ int cmCPackExternalGenerator::InstallProjectViaInstallCommands(
   bool setDestDir, const std::string& tempInstallDirectory)
 {
   if (this->StagingEnabled()) {
-    return cmCPackGenerator::InstallProjectViaInstallCommands(
+    return this->cmCPackGenerator::InstallProjectViaInstallCommands(
       setDestDir, tempInstallDirectory);
   }
 
@@ -106,7 +106,7 @@ int cmCPackExternalGenerator::InstallProjectViaInstallScript(
   bool setDestDir, const std::string& tempInstallDirectory)
 {
   if (this->StagingEnabled()) {
-    return cmCPackGenerator::InstallProjectViaInstallScript(
+    return this->cmCPackGenerator::InstallProjectViaInstallScript(
       setDestDir, tempInstallDirectory);
   }
 
@@ -118,7 +118,7 @@ int cmCPackExternalGenerator::InstallProjectViaInstalledDirectories(
   const mode_t* default_dir_mode)
 {
   if (this->StagingEnabled()) {
-    return cmCPackGenerator::InstallProjectViaInstalledDirectories(
+    return this->cmCPackGenerator::InstallProjectViaInstalledDirectories(
       setDestDir, tempInstallDirectory, default_dir_mode);
   }
 
@@ -130,7 +130,7 @@ int cmCPackExternalGenerator::RunPreinstallTarget(
   cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
 {
   if (this->StagingEnabled()) {
-    return cmCPackGenerator::RunPreinstallTarget(
+    return this->cmCPackGenerator::RunPreinstallTarget(
       installProjectName, installDirectory, globalGenerator, buildConfig);
   }
 
@@ -145,7 +145,7 @@ int cmCPackExternalGenerator::InstallCMakeProject(
   std::string& absoluteDestFiles)
 {
   if (this->StagingEnabled()) {
-    return cmCPackGenerator::InstallCMakeProject(
+    return this->cmCPackGenerator::InstallCMakeProject(
       setDestDir, installDirectory, baseTempInstallDirectory, default_dir_mode,
       component, componentInstall, installSubDirectory, buildConfig,
       absoluteDestFiles);
index a9fe91c..3db4162 100644 (file)
@@ -60,18 +60,18 @@ int cmCPackGenerator::PrepareNames()
   cmCPackLogger(cmCPackLog::LOG_DEBUG, "Create temp directory." << std::endl);
 
   // checks CPACK_SET_DESTDIR support
-  if (IsOn("CPACK_SET_DESTDIR")) {
-    if (SETDESTDIR_UNSUPPORTED == SupportsSetDestdir()) {
+  if (this->IsOn("CPACK_SET_DESTDIR")) {
+    if (SETDESTDIR_UNSUPPORTED == this->SupportsSetDestdir()) {
       cmCPackLogger(cmCPackLog::LOG_ERROR,
                     "CPACK_SET_DESTDIR is set to ON but the '"
-                      << Name << "' generator does NOT support it."
+                      << this->Name << "' generator does NOT support it."
                       << std::endl);
       return 0;
     }
-    if (SETDESTDIR_SHOULD_NOT_BE_USED == SupportsSetDestdir()) {
+    if (SETDESTDIR_SHOULD_NOT_BE_USED == this->SupportsSetDestdir()) {
       cmCPackLogger(cmCPackLog::LOG_WARNING,
                     "CPACK_SET_DESTDIR is set to ON but it is "
-                      << "usually a bad idea to do that with '" << Name
+                      << "usually a bad idea to do that with '" << this->Name
                       << "' generator. Use at your own risk." << std::endl);
     }
   }
@@ -380,8 +380,8 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories(
                         << std::endl);
         return 0;
       }
-      files = gl.GetFiles();
-      for (std::string const& gf : files) {
+      this->files = gl.GetFiles();
+      for (std::string const& gf : this->files) {
         bool skip = false;
         std::string inFile = gf;
         if (cmSystemTools::FileIsDirectory(gf)) {
@@ -763,7 +763,7 @@ int cmCPackGenerator::InstallCMakeProject(
     //  one install directory for each component **GROUP**
     // instead of the default
     //  one install directory for each component.
-    tempInstallDirectory += GetComponentInstallDirNameSuffix(component);
+    tempInstallDirectory += this->GetComponentInstallDirNameSuffix(component);
     if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
       tempInstallDirectory += "/";
       tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
@@ -897,7 +897,7 @@ int cmCPackGenerator::InstallCMakeProject(
   // ABSOLUTE INSTALL DESTINATION or CPack has been asked for
   // then ask cmake_install.cmake script to error out
   // as soon as it occurs (before installing file)
-  if (!SupportsAbsoluteDestination() ||
+  if (!this->SupportsAbsoluteDestination() ||
       this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
     mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
   }
@@ -933,7 +933,7 @@ int cmCPackGenerator::InstallCMakeProject(
       localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit);
       localFileName =
         localFileName.substr(localFileName.find_first_not_of('/'));
-      Components[component].Files.push_back(localFileName);
+      this->Components[component].Files.push_back(localFileName);
       cmCPackLogger(cmCPackLog::LOG_DEBUG,
                     "Adding file <" << localFileName << "> to component <"
                                     << component << ">" << std::endl);
@@ -952,7 +952,7 @@ int cmCPackGenerator::InstallCMakeProject(
     if (componentInstall) {
       std::string absoluteDestFileComponent =
         std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
-        GetComponentInstallDirNameSuffix(component);
+        this->GetComponentInstallDirNameSuffix(component);
       if (nullptr != this->GetOption(absoluteDestFileComponent)) {
         std::string absoluteDestFilesListComponent =
           cmStrCat(this->GetOption(absoluteDestFileComponent), ';', *d);
@@ -1073,17 +1073,17 @@ int cmCPackGenerator::DoPackage()
   }
 
   // The files to be installed
-  files = gl.GetFiles();
+  this->files = gl.GetFiles();
 
-  packageFileNames.clear();
+  this->packageFileNames.clear();
   /* Put at least one file name into the list of
    * wanted packageFileNames. The specific generator
    * may update this during PackageFiles.
    * (either putting several names or updating the provided one)
    */
-  packageFileNames.emplace_back(tempPackageFileName ? tempPackageFileName
-                                                    : "");
-  toplevel = tempDirectory;
+  this->packageFileNames.emplace_back(tempPackageFileName ? tempPackageFileName
+                                                          : "");
+  this->toplevel = tempDirectory;
   { // scope that enables package generators to run internal scripts with
     // latest CMake policies enabled
     cmMakefile::ScopePushPop pp{ this->MakefileMap };
@@ -1127,10 +1127,10 @@ int cmCPackGenerator::DoPackage()
    *    (because the specific generator did 'normalize' it)
    */
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
-                "Copying final package(s) [" << packageFileNames.size()
+                "Copying final package(s) [" << this->packageFileNames.size()
                                              << "]:" << std::endl);
   /* now copy package one by one */
-  for (std::string const& pkgFileName : packageFileNames) {
+  for (std::string const& pkgFileName : this->packageFileNames) {
     std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"));
     std::string filename(cmSystemTools::GetFilenameName(pkgFileName));
     tempPackageFileName = pkgFileName.c_str();
@@ -1211,7 +1211,7 @@ bool cmCPackGenerator::IsSet(const std::string& name) const
 
 bool cmCPackGenerator::IsOn(const std::string& name) const
 {
-  return cmIsOn(GetOption(name));
+  return cmIsOn(this->GetOption(name));
 }
 
 bool cmCPackGenerator::IsSetToOff(const std::string& op) const
@@ -1329,7 +1329,7 @@ bool cmCPackGenerator::ConfigureFile(const std::string& inName,
                                      bool copyOnly /* = false */)
 {
   return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
-                                          false, true) == 1;
+                                          false) == 1;
 }
 
 int cmCPackGenerator::CleanTemporaryDirectory()
@@ -1405,7 +1405,7 @@ int cmCPackGenerator::PrepareGroupingKind()
   // fallback to default if not group based
   if (method == ONE_PACKAGE_PER_GROUP && this->ComponentGroups.empty() &&
       !this->Components.empty()) {
-    if (componentPackageMethod == ONE_PACKAGE) {
+    if (this->componentPackageMethod == ONE_PACKAGE) {
       method = ONE_PACKAGE;
     } else {
       method = ONE_PACKAGE_PER_COMPONENT;
@@ -1421,7 +1421,7 @@ int cmCPackGenerator::PrepareGroupingKind()
   // if user specified packaging method, override the default packaging
   // method
   if (method != UNKNOWN_COMPONENT_PACKAGE_METHOD) {
-    componentPackageMethod = method;
+    this->componentPackageMethod = method;
   }
 
   const char* method_names[] = { "ALL_COMPONENTS_IN_ONE", "IGNORE_GROUPS",
@@ -1430,7 +1430,8 @@ int cmCPackGenerator::PrepareGroupingKind()
   cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                 "[" << this->Name << "]"
                     << " requested component grouping = "
-                    << method_names[componentPackageMethod] << std::endl);
+                    << method_names[this->componentPackageMethod]
+                    << std::endl);
 
   return 1;
 }
@@ -1451,13 +1452,14 @@ std::string cmCPackGenerator::GetComponentPackageFileName(
    */
   std::string suffix = "-" + groupOrComponentName;
   /* check if we should use DISPLAY name */
-  std::string dispNameVar = "CPACK_" + Name + "_USE_DISPLAY_NAME_IN_FILENAME";
-  if (IsOn(dispNameVar)) {
+  std::string dispNameVar =
+    "CPACK_" + this->Name + "_USE_DISPLAY_NAME_IN_FILENAME";
+  if (this->IsOn(dispNameVar)) {
     /* the component Group case */
     if (isGroupName) {
       std::string groupDispVar = "CPACK_COMPONENT_GROUP_" +
         cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
-      const char* groupDispName = GetOption(groupDispVar);
+      const char* groupDispName = this->GetOption(groupDispVar);
       if (groupDispName) {
         suffix = "-" + std::string(groupDispName);
       }
@@ -1466,7 +1468,7 @@ std::string cmCPackGenerator::GetComponentPackageFileName(
     else {
       std::string dispVar = "CPACK_COMPONENT_" +
         cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME";
-      const char* dispName = GetOption(dispVar);
+      const char* dispName = this->GetOption(dispVar);
       if (dispName) {
         suffix = "-" + std::string(dispName);
       }
@@ -1493,8 +1495,8 @@ bool cmCPackGenerator::SupportsComponentInstallation() const
 
 bool cmCPackGenerator::WantsComponentInstallation() const
 {
-  return (!IsOn("CPACK_MONOLITHIC_INSTALL") &&
-          SupportsComponentInstallation()
+  return (!this->IsOn("CPACK_MONOLITHIC_INSTALL") &&
+          this->SupportsComponentInstallation()
           // check that we have at least one group or component
           && (!this->ComponentGroups.empty() || !this->Components.empty()));
 }
@@ -1557,7 +1559,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent(
 
     const char* groupName = this->GetOption(macroPrefix + "_GROUP");
     if (cmNonempty(groupName)) {
-      component->Group = GetComponentGroup(projectName, groupName);
+      component->Group = this->GetComponentGroup(projectName, groupName);
       component->Group->Components.push_back(component);
     } else {
       component->Group = nullptr;
@@ -1584,7 +1586,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent(
     if (cmNonempty(depends)) {
       std::vector<std::string> dependsVector = cmExpandedList(depends);
       for (std::string const& depend : dependsVector) {
-        cmCPackComponent* child = GetComponent(projectName, depend);
+        cmCPackComponent* child = this->GetComponent(projectName, depend);
         component->Dependencies.push_back(child);
         child->ReverseDependencies.push_back(component);
       }
@@ -1620,7 +1622,8 @@ cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup(
     const char* parentGroupName =
       this->GetOption(macroPrefix + "_PARENT_GROUP");
     if (cmNonempty(parentGroupName)) {
-      group->ParentGroup = GetComponentGroup(projectName, parentGroupName);
+      group->ParentGroup =
+        this->GetComponentGroup(projectName, parentGroupName);
       group->ParentGroup->Subgroups.push_back(group);
     } else {
       group->ParentGroup = nullptr;
index 2109b4e..263adfd 100644 (file)
@@ -31,7 +31,7 @@
 
 cmCPackNSISGenerator::cmCPackNSISGenerator(bool nsis64)
 {
-  Nsis64 = nsis64;
+  this->Nsis64 = nsis64;
 }
 
 cmCPackNSISGenerator::~cmCPackNSISGenerator() = default;
@@ -61,18 +61,18 @@ int cmCPackNSISGenerator::PackageFiles()
   std::string nsisInstallOptions = nsisFileName + "/NSIS.InstallOptions.ini";
   nsisFileName += "/project.nsi";
   std::ostringstream str;
-  for (std::string const& file : files) {
+  for (std::string const& file : this->files) {
     std::string outputDir = "$INSTDIR";
-    std::string fileN = cmSystemTools::RelativePath(toplevel, file);
+    std::string fileN = cmSystemTools::RelativePath(this->toplevel, file);
     if (!this->Components.empty()) {
       const std::string::size_type pos = fileN.find('/');
 
       // Use the custom component install directory if we have one
       if (pos != std::string::npos) {
         auto componentName = cm::string_view(fileN).substr(0, pos);
-        outputDir = CustomComponentInstallDirectory(componentName);
+        outputDir = this->CustomComponentInstallDirectory(componentName);
       } else {
-        outputDir = CustomComponentInstallDirectory(fileN);
+        outputDir = this->CustomComponentInstallDirectory(fileN);
       }
 
       // Strip off the component part of the path.
@@ -86,15 +86,15 @@ int cmCPackNSISGenerator::PackageFiles()
                 "Uninstall Files: " << str.str() << std::endl);
   this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
   std::vector<std::string> dirs;
-  this->GetListOfSubdirectories(toplevel.c_str(), dirs);
+  this->GetListOfSubdirectories(this->toplevel.c_str(), dirs);
   std::ostringstream dstr;
   for (std::string const& dir : dirs) {
     std::string componentName;
-    std::string fileN = cmSystemTools::RelativePath(toplevel, dir);
+    std::string fileN = cmSystemTools::RelativePath(this->toplevel, dir);
     if (fileN.empty()) {
       continue;
     }
-    if (!Components.empty()) {
+    if (!this->Components.empty()) {
       // If this is a component installation, strip off the component
       // part of the path.
       std::string::size_type slash = fileN.find('/');
@@ -110,7 +110,7 @@ int cmCPackNSISGenerator::PackageFiles()
     std::replace(fileN.begin(), fileN.end(), '/', '\\');
 
     const std::string componentOutputDir =
-      CustomComponentInstallDirectory(componentName);
+      this->CustomComponentInstallDirectory(componentName);
 
     dstr << "  RMDir \"" << componentOutputDir << "\\" << fileN << "\""
          << std::endl;
@@ -209,6 +209,25 @@ int cmCPackNSISGenerator::PackageFiles()
                             "ManifestDPIAware true");
   }
 
+  if (this->IsSet("CPACK_NSIS_BRANDING_TEXT")) {
+    // Default position to LEFT
+    std::string brandingTextPosition = "LEFT";
+    if (this->IsSet("CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION")) {
+      std::string wantedPosition =
+        this->GetOption("CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION");
+      const std::set<std::string> possiblePositions{ "CENTER", "LEFT",
+                                                     "RIGHT" };
+      if (possiblePositions.find(wantedPosition) != possiblePositions.end()) {
+        brandingTextPosition = wantedPosition;
+      }
+    }
+    std::string brandingTextCode =
+      cmStrCat("BrandingText /TRIM", brandingTextPosition, " \"",
+               this->GetOption("CPACK_NSIS_BRANDING_TEXT"), "\"\n");
+    this->SetOptionIfNotSet("CPACK_NSIS_BRANDING_TEXT_CODE",
+                            brandingTextCode.c_str());
+  }
+
   // Setup all of the component sections
   if (this->Components.empty()) {
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", "");
@@ -677,7 +696,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
   }
 
   const std::string componentOutputDir =
-    CustomComponentInstallDirectory(component->Name);
+    this->CustomComponentInstallDirectory(component->Name);
   componentCode += cmStrCat("  SetOutPath \"", componentOutputDir, "\"\n");
 
   // Create the actual installation commands
@@ -833,14 +852,16 @@ std::string cmCPackNSISGenerator::CreateComponentDescription(
   // depends on.
   std::set<cmCPackComponent*> visited;
   macrosOut << "!macro Select_" << component->Name << "_depends\n";
-  macrosOut << CreateSelectionDependenciesDescription(component, visited);
+  macrosOut << this->CreateSelectionDependenciesDescription(component,
+                                                            visited);
   macrosOut << "!macroend\n";
 
   // Macro used to deselect each of the components that depend on this
   // component.
   visited.clear();
   macrosOut << "!macro Deselect_required_by_" << component->Name << "\n";
-  macrosOut << CreateDeselectionDependenciesDescription(component, visited);
+  macrosOut << this->CreateDeselectionDependenciesDescription(component,
+                                                              visited);
   macrosOut << "!macroend\n";
   return componentCode;
 }
@@ -862,7 +883,8 @@ std::string cmCPackNSISGenerator::CreateSelectionDependenciesDescription(
     out << "  SectionSetFlags ${" << depend->Name << "} $0\n";
     out << "  IntOp $" << depend->Name << "_selected 0 + ${SF_SELECTED}\n";
     // Recurse
-    out << CreateSelectionDependenciesDescription(depend, visited).c_str();
+    out
+      << this->CreateSelectionDependenciesDescription(depend, visited).c_str();
   }
 
   return out.str();
@@ -887,7 +909,8 @@ std::string cmCPackNSISGenerator::CreateDeselectionDependenciesDescription(
     out << "  IntOp $" << depend->Name << "_selected 0 + 0\n";
 
     // Recurse
-    out << CreateDeselectionDependenciesDescription(depend, visited).c_str();
+    out << this->CreateDeselectionDependenciesDescription(depend, visited)
+             .c_str();
   }
 
   return out.str();
index 60faecd..98dc890 100644 (file)
 
 bool cmCPackNuGetGenerator::SupportsComponentInstallation() const
 {
-  return IsOn("CPACK_NUGET_COMPONENT_INSTALL");
+  return this->IsOn("CPACK_NUGET_COMPONENT_INSTALL");
 }
 
 int cmCPackNuGetGenerator::PackageFiles()
 {
-  cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+  cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                "Toplevel: " << this->toplevel << std::endl);
 
   /* Reset package file name list it will be populated after the
    * `CPackNuGet.cmake` run */
-  packageFileNames.clear();
+  this->packageFileNames.clear();
 
   /* Are we in the component packaging case */
-  if (WantsComponentInstallation()) {
-    if (componentPackageMethod == ONE_PACKAGE) {
+  if (this->WantsComponentInstallation()) {
+    if (this->componentPackageMethod == ONE_PACKAGE) {
       // CASE 1 : COMPONENT ALL-IN-ONE package
       // Meaning that all per-component pre-installed files
       // goes into the single package.
       this->SetOption("CPACK_NUGET_ALL_IN_ONE", "TRUE");
-      SetupGroupComponentVariables(true);
+      this->SetupGroupComponentVariables(true);
     } else {
       // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
       // There will be 1 package for each component group
       // however one may require to ignore component group and
       // in this case you'll get 1 package for each component.
-      SetupGroupComponentVariables(componentPackageMethod ==
-                                   ONE_PACKAGE_PER_COMPONENT);
+      this->SetupGroupComponentVariables(this->componentPackageMethod ==
+                                         ONE_PACKAGE_PER_COMPONENT);
     }
   } else {
     // CASE 3 : NON COMPONENT package.
@@ -51,7 +52,7 @@ int cmCPackNuGetGenerator::PackageFiles()
 
   auto retval = this->ReadListFile("Internal/CPack/CPackNuGet.cmake");
   if (retval) {
-    AddGeneratedPackageNames();
+    this->AddGeneratedPackageNames();
   } else {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error while execution CPackNuGet.cmake" << std::endl);
@@ -133,9 +134,9 @@ void cmCPackNuGetGenerator::AddGeneratedPackageNames()
   std::string::size_type pos1 = 0;
   std::string::size_type pos2 = fileNames.find(sep, pos1 + 1);
   while (pos2 != std::string::npos) {
-    packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+    this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
     pos1 = pos2 + 1;
     pos2 = fileNames.find(sep, pos1 + 1);
   }
-  packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+  this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
 }
index 0c1cecf..c3f6d59 100644 (file)
@@ -51,11 +51,11 @@ void cmCPackRPMGenerator::AddGeneratedPackageNames()
   std::string::size_type pos1 = 0;
   std::string::size_type pos2 = fileNames.find(sep, pos1 + 1);
   while (pos2 != std::string::npos) {
-    packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+    this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
     pos1 = pos2 + 1;
     pos2 = fileNames.find(sep, pos1 + 1);
   }
-  packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
+  this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1));
 }
 
 int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
@@ -64,10 +64,11 @@ int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel,
   int retval = 1;
   // Begin the archive for this pack
   std::string localToplevel(initialToplevel);
-  std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+  std::string packageFileName(
+    cmSystemTools::GetParentDirectory(this->toplevel));
   std::string outputFileName(
-    GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
-                                packageName, true) +
+    this->GetComponentPackageFileName(
+      this->GetOption("CPACK_PACKAGE_FILE_NAME"), packageName, true) +
     this->GetOutputExtension());
 
   localToplevel += "/" + packageName;
@@ -99,7 +100,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
   int retval = 1;
   /* Reset package file name list it will be populated during the
    * component packaging run*/
-  packageFileNames.clear();
+  this->packageFileNames.clear();
   std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
 
   const char* mainComponent = this->GetOption("CPACK_RPM_MAIN_COMPONENT");
@@ -202,7 +203,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
         cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                       "Packaging component group: " << compGIt->first
                                                     << std::endl);
-        retval &= PackageOnePack(initialTopLevel, compGIt->first);
+        retval &= this->PackageOnePack(initialTopLevel, compGIt->first);
       }
       // Handle Orphan components (components not belonging to any groups)
       auto mainCompIt = this->Components.end();
@@ -227,7 +228,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
               << compIt->second.Name
               << "> does not belong to any group, package it separately."
               << std::endl);
-          retval &= PackageOnePack(initialTopLevel, compIt->first);
+          retval &= this->PackageOnePack(initialTopLevel, compIt->first);
         }
       }
 
@@ -235,9 +236,9 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
         this->SetOption("GENERATE_SPEC_PARTS", "OFF");
 
         if (mainCompGIt != this->ComponentGroups.end()) {
-          retval &= PackageOnePack(initialTopLevel, mainCompGIt->first);
+          retval &= this->PackageOnePack(initialTopLevel, mainCompGIt->first);
         } else if (mainCompIt != this->Components.end()) {
-          retval &= PackageOnePack(initialTopLevel, mainCompIt->first);
+          retval &= this->PackageOnePack(initialTopLevel, mainCompIt->first);
         } else {
           cmCPackLogger(cmCPackLog::LOG_ERROR,
                         "CPACK_RPM_MAIN_COMPONENT set"
@@ -264,14 +265,14 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
           continue;
         }
 
-        retval &= PackageOnePack(initialTopLevel, compIt->first);
+        retval &= this->PackageOnePack(initialTopLevel, compIt->first);
       }
 
       if (retval) {
         this->SetOption("GENERATE_SPEC_PARTS", "OFF");
 
         if (mainCompIt != this->Components.end()) {
-          retval &= PackageOnePack(initialTopLevel, mainCompIt->first);
+          retval &= this->PackageOnePack(initialTopLevel, mainCompIt->first);
         } else {
           cmCPackLogger(cmCPackLog::LOG_ERROR,
                         "CPACK_RPM_MAIN_COMPONENT set"
@@ -291,7 +292,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
         cmCPackLogger(cmCPackLog::LOG_VERBOSE,
                       "Packaging component group: " << compGIt->first
                                                     << std::endl);
-        retval &= PackageOnePack(initialTopLevel, compGIt->first);
+        retval &= this->PackageOnePack(initialTopLevel, compGIt->first);
       }
       // Handle Orphan components (components not belonging to any groups)
       std::map<std::string, cmCPackComponent>::iterator compIt;
@@ -305,7 +306,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
               << compIt->second.Name
               << "> does not belong to any group, package it separately."
               << std::endl);
-          retval &= PackageOnePack(initialTopLevel, compIt->first);
+          retval &= this->PackageOnePack(initialTopLevel, compIt->first);
         }
       }
     }
@@ -315,7 +316,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
       std::map<std::string, cmCPackComponent>::iterator compIt;
       for (compIt = this->Components.begin(); compIt != this->Components.end();
            ++compIt) {
-        retval &= PackageOnePack(initialTopLevel, compIt->first);
+        retval &= this->PackageOnePack(initialTopLevel, compIt->first);
       }
     }
   } else {
@@ -328,7 +329,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
   }
 
   if (retval) {
-    AddGeneratedPackageNames();
+    this->AddGeneratedPackageNames();
   }
 
   return retval;
@@ -340,7 +341,7 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne(
   int retval = 1;
   /* Reset package file name list it will be populated during the
    * component packaging run*/
-  packageFileNames.clear();
+  this->packageFileNames.clear();
   std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
 
   if (this->IsOn("CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE")) {
@@ -354,7 +355,8 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne(
 
   // The ALL GROUPS in ONE package case
   std::string localToplevel(initialTopLevel);
-  std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+  std::string packageFileName(
+    cmSystemTools::GetParentDirectory(this->toplevel));
   std::string outputFileName(
     std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
     this->GetOutputExtension());
@@ -378,7 +380,7 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne(
   }
 
   if (this->ReadListFile("Internal/CPack/CPackRPM.cmake")) {
-    AddGeneratedPackageNames();
+    this->AddGeneratedPackageNames();
   } else {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error while execution CPackRPM.cmake" << std::endl);
@@ -390,48 +392,49 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne(
 
 int cmCPackRPMGenerator::PackageFiles()
 {
-  cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+  cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                "Toplevel: " << this->toplevel << std::endl);
 
   /* Are we in the component packaging case */
-  if (WantsComponentInstallation()) {
+  if (this->WantsComponentInstallation()) {
     // CASE 1 : COMPONENT ALL-IN-ONE package
     // If ALL COMPONENTS in ONE package has been requested
     // then the package file is unique and should be open here.
-    if (componentPackageMethod == ONE_PACKAGE) {
-      return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+    if (this->componentPackageMethod == ONE_PACKAGE) {
+      return this->PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
     }
     // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
     // There will be 1 package for each component group
     // however one may require to ignore component group and
     // in this case you'll get 1 package for each component.
-    return PackageComponents(componentPackageMethod ==
-                             ONE_PACKAGE_PER_COMPONENT);
+    return this->PackageComponents(this->componentPackageMethod ==
+                                   ONE_PACKAGE_PER_COMPONENT);
   }
   // CASE 3 : NON COMPONENT package.
-  return PackageComponentsAllInOne("");
+  return this->PackageComponentsAllInOne("");
 }
 
 bool cmCPackRPMGenerator::SupportsComponentInstallation() const
 {
-  return IsOn("CPACK_RPM_COMPONENT_INSTALL");
+  return this->IsOn("CPACK_RPM_COMPONENT_INSTALL");
 }
 
 std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix(
   const std::string& componentName)
 {
-  if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+  if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
     return componentName;
   }
 
-  if (componentPackageMethod == ONE_PACKAGE) {
+  if (this->componentPackageMethod == ONE_PACKAGE) {
     return std::string("ALL_COMPONENTS_IN_ONE");
   }
   // We have to find the name of the COMPONENT GROUP
   // the current COMPONENT belongs to.
   std::string groupVar =
     "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
-  if (nullptr != GetOption(groupVar)) {
-    return std::string(GetOption(groupVar));
+  if (nullptr != this->GetOption(groupVar)) {
+    return std::string(this->GetOption(groupVar));
   }
   return componentName;
 }
index a4a5e6f..3e36e8c 100644 (file)
@@ -50,7 +50,7 @@ int cmCPackSTGZGenerator::PackageFiles()
    * have generated several packages (component packaging)
    * so we must iterate over generated packages.
    */
-  for (std::string const& pfn : packageFileNames) {
+  for (std::string const& pfn : this->packageFileNames) {
     retval &= cmSystemTools::SetPermissions(pfn.c_str(),
 #if defined(_MSC_VER) || defined(__MINGW32__)
                                             S_IREAD | S_IWRITE | S_IEXEC
index c533cd7..a353435 100644 (file)
@@ -104,8 +104,8 @@ private:
   {
     if (this->RegexCheckOut.find(this->Line)) {
       this->BZR->URL = this->RegexCheckOut.match(1);
-      CheckOutFound = true;
-    } else if (!CheckOutFound && this->RegexParent.find(this->Line)) {
+      this->CheckOutFound = true;
+    } else if (!this->CheckOutFound && this->RegexParent.find(this->Line)) {
       this->BZR->URL = this->RegexParent.match(1);
     }
     return true;
@@ -191,7 +191,7 @@ public:
 
   int InitializeParser() override
   {
-    int res = cmXMLParser::InitializeParser();
+    int res = this->cmXMLParser::InitializeParser();
     if (res) {
       XML_SetUnknownEncodingHandler(static_cast<XML_Parser>(this->Parser),
                                     cmBZRXMLParserUnknownEncodingHandler,
index 1cc267e..88e2871 100644 (file)
@@ -54,22 +54,21 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
     //
     cmProp ctestBuildConfiguration =
       this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
-    const std::string* cmakeBuildConfiguration = !this->Configuration.empty()
-      ? &this->Configuration
-      : (cmNonempty(ctestBuildConfiguration) ? ctestBuildConfiguration
-                                             : &this->CTest->GetConfigType());
-
-    const std::string* cmakeBuildAdditionalFlags = !this->Flags.empty()
-      ? &this->Flags
-      : this->Makefile->GetDefinition("CTEST_BUILD_FLAGS");
-    const std::string* cmakeBuildTarget = !this->Target.empty()
-      ? &this->Target
-      : this->Makefile->GetDefinition("CTEST_BUILD_TARGET");
+    std::string cmakeBuildConfiguration = cmNonempty(this->Configuration)
+      ? this->Configuration
+      : cmNonempty(ctestBuildConfiguration) ? *ctestBuildConfiguration
+                                            : this->CTest->GetConfigType();
+
+    const std::string& cmakeBuildAdditionalFlags = cmNonempty(this->Flags)
+      ? this->Flags
+      : this->Makefile->GetSafeDefinition("CTEST_BUILD_FLAGS");
+    const std::string& cmakeBuildTarget = cmNonempty(this->Target)
+      ? this->Target
+      : this->Makefile->GetSafeDefinition("CTEST_BUILD_TARGET");
 
     if (cmNonempty(cmakeGeneratorName)) {
-      if (!cmakeBuildConfiguration) {
-        static const std::string sRelease = "Release";
-        cmakeBuildConfiguration = &sRelease;
+      if (cmakeBuildConfiguration.empty()) {
+        cmakeBuildConfiguration = "Release";
       }
       if (this->GlobalGenerator) {
         if (this->GlobalGenerator->GetName() != *cmakeGeneratorName) {
@@ -88,24 +87,18 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
           return nullptr;
         }
       }
-      if (cmakeBuildConfiguration->empty()) {
-        const std::string* config = nullptr;
+      if (cmakeBuildConfiguration.empty()) {
 #ifdef CMAKE_INTDIR
-        static const std::string sIntDir = CMAKE_INTDIR;
-        config = &sIntDir;
+        cmakeBuildConfiguration = CMAKE_INTDIR;
+#else
+        cmakeBuildConfiguration = "Debug";
 #endif
-        if (!config) {
-          static const std::string sDebug = "Debug";
-          config = &sDebug;
-        }
-        cmakeBuildConfiguration = config;
       }
 
       std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory");
       std::string buildCommand =
         this->GlobalGenerator->GenerateCMakeBuildCommand(
-          cmakeBuildTarget ? *cmakeBuildTarget : "", *cmakeBuildConfiguration,
-          cmakeBuildAdditionalFlags ? *cmakeBuildAdditionalFlags : "",
+          cmakeBuildTarget, cmakeBuildConfiguration, cmakeBuildAdditionalFlags,
           this->Makefile->IgnoreErrorsCMP0061());
       cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                          "SetMakeCommand:" << buildCommand << "\n",
@@ -144,7 +137,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
 bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
                                       cmExecutionStatus& status)
 {
-  bool ret = cmCTestHandlerCommand::InitialPass(args, status);
+  bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
   if (!this->NumberErrors.empty()) {
     this->Makefile->AddDefinition(
       this->NumberErrors, std::to_string(this->Handler->GetTotalErrors()));
index 093b2d1..3d7d031 100644 (file)
@@ -107,7 +107,7 @@ public:
     this->PipeState = cmsysProcess_WaitForExit(this->Process, timeout);
     return this->PipeState;
   }
-  int GetProcessState() { return this->PipeState; }
+  int GetProcessState() const { return this->PipeState; }
 
 private:
   int PipeState;
@@ -778,16 +778,16 @@ struct cmCTestCoverageHandlerLocale
   {
     std::string l;
     if (cmSystemTools::GetEnv("LC_ALL", l)) {
-      lc_all = l;
+      this->lc_all = l;
     }
-    if (lc_all != "C") {
+    if (this->lc_all != "C") {
       cmSystemTools::PutEnv("LC_ALL=C");
     }
   }
   ~cmCTestCoverageHandlerLocale()
   {
-    if (!lc_all.empty()) {
-      cmSystemTools::PutEnv("LC_ALL=" + lc_all);
+    if (!this->lc_all.empty()) {
+      cmSystemTools::PutEnv("LC_ALL=" + this->lc_all);
     } else {
       cmSystemTools::UnsetEnv("LC_ALL");
     }
index b9ed033..15c443a 100644 (file)
@@ -265,7 +265,7 @@ void cmCTestLaunch::LoadScrapeRules()
 }
 
 void cmCTestLaunch::LoadScrapeRules(
-  const char* purpose, std::vector<cmsys::RegularExpression>& regexps)
+  const char* purpose, std::vector<cmsys::RegularExpression>& regexps) const
 {
   std::string fname =
     cmStrCat(this->Reporter.LogDir, "Custom", purpose, ".txt");
index d18f66d..eabb608 100644 (file)
@@ -60,7 +60,7 @@ private:
   bool ScrapeRulesLoaded;
   void LoadScrapeRules();
   void LoadScrapeRules(const char* purpose,
-                       std::vector<cmsys::RegularExpression>& regexps);
+                       std::vector<cmsys::RegularExpression>& regexps) const;
   bool ScrapeLog(std::string const& fname);
 
   // Helper class to generate the xml fragment.
index 6ec7d0e..5334a93 100644 (file)
@@ -150,7 +150,7 @@ void cmCTestLaunchReporter::WriteXML()
   this->WriteXMLLabels(e2);
 }
 
-void cmCTestLaunchReporter::WriteXMLAction(cmXMLElement& e2)
+void cmCTestLaunchReporter::WriteXMLAction(cmXMLElement& e2) const
 {
   e2.Comment("Meta-information about the build action");
   cmXMLElement e3(e2, "Action");
@@ -284,7 +284,7 @@ void cmCTestLaunchReporter::DumpFileToXML(cmXMLElement& e3, const char* tag,
 
   cmXMLElement e4(e3, tag);
   while (cmSystemTools::GetLineFromStream(fin, line)) {
-    if (MatchesFilterPrefix(line)) {
+    if (this->MatchesFilterPrefix(line)) {
       continue;
     }
     if (this->Match(line, this->RegexWarningSuppress)) {
index 675a878..4be0d9b 100644 (file)
@@ -70,7 +70,7 @@ public:
 
   // Methods to generate the xml fragment.
   void WriteXML();
-  void WriteXMLAction(cmXMLElement&);
+  void WriteXMLAction(cmXMLElement&) const;
   void WriteXMLCommand(cmXMLElement&);
   void WriteXMLResult(cmXMLElement&);
   void WriteXMLLabels(cmXMLElement&);
index 8a30dc0..125d003 100644 (file)
@@ -300,7 +300,7 @@ void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile* mf)
                                     this->CustomTestsIgnore);
 }
 
-int cmCTestMemCheckHandler::GetDefectCount()
+int cmCTestMemCheckHandler::GetDefectCount() const
 {
   return this->DefectCount;
 }
@@ -1364,9 +1364,15 @@ void cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
     }
   }
   if (this->LogWithPID) {
-    cmSystemTools::RemoveFile(ofile);
-    cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
-                       "Remove: " << ofile << "\n", this->Quiet);
+    auto pos = ofile.find_last_of('.');
+    if (pos != std::string::npos) {
+      auto ofileWithoutPid = ofile.substr(0, pos);
+      cmSystemTools::RenameFile(ofile, ofileWithoutPid);
+      cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+                         "Renaming: " << ofile << " to: " << ofileWithoutPid
+                                      << "\n",
+                         this->Quiet);
+    }
   }
 }
 
index 7ab00db..b200c43 100644 (file)
@@ -29,7 +29,7 @@ public:
 
   void Initialize() override;
 
-  int GetDefectCount();
+  int GetDefectCount() const;
 
 protected:
   int PreProcessHandler() override;
index a08cb34..852f9d9 100644 (file)
@@ -56,8 +56,8 @@ public:
   // Sorts tests in descending order of cost
   bool operator()(int index1, int index2) const
   {
-    return Handler->Properties[index1]->Cost >
-      Handler->Properties[index2]->Cost;
+    return this->Handler->Properties[index1]->Cost >
+      this->Handler->Properties[index2]->Cost;
   }
 
 private:
@@ -169,7 +169,7 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test)
   this->TestRunningMap[test] = true; // mark the test as running
   // now remove the test itself
   this->EraseTest(test);
-  this->RunningCount += GetProcessorsUsed(test);
+  this->RunningCount += this->GetProcessorsUsed(test);
 
   auto testRun = cm::make_unique<cmCTestRunTest>(*this);
 
@@ -552,12 +552,12 @@ void cmCTestMultiProcessHandler::StartNextTests()
       continue;
     }
 
-    size_t processors = GetProcessorsUsed(test);
+    size_t processors = this->GetProcessorsUsed(test);
     bool testLoadOk = true;
     if (this->TestLoad > 0) {
       if (processors <= spareLoad) {
         cmCTestLog(this->CTest, DEBUG,
-                   "OK to run " << GetName(test) << ", it requires "
+                   "OK to run " << this->GetName(test) << ", it requires "
                                 << processors << " procs & system load is: "
                                 << systemLoad << std::endl);
         allTestsFailedTestLoadCheck = false;
@@ -568,7 +568,7 @@ void cmCTestMultiProcessHandler::StartNextTests()
 
     if (processors <= minProcessorsRequired) {
       minProcessorsRequired = processors;
-      testWithMinProcessors = GetName(test);
+      testWithMinProcessors = this->GetName(test);
     }
 
     if (testLoadOk && processors <= numToStart && this->StartTest(test)) {
@@ -621,7 +621,7 @@ void cmCTestMultiProcessHandler::StartNextTests()
 
 void cmCTestMultiProcessHandler::OnTestLoadRetryCB(uv_timer_t* timer)
 {
-  auto self = static_cast<cmCTestMultiProcessHandler*>(timer->data);
+  auto* self = static_cast<cmCTestMultiProcessHandler*>(timer->data);
   self->StartNextTests();
 }
 
@@ -631,7 +631,7 @@ void cmCTestMultiProcessHandler::FinishTestProcess(
   this->Completed++;
 
   int test = runner->GetIndex();
-  auto properties = runner->GetTestProperties();
+  auto* properties = runner->GetTestProperties();
 
   bool testResult = runner->EndTest(this->Completed, this->Total, started);
   if (runner->TimedOutForStopTime()) {
@@ -660,7 +660,7 @@ void cmCTestMultiProcessHandler::FinishTestProcess(
   this->WriteCheckpoint(test);
   this->DeallocateResources(test);
   this->UnlockResources(test);
-  this->RunningCount -= GetProcessorsUsed(test);
+  this->RunningCount -= this->GetProcessorsUsed(test);
 
   for (auto p : properties->Affinity) {
     this->ProcessorsAvailable.insert(p);
@@ -793,9 +793,9 @@ int cmCTestMultiProcessHandler::SearchByName(std::string const& name)
 void cmCTestMultiProcessHandler::CreateTestCostList()
 {
   if (this->ParallelLevel > 1) {
-    CreateParallelTestCostList();
+    this->CreateParallelTestCostList();
   } else {
-    CreateSerialTestCostList();
+    this->CreateSerialTestCostList();
   }
 }
 
@@ -862,7 +862,7 @@ void cmCTestMultiProcessHandler::GetAllTestDependencies(int test,
 {
   TestSet const& dependencySet = this->Tests[test];
   for (int i : dependencySet) {
-    GetAllTestDependencies(i, dependencies);
+    this->GetAllTestDependencies(i, dependencies);
     dependencies.push_back(i);
   }
 }
@@ -886,7 +886,7 @@ void cmCTestMultiProcessHandler::CreateSerialTestCostList()
     }
 
     TestList dependencies;
-    GetAllTestDependencies(test, dependencies);
+    this->GetAllTestDependencies(test, dependencies);
 
     for (int testDependency : dependencies) {
       if (!cm::contains(alreadySortedTests, testDependency)) {
@@ -920,7 +920,7 @@ void cmCTestMultiProcessHandler::MarkFinished()
 static Json::Value DumpToJsonArray(const std::set<std::string>& values)
 {
   Json::Value jsonArray = Json::arrayValue;
-  for (auto& it : values) {
+  for (const auto& it : values) {
     jsonArray.append(it);
   }
   return jsonArray;
@@ -929,7 +929,7 @@ static Json::Value DumpToJsonArray(const std::set<std::string>& values)
 static Json::Value DumpToJsonArray(const std::vector<std::string>& values)
 {
   Json::Value jsonArray = Json::arrayValue;
-  for (auto& it : values) {
+  for (const auto& it : values) {
     jsonArray.append(it);
   }
   return jsonArray;
@@ -939,7 +939,7 @@ static Json::Value DumpRegExToJsonArray(
   const std::vector<std::pair<cmsys::RegularExpression, std::string>>& values)
 {
   Json::Value jsonArray = Json::arrayValue;
-  for (auto& it : values) {
+  for (const auto& it : values) {
     jsonArray.append(it.second);
   }
   return jsonArray;
@@ -949,7 +949,7 @@ static Json::Value DumpMeasurementToJsonArray(
   const std::map<std::string, std::string>& values)
 {
   Json::Value jsonArray = Json::arrayValue;
-  for (auto& it : values) {
+  for (const auto& it : values) {
     Json::Value measurement = Json::objectValue;
     measurement["measurement"] = it.first;
     measurement["value"] = it.second;
@@ -1274,7 +1274,7 @@ void cmCTestMultiProcessHandler::PrintOutputAsJson()
 void cmCTestMultiProcessHandler::PrintTestList()
 {
   if (this->CTest->GetOutputAsJson()) {
-    PrintOutputAsJson();
+    this->PrintOutputAsJson();
     return;
   }
 
index 1375be4..50c9c16 100644 (file)
@@ -56,7 +56,7 @@ public:
   ChangesParser(cmCTestP4* p4, const char* prefix)
     : P4(p4)
   {
-    this->SetLog(&P4->Log, prefix);
+    this->SetLog(&this->P4->Log, prefix);
     this->RegexIdentify.compile("^Change ([0-9]+) on");
   }
 
@@ -67,7 +67,7 @@ private:
   bool ProcessLine() override
   {
     if (this->RegexIdentify.find(this->Line)) {
-      P4->ChangeLists.push_back(this->RegexIdentify.match(1));
+      this->P4->ChangeLists.push_back(this->RegexIdentify.match(1));
     }
     return true;
   }
@@ -79,7 +79,7 @@ public:
   UserParser(cmCTestP4* p4, const char* prefix)
     : P4(p4)
   {
-    this->SetLog(&P4->Log, prefix);
+    this->SetLog(&this->P4->Log, prefix);
     this->RegexUser.compile("^(.+) <(.*)> \\((.*)\\) accessed (.*)$");
   }
 
@@ -96,7 +96,7 @@ private:
       NewUser.EMail = this->RegexUser.match(2);
       NewUser.Name = this->RegexUser.match(3);
       NewUser.AccessTime = this->RegexUser.match(4);
-      P4->Users[this->RegexUser.match(1)] = NewUser;
+      this->P4->Users[this->RegexUser.match(1)] = NewUser;
 
       return false;
     }
@@ -120,7 +120,7 @@ public:
     : P4(p4)
     , AlreadyNotified(false)
   {
-    this->SetLog(&P4->Log, prefix);
+    this->SetLog(&this->P4->Log, prefix);
     this->RegexDiff.compile("^==== (.*)#[0-9]+ - (.*)");
   }
 
@@ -134,12 +134,12 @@ private:
   {
     if (!this->Line.empty() && this->Line[0] == '=' &&
         this->RegexDiff.find(this->Line)) {
-      CurrentPath = this->RegexDiff.match(1);
-      AlreadyNotified = false;
+      this->CurrentPath = this->RegexDiff.match(1);
+      this->AlreadyNotified = false;
     } else {
-      if (!AlreadyNotified) {
-        P4->DoModification(PathModified, CurrentPath);
-        AlreadyNotified = true;
+      if (!this->AlreadyNotified) {
+        this->P4->DoModification(PathModified, this->CurrentPath);
+        this->AlreadyNotified = true;
       }
     }
     return true;
@@ -148,11 +148,11 @@ private:
 
 cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
 {
-  auto it = Users.find(username);
+  auto it = this->Users.find(username);
 
-  if (it == Users.end()) {
+  if (it == this->Users.end()) {
     std::vector<char const*> p4_users;
-    SetP4Options(p4_users);
+    this->SetP4Options(p4_users);
     p4_users.push_back("users");
     p4_users.push_back("-m");
     p4_users.push_back("1");
@@ -161,11 +161,11 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
 
     UserParser out(this, "users-out> ");
     OutputLogger err(this->Log, "users-err> ");
-    RunChild(&p4_users[0], &out, &err);
+    this->RunChild(&p4_users[0], &out, &err);
 
     // The user should now be added to the map. Search again.
-    it = Users.find(username);
-    if (it == Users.end()) {
+    it = this->Users.find(username);
+    if (it == this->Users.end()) {
       return cmCTestP4::User();
     }
   }
@@ -195,7 +195,7 @@ public:
     , P4(p4)
     , Section(SectionHeader)
   {
-    this->SetLog(&P4->Log, prefix);
+    this->SetLog(&this->P4->Log, prefix);
     this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$");
     this->RegexDiff.compile(R"(^\.\.\. (.*)#[0-9]+ ([^ ]+)$)");
   }
@@ -259,7 +259,7 @@ private:
       this->Rev.Rev = this->RegexHeader.match(1);
       this->Rev.Date = this->RegexHeader.match(4);
 
-      cmCTestP4::User user = P4->GetUserData(this->RegexHeader.match(2));
+      cmCTestP4::User user = this->P4->GetUserData(this->RegexHeader.match(2));
       this->Rev.Author = user.Name;
       this->Rev.EMail = user.EMail;
 
@@ -300,38 +300,38 @@ private:
         change.Action = 'M';
       }
 
-      Changes.push_back(change);
+      this->Changes.push_back(change);
     }
   }
 };
 
 void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
 {
-  if (P4Options.empty()) {
+  if (this->P4Options.empty()) {
     const char* p4 = this->CommandLineTool.c_str();
-    P4Options.emplace_back(p4);
+    this->P4Options.emplace_back(p4);
 
     // The CTEST_P4_CLIENT variable sets the P4 client used when issuing
     // Perforce commands, if it's different from the default one.
     std::string client = this->CTest->GetCTestConfiguration("P4Client");
     if (!client.empty()) {
-      P4Options.emplace_back("-c");
-      P4Options.push_back(client);
+      this->P4Options.emplace_back("-c");
+      this->P4Options.push_back(client);
     }
 
     // Set the message language to be English, in case the P4 admin
     // has localized them
-    P4Options.emplace_back("-L");
-    P4Options.emplace_back("en");
+    this->P4Options.emplace_back("-L");
+    this->P4Options.emplace_back("en");
 
     // The CTEST_P4_OPTIONS variable adds additional Perforce command line
     // options before the main command
     std::string opts = this->CTest->GetCTestConfiguration("P4Options");
-    cm::append(P4Options, cmSystemTools::ParseArguments(opts));
+    cm::append(this->P4Options, cmSystemTools::ParseArguments(opts));
   }
 
   CommandOptions.clear();
-  for (std::string const& o : P4Options) {
+  for (std::string const& o : this->P4Options) {
     CommandOptions.push_back(o.c_str());
   }
 }
@@ -339,7 +339,7 @@ void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
 std::string cmCTestP4::GetWorkingRevision()
 {
   std::vector<char const*> p4_identify;
-  SetP4Options(p4_identify);
+  this->SetP4Options(p4_identify);
 
   p4_identify.push_back("changes");
   p4_identify.push_back("-m");
@@ -354,7 +354,7 @@ std::string cmCTestP4::GetWorkingRevision()
   IdentifyParser out(this, "p4_changes-out> ", rev);
   OutputLogger err(this->Log, "p4_changes-err> ");
 
-  bool result = RunChild(&p4_identify[0], &out, &err);
+  bool result = this->RunChild(&p4_identify[0], &out, &err);
 
   // If there was a problem contacting the server return "<unknown>"
   if (!result) {
@@ -391,7 +391,7 @@ bool cmCTestP4::NoteNewRevision()
 bool cmCTestP4::LoadRevisions()
 {
   std::vector<char const*> p4_changes;
-  SetP4Options(p4_changes);
+  this->SetP4Options(p4_changes);
 
   // Use 'p4 changes ...@old,new' to get a list of changelists
   std::string range = this->SourceDirectory + "/...";
@@ -417,17 +417,17 @@ bool cmCTestP4::LoadRevisions()
   ChangesParser out(this, "p4_changes-out> ");
   OutputLogger err(this->Log, "p4_changes-err> ");
 
-  ChangeLists.clear();
+  this->ChangeLists.clear();
   this->RunChild(&p4_changes[0], &out, &err);
 
-  if (ChangeLists.empty()) {
+  if (this->ChangeLists.empty()) {
     return true;
   }
 
   // p4 describe -s ...@1111111,2222222
   std::vector<char const*> p4_describe;
-  for (std::string const& i : cmReverseRange(ChangeLists)) {
-    SetP4Options(p4_describe);
+  for (std::string const& i : cmReverseRange(this->ChangeLists)) {
+    this->SetP4Options(p4_describe);
     p4_describe.push_back("describe");
     p4_describe.push_back("-s");
     p4_describe.push_back(i.c_str());
@@ -443,7 +443,7 @@ bool cmCTestP4::LoadRevisions()
 bool cmCTestP4::LoadModifications()
 {
   std::vector<char const*> p4_diff;
-  SetP4Options(p4_diff);
+  this->SetP4Options(p4_diff);
 
   p4_diff.push_back("diff");
 
@@ -491,7 +491,7 @@ bool cmCTestP4::UpdateImpl()
   }
 
   std::vector<char const*> p4_sync;
-  SetP4Options(p4_sync);
+  this->SetP4Options(p4_sync);
 
   p4_sync.push_back("sync");
 
index 072af42..4c26b3f 100644 (file)
@@ -17,7 +17,7 @@ bool cmCTestResourceGroupsLexerHelper::ParseString(const std::string& value)
   yyscan_t lexer;
   cmCTestResourceGroups_yylex_init_extra(this, &lexer);
 
-  auto state = cmCTestResourceGroups_yy_scan_string(value.c_str(), lexer);
+  auto* state = cmCTestResourceGroups_yy_scan_string(value.c_str(), lexer);
   int retval = cmCTestResourceGroups_yylex(lexer);
   cmCTestResourceGroups_yy_delete_buffer(state, lexer);
 
index 4d65c9b..5a6c775 100644 (file)
@@ -139,7 +139,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
         s << "SKIP_RETURN_CODE=" << this->TestProperties->SkipReturnCode;
       }
       this->TestResult.CompletionStatus = s.str();
-      cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Skipped ");
+      outputStream << "***Skipped ";
       skipped = true;
     } else if (success != this->TestProperties->WillFail) {
       this->TestResult.Status = cmCTestTestHandler::COMPLETED;
@@ -195,10 +195,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
   sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime().count());
   outputStream << buf << "\n";
 
+  bool passedOrSkipped = passed || skipped;
   if (this->CTest->GetTestProgressOutput()) {
-    if (!passed) {
+    if (!passedOrSkipped) {
       // If the test did not pass, reprint test name and error
-      std::string output = GetTestPrefix(completed, total);
+      std::string output = this->GetTestPrefix(completed, total);
       std::string testName = this->TestProperties->Name;
       const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth();
       testName.resize(maxTestNameWidth + 4, '.');
@@ -211,12 +212,12 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
       cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, "\n"); // flush
     }
     if (completed == total) {
-      std::string testName =
-        GetTestPrefix(completed, total) + this->TestProperties->Name + "\n";
+      std::string testName = this->GetTestPrefix(completed, total) +
+        this->TestProperties->Name + "\n";
       cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, testName);
     }
   }
-  if (!this->CTest->GetTestProgressOutput() || !passed) {
+  if (!this->CTest->GetTestProgressOutput() || !passedOrSkipped) {
     cmCTestLog(this->CTest, HANDLER_OUTPUT, outputStream.str());
   }
 
@@ -485,8 +486,8 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
                  << this->TestProperties->Index << ": "
                  << this->TestProperties->Name << std::endl);
   } else {
-    std::string testName =
-      GetTestPrefix(completed, total) + this->TestProperties->Name + "\n";
+    std::string testName = this->GetTestPrefix(completed, total) +
+      this->TestProperties->Name + "\n";
     cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, testName);
   }
 
index 44dfab2..4692dbd 100644 (file)
@@ -286,9 +286,9 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
   args.push_back(nullptr);
 
   if (strcmp(parameters[0], "update") == 0) {
-    return RunUpdateCommand(&args[0], out, err);
+    return this->RunUpdateCommand(&args[0], out, err);
   }
-  return RunChild(&args[0], out, err);
+  return this->RunChild(&args[0], out, err);
 }
 
 class cmCTestSVN::LogParser
@@ -328,7 +328,7 @@ private:
     this->CData.clear();
     if (name == "logentry") {
       this->Rev = Revision();
-      this->Rev.SVNInfo = &SVNRepo;
+      this->Rev.SVNInfo = &this->SVNRepo;
       if (const char* rev =
             cmCTestSVN::LogParser::FindAttribute(atts, "revision")) {
         this->Rev.Rev = rev;
@@ -354,7 +354,7 @@ private:
       this->SVN->DoRevisionSVN(this->Rev, this->Changes);
     } else if (!this->CData.empty() && name == "path") {
       std::string orig_path(&this->CData[0], this->CData.size());
-      std::string new_path = SVNRepo.BuildLocalPath(orig_path);
+      std::string new_path = this->SVNRepo.BuildLocalPath(orig_path);
       this->CurChange.Path.assign(new_path);
       this->Changes.push_back(this->CurChange);
     } else if (!this->CData.empty() && name == "author") {
index 4d1a589..1cb5d00 100644 (file)
@@ -122,7 +122,7 @@ bool cmCTestSubdirCommand(std::vector<std::string> const& args,
       readit = status.GetMakefile().ReadDependentFile(fname);
     }
     if (!readit) {
-      status.SetError(cmStrCat("Could not find include file: ", fname));
+      status.SetError(cmStrCat("Could not load include file: ", fname));
       return false;
     }
   }
@@ -340,7 +340,7 @@ void cmCTestTestHandler::Initialize()
   this->ExcludeFixtureSetupRegExp.clear();
   this->ExcludeFixtureCleanupRegExp.clear();
 
-  TestsToRunString.clear();
+  this->TestsToRunString.clear();
   this->UseUnion = false;
   this->TestList.clear();
 }
@@ -877,7 +877,7 @@ bool cmCTestTestHandler::ComputeTestList()
     finalList.push_back(tp);
   }
 
-  UpdateForFixtures(finalList);
+  this->UpdateForFixtures(finalList);
 
   // Save the total number of tests before exclusions
   this->TotalNumberOfTests = this->TestList.size();
@@ -906,7 +906,7 @@ void cmCTestTestHandler::ComputeTestListForRerunFailed()
     finalList.push_back(tp);
   }
 
-  UpdateForFixtures(finalList);
+  this->UpdateForFixtures(finalList);
 
   // Save the total number of tests before exclusions
   this->TotalNumberOfTests = this->TestList.size();
@@ -1675,7 +1675,7 @@ std::string cmCTestTestHandler::FindExecutable(
   // if everything else failed, check the users path, but only if a full path
   // wasn't specified
   if (fullPath.empty() && filepath.empty()) {
-    std::string const path = cmSystemTools::FindProgram(filename.c_str());
+    std::string path = cmSystemTools::FindProgram(filename.c_str());
     if (!path.empty()) {
       resultingConfig.clear();
       return path;
index 6fef90a..0ba2c41 100644 (file)
@@ -5,7 +5,6 @@
 #include "cmCTest.h"
 #include "cmCTestUpdateHandler.h"
 #include "cmMakefile.h"
-#include "cmProperty.h"
 #include "cmSystemTools.h"
 
 cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
@@ -18,7 +17,7 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
     this->CTest->SetCTestConfiguration(
       "SourceDirectory",
       cmSystemTools::CollapseFullPath(
-        cmToCStrSafe(this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY"))),
+        this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
       this->Quiet);
   }
   std::string source_dir =
index 409025f..3a6651f 100644 (file)
@@ -66,7 +66,7 @@ public:
         }
         foundFile = true;
         inSource = false;
-        filename = getValue(line, 0);
+        filename = this->getValue(line, 0);
       } else if ((line.find("coverage") != std::string::npos) && foundFile &&
                  inSource) {
         /*
@@ -78,7 +78,7 @@ public:
          *  FoundFile and foundSource ensure that
          *  only the value of the line coverage is captured
          */
-        std::string result = getValue(line, 1);
+        std::string result = this->getValue(line, 1);
         result = result.substr(2);
         if (result == "\"\"") {
           // Empty quotation marks indicate that the
index 711a856..9311769 100644 (file)
@@ -66,7 +66,7 @@ protected:
 
           // Check if this is an absolute path that falls within our
           // source or binary directories.
-          for (std::string const& filePath : FilePaths) {
+          for (std::string const& filePath : this->FilePaths) {
             if (cmHasPrefix(filename, filePath)) {
               this->CurFileName = filename;
               break;
@@ -76,7 +76,7 @@ protected:
           if (this->CurFileName.empty()) {
             // Check if this is a path that is relative to our source or
             // binary directories.
-            for (std::string const& filePath : FilePaths) {
+            for (std::string const& filePath : this->FilePaths) {
               finalpath = cmStrCat(filePath, "/", filename);
               if (cmSystemTools::FileExists(finalpath)) {
                 this->CurFileName = finalpath;
index 016e90c..640873e 100644 (file)
@@ -133,7 +133,7 @@ public:
     cmsys::Glob gl;
     gl.RecurseOn();
     gl.RecurseThroughSymlinksOff();
-    std::string glob = Coverage.SourceDir + "*/" + filename;
+    std::string glob = this->Coverage.SourceDir + "*/" + filename;
     gl.FindFiles(glob);
     std::vector<std::string> const& files = gl.GetFiles();
     if (files.empty()) {
index 9ee1c17..16bca01 100644 (file)
@@ -152,7 +152,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
 
 void cmProcess::StartTimer()
 {
-  auto properties = this->Runner->GetTestProperties();
+  auto* properties = this->Runner->GetTestProperties();
   auto msec =
     std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout);
 
@@ -177,7 +177,7 @@ bool cmProcess::Buffer::GetLine(std::string& line)
 
       // Start a new range for the next line.
       ++this->Last;
-      this->First = Last;
+      this->First = this->Last;
 
       // Return the line extracted.
       return true;
@@ -209,7 +209,7 @@ bool cmProcess::Buffer::GetLast(std::string& line)
 void cmProcess::OnReadCB(uv_stream_t* stream, ssize_t nread,
                          const uv_buf_t* buf)
 {
-  auto self = static_cast<cmProcess*>(stream->data);
+  auto* self = static_cast<cmProcess*>(stream->data);
   self->OnRead(nread, buf);
 }
 
@@ -256,7 +256,7 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
 void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
                              uv_buf_t* buf)
 {
-  auto self = static_cast<cmProcess*>(handle->data);
+  auto* self = static_cast<cmProcess*>(handle->data);
   self->OnAllocate(suggested_size, buf);
 }
 
@@ -272,7 +272,7 @@ void cmProcess::OnAllocate(size_t /*suggested_size*/, uv_buf_t* buf)
 
 void cmProcess::OnTimeoutCB(uv_timer_t* timer)
 {
-  auto self = static_cast<cmProcess*>(timer->data);
+  auto* self = static_cast<cmProcess*>(timer->data);
   self->OnTimeout();
 }
 
@@ -298,7 +298,7 @@ void cmProcess::OnTimeout()
 void cmProcess::OnExitCB(uv_process_t* process, int64_t exit_status,
                          int term_signal)
 {
-  auto self = static_cast<cmProcess*>(process->data);
+  auto* self = static_cast<cmProcess*>(process->data);
   self->OnExit(exit_status, term_signal);
 }
 
@@ -358,7 +358,7 @@ void cmProcess::ResetStartTime()
   this->StartTime = std::chrono::steady_clock::now();
 }
 
-cmProcess::Exception cmProcess::GetExitException()
+cmProcess::Exception cmProcess::GetExitException() const
 {
   auto exception = Exception::None;
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -430,7 +430,7 @@ cmProcess::Exception cmProcess::GetExitException()
   return exception;
 }
 
-std::string cmProcess::GetExitExceptionString()
+std::string cmProcess::GetExitExceptionString() const
 {
   std::string exception_str;
 #if defined(_WIN32)
index 9eec952..a44aeb0 100644 (file)
@@ -67,8 +67,8 @@ public:
     Other
   };
 
-  Exception GetExitException();
-  std::string GetExitExceptionString();
+  Exception GetExitException() const;
+  std::string GetExitExceptionString() const;
 
   std::unique_ptr<cmCTestRunTest> GetRunner()
   {
index 6fc556c..069c02e 100644 (file)
@@ -405,7 +405,7 @@ void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message)
 
     // Get the help string of the current entry
     // and add it to the help string
-    auto cmakeState = this->CMakeInstance->GetState();
+    auto* cmakeState = this->CMakeInstance->GetState();
     cmProp existingValue = cmakeState->GetCacheEntryValue(labelValue);
     if (existingValue) {
       cmProp help =
@@ -1000,7 +1000,7 @@ void cmCursesMainForm::DisplayOutputs(std::string const& newOutput)
   getmaxyx(stdscr, yi, xi);
 
   if (CurrentForm != this->LogForm.get()) {
-    auto newLogForm = new cmCursesLongMessageForm(
+    auto* newLogForm = new cmCursesLongMessageForm(
       this->Outputs, this->LastProgress.c_str(),
       cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
     CurrentForm = newLogForm;
index 21c499e..8f26b9a 100644 (file)
@@ -5,7 +5,7 @@ project(CMAKE_FORM)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 34dc8ec..b8bc82c 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
 /* C LALR(1) parser skeleton written by Richard Stallman, by
    simplifying the original so-called "semantic" parser.  */
 
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
 /* All symbols defined below should begin with yy or YY, to avoid
    infringing on user name space.  This should be done even for local
    variables, as they might otherwise be expanded by user macros.
    define necessary library symbols; they are noted "INFRINGES ON
    USER NAME SPACE" below.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
+/* Identify Bison output, and Bison version.  */
+#define YYBISON 30704
 
-/* Bison version.  */
-#define YYBISON_VERSION "3.4.2"
+/* Bison version string.  */
+#define YYBISON_VERSION "3.7.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -70,7 +71,6 @@
 #define yydebug         cmCommandArgument_yydebug
 #define yynerrs         cmCommandArgument_yynerrs
 
-
 /* First part of user prologue.  */
 #line 1 "cmCommandArgumentParser.y"
 
@@ -82,10 +82,7 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
-
-Modify cmCommandArgumentParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+  bison --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
 
 */
 
@@ -100,6 +97,7 @@ Modify cmCommandArgumentParser.cxx:
 # include <malloc.h>
 #endif
 
+#include <stdint.h>
 /* Make sure the parser uses standard memory allocation.  The default
    generated parser malloc/free declarations do not work on all
    platforms.  */
@@ -110,7 +108,6 @@ Modify cmCommandArgumentParser.cxx:
 /*-------------------------------------------------------------------------*/
 #include "cmCommandArgumentParserHelper.h" /* Interface to parser object.  */
 #include "cmCommandArgumentLexer.h"  /* Interface to lexer object.  */
-#include "cmCommandArgumentParserTokens.h" /* Need YYSTYPE for YY_DECL.  */
 
 /* Forward declare the lexer entry point.  */
 YY_DECL;
@@ -132,10 +129,20 @@ static void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message);
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
 #endif
 
-#line 138 "cmCommandArgumentParser.cxx"
+#line 136 "cmCommandArgumentParser.cxx"
 
+# ifndef YY_CAST
+#  ifdef __cplusplus
+#   define YY_CAST(Type, Val) static_cast<Type> (Val)
+#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+#  else
+#   define YY_CAST(Type, Val) ((Type) (Val))
+#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+#  endif
+# endif
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -148,95 +155,115 @@ static void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message);
 #  endif
 # endif
 
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Use api.header.include to #include this header
-   instead of duplicating it here.  */
-#ifndef YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
-# define YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
-/* Debug traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int cmCommandArgument_yydebug;
-#endif
-
-/* Token type.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-  enum yytokentype
-  {
-    cal_ENVCURLY = 258,
-    cal_NCURLY = 259,
-    cal_DCURLY = 260,
-    cal_DOLLAR = 261,
-    cal_LCURLY = 262,
-    cal_RCURLY = 263,
-    cal_NAME = 264,
-    cal_BSLASH = 265,
-    cal_SYMBOL = 266,
-    cal_AT = 267,
-    cal_ERROR = 268,
-    cal_ATNAME = 269
-  };
-#endif
-/* Tokens.  */
-#define cal_ENVCURLY 258
-#define cal_NCURLY 259
-#define cal_DCURLY 260
-#define cal_DOLLAR 261
-#define cal_LCURLY 262
-#define cal_RCURLY 263
-#define cal_NAME 264
-#define cal_BSLASH 265
-#define cal_SYMBOL 266
-#define cal_AT 267
-#define cal_ERROR 268
-#define cal_ATNAME 269
+#include "cmCommandArgumentParserTokens.h"
+/* Symbol kind.  */
+enum yysymbol_kind_t
+{
+  YYSYMBOL_YYEMPTY = -2,
+  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
+  YYSYMBOL_YYerror = 1,                    /* error  */
+  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
+  YYSYMBOL_cal_ENVCURLY = 3,               /* cal_ENVCURLY  */
+  YYSYMBOL_cal_NCURLY = 4,                 /* cal_NCURLY  */
+  YYSYMBOL_cal_DCURLY = 5,                 /* cal_DCURLY  */
+  YYSYMBOL_cal_DOLLAR = 6,                 /* "$"  */
+  YYSYMBOL_cal_LCURLY = 7,                 /* "{"  */
+  YYSYMBOL_cal_RCURLY = 8,                 /* "}"  */
+  YYSYMBOL_cal_NAME = 9,                   /* cal_NAME  */
+  YYSYMBOL_cal_BSLASH = 10,                /* "\\"  */
+  YYSYMBOL_cal_SYMBOL = 11,                /* cal_SYMBOL  */
+  YYSYMBOL_cal_AT = 12,                    /* "@"  */
+  YYSYMBOL_cal_ERROR = 13,                 /* cal_ERROR  */
+  YYSYMBOL_cal_ATNAME = 14,                /* cal_ATNAME  */
+  YYSYMBOL_YYACCEPT = 15,                  /* $accept  */
+  YYSYMBOL_Start = 16,                     /* Start  */
+  YYSYMBOL_GoalWithOptionalBackSlash = 17, /* GoalWithOptionalBackSlash  */
+  YYSYMBOL_Goal = 18,                      /* Goal  */
+  YYSYMBOL_String = 19,                    /* String  */
+  YYSYMBOL_OuterText = 20,                 /* OuterText  */
+  YYSYMBOL_Variable = 21,                  /* Variable  */
+  YYSYMBOL_EnvVarName = 22,                /* EnvVarName  */
+  YYSYMBOL_MultipleIds = 23,               /* MultipleIds  */
+  YYSYMBOL_ID = 24                         /* ID  */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
 
-/* Value type.  */
 
 
 
-int cmCommandArgument_yyparse (yyscan_t yyscanner);
+#ifdef short
+# undef short
+#endif
 
-#endif /* !YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED  */
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+   <limits.h> and (if available) <stdint.h> are included
+   so that the code can choose integer types of a good width.  */
 
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+#  define YY_STDINT_H
+# endif
+#endif
 
+/* Narrow types that promote to a signed type and that can represent a
+   signed or unsigned integer of at least N bits.  In tables they can
+   save space and decrease cache pressure.  Promoting to a signed type
+   helps avoid bugs in integer arithmetic.  */
 
-#ifdef short
-# undef short
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
 #endif
 
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
 #else
-typedef unsigned char yytype_uint8;
+typedef short yytype_int16;
 #endif
 
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
 #else
-typedef signed char yytype_int8;
+typedef short yytype_uint8;
 #endif
 
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
 typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
 #endif
 
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short yytype_int16;
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+#  define YYPTRDIFF_T __PTRDIFF_TYPE__
+#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+#  ifndef ptrdiff_t
+#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  endif
+#  define YYPTRDIFF_T ptrdiff_t
+#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+#  define YYPTRDIFF_T long
+#  define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
 #endif
 
 #ifndef YYSIZE_T
@@ -244,7 +271,7 @@ typedef short yytype_int16;
 #  define YYSIZE_T __SIZE_TYPE__
 # elif defined size_t
 #  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
 #  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
 #  define YYSIZE_T size_t
 # else
@@ -252,7 +279,20 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+#define YYSIZE_MAXIMUM                                  \
+  YY_CAST (YYPTRDIFF_T,                                 \
+           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
+            ? YYPTRDIFF_MAXIMUM                         \
+            : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int8 yy_state_t;
+
+/* State numbers in computations.  */
+typedef int yy_state_fast_t;
 
 #ifndef YY_
 # if defined YYENABLE_NLS && YYENABLE_NLS
@@ -266,22 +306,21 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#ifndef YY_ATTRIBUTE
-# if (defined __GNUC__                                               \
-      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
-     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
-#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
-# else
-#  define YY_ATTRIBUTE(Spec) /* empty */
-# endif
-#endif
 
 #ifndef YY_ATTRIBUTE_PURE
-# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define YY_ATTRIBUTE_PURE
+# endif
 #endif
 
 #ifndef YY_ATTRIBUTE_UNUSED
-# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+#  define YY_ATTRIBUTE_UNUSED
+# endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
@@ -293,11 +332,11 @@ typedef short yytype_int16;
 
 #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
 /* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
-    _Pragma ("GCC diagnostic push") \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                            \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
     _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
     _Pragma ("GCC diagnostic pop")
 #else
 # define YY_INITIAL_VALUE(Value) Value
@@ -310,10 +349,22 @@ typedef short yytype_int16;
 # define YY_INITIAL_VALUE(Value) /* Nothing. */
 #endif
 
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN                          \
+    _Pragma ("GCC diagnostic push")                            \
+    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END            \
+    _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
 
 #define YY_ASSERT(E) ((void) (0 && (E)))
 
-#if ! defined yyoverflow || YYERROR_VERBOSE
+#if 1
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
@@ -378,8 +429,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 # endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
+#endif /* 1 */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus \
@@ -388,17 +438,17 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  yytype_int16 yyss_alloc;
+  yy_state_t yyss_alloc;
   YYSTYPE yyvs_alloc;
 };
 
 /* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
 
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
       + YYSTACK_GAP_MAXIMUM)
 
 # define YYCOPY_NEEDED 1
@@ -411,11 +461,11 @@ union yyalloc
 # define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
     do                                                                  \
       {                                                                 \
-        YYSIZE_T yynewbytes;                                            \
+        YYPTRDIFF_T yynewbytes;                                         \
         YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
         Stack = &yyptr->Stack_alloc;                                    \
-        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-        yyptr += yynewbytes / sizeof (*yyptr);                          \
+        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
       }                                                                 \
     while (0)
 
@@ -427,12 +477,12 @@ union yyalloc
 # ifndef YYCOPY
 #  if defined __GNUC__ && 1 < __GNUC__
 #   define YYCOPY(Dst, Src, Count) \
-      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
 #  else
 #   define YYCOPY(Dst, Src, Count)              \
       do                                        \
         {                                       \
-          YYSIZE_T yyi;                         \
+          YYPTRDIFF_T yyi;                      \
           for (yyi = 0; yyi < (Count); yyi++)   \
             (Dst)[yyi] = (Src)[yyi];            \
         }                                       \
@@ -455,17 +505,20 @@ union yyalloc
 /* YYNSTATES -- Number of states.  */
 #define YYNSTATES  33
 
-#define YYUNDEFTOK  2
+/* YYMAXUTOK -- Last valid token kind.  */
 #define YYMAXUTOK   269
 
+
 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex, with out-of-bounds checking.  */
-#define YYTRANSLATE(YYX)                                                \
-  ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+#define YYTRANSLATE(YYX)                                \
+  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
+   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
+   : YYSYMBOL_YYUNDEF)
 
 /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex.  */
-static const yytype_uint8 yytranslate[] =
+static const yytype_int8 yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -500,43 +553,56 @@ static const yytype_uint8 yytranslate[] =
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    99,    99,   105,   108,   113,   116,   121,   124,   129,
-     132,   135,   138,   141,   144,   149,   152,   155,   158,   163,
-     166,   171,   174,   179,   182
+       0,    97,    97,   103,   106,   111,   114,   119,   122,   127,
+     130,   133,   136,   139,   142,   147,   150,   153,   156,   161,
+     164,   169,   172,   177,   180
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || 1
+/** Accessing symbol of state STATE.  */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+   YYSYMBOL.  No bounds checking.  */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "cal_ENVCURLY", "cal_NCURLY",
-  "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME", "\"\\\\\"",
-  "cal_SYMBOL", "\"@\"", "cal_ERROR", "cal_ATNAME", "$accept", "Start",
-  "GoalWithOptionalBackSlash", "Goal", "String", "OuterText", "Variable",
-  "EnvVarName", "MultipleIds", "ID", YY_NULLPTR
+  "\"end of file\"", "error", "\"invalid token\"", "cal_ENVCURLY",
+  "cal_NCURLY", "cal_DCURLY", "\"$\"", "\"{\"", "\"}\"", "cal_NAME",
+  "\"\\\\\"", "cal_SYMBOL", "\"@\"", "cal_ERROR", "cal_ATNAME", "$accept",
+  "Start", "GoalWithOptionalBackSlash", "Goal", "String", "OuterText",
+  "Variable", "EnvVarName", "MultipleIds", "ID", YY_NULLPTR
 };
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+  return yytname[yysymbol];
+}
 #endif
 
-# ifdef YYPRINT
+#ifdef YYPRINT
 /* YYTOKNUM[NUM] -- (External) token number corresponding to the
    (internal) symbol number NUM (which must be that of a token).  */
-static const yytype_uint16 yytoknum[] =
+static const yytype_int16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269
 };
-# endif
+#endif
 
-#define YYPACT_NINF -3
+#define YYPACT_NINF (-3)
 
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-3)))
+#define yypact_value_is_default(Yyn) \
+  ((Yyn) == YYPACT_NINF)
 
-#define YYTABLE_NINF -1
+#define YYTABLE_NINF (-1)
 
-#define yytable_value_is_error(Yytable_value) \
+#define yytable_value_is_error(Yyn) \
   0
 
   /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
@@ -552,7 +618,7 @@ static const yytype_int8 yypact[] =
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
      Performed when YYTABLE does not specify something else to do.  Zero
      means the default is an error.  */
-static const yytype_uint8 yydefact[] =
+static const yytype_int8 yydefact[] =
 {
        5,    21,    21,    21,    11,    12,    13,     9,    14,    10,
       18,     0,     2,     3,     5,     7,     8,    23,    21,    24,
@@ -575,7 +641,7 @@ static const yytype_int8 yydefgoto[] =
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
      positive, shift that token.  If negative, reduce the rule whose
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
-static const yytype_uint8 yytable[] =
+static const yytype_int8 yytable[] =
 {
       23,    24,    16,     1,     2,     3,     4,     5,     6,     7,
       25,     8,     9,    26,    10,    29,    16,     1,     2,     3,
@@ -595,7 +661,7 @@ static const yytype_int8 yycheck[] =
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
+static const yytype_int8 yystos[] =
 {
        0,     3,     4,     5,     6,     7,     8,     9,    11,    12,
       14,    16,    17,    18,    19,    20,    21,     9,    11,    21,
@@ -604,7 +670,7 @@ static const yytype_uint8 yystos[] =
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
+static const yytype_int8 yyr1[] =
 {
        0,    15,    16,    17,    17,    18,    18,    19,    19,    20,
       20,    20,    20,    20,    20,    21,    21,    21,    21,    22,
@@ -612,7 +678,7 @@ static const yytype_uint8 yyr1[] =
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
+static const yytype_int8 yyr2[] =
 {
        0,     2,     1,     1,     2,     0,     2,     1,     1,     1,
        1,     1,     1,     1,     1,     3,     3,     3,     1,     1,
@@ -620,10 +686,10 @@ static const yytype_uint8 yyr2[] =
 };
 
 
+enum { YYENOMEM = -2 };
+
 #define yyerrok         (yyerrstatus = 0)
 #define yyclearin       (yychar = YYEMPTY)
-#define YYEMPTY         (-2)
-#define YYEOF           0
 
 #define YYACCEPT        goto yyacceptlab
 #define YYABORT         goto yyabortlab
@@ -649,10 +715,9 @@ static const yytype_uint8 yyr2[] =
       }                                                           \
   while (0)
 
-/* Error token number */
-#define YYTERROR        1
-#define YYERRCODE       256
-
+/* Backward compatibility with an undocumented macro.
+   Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
 
 
 /* Enable debugging if requested.  */
@@ -670,18 +735,18 @@ do {                                            \
 } while (0)
 
 /* This macro is provided for backward compatibility. */
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
+# ifndef YY_LOCATION_PRINT
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
 
 
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
 do {                                                                      \
   if (yydebug)                                                            \
     {                                                                     \
       YYFPRINTF (stderr, "%s ", Title);                                   \
       yy_symbol_print (stderr,                                            \
-                  Type, Value, yyscanner); \
+                  Kind, Value, yyscanner); \
       YYFPRINTF (stderr, "\n");                                           \
     }                                                                     \
 } while (0)
@@ -692,7 +757,8 @@ do {                                                                      \
 `-----------------------------------*/
 
 static void
-yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_value_print (FILE *yyo,
+                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   FILE *yyoutput = yyo;
   YYUSE (yyoutput);
@@ -700,11 +766,11 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
   if (!yyvaluep)
     return;
 # ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
+  if (yykind < YYNTOKENS)
+    YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
 # endif
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
@@ -714,12 +780,13 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
 `---------------------------*/
 
 static void
-yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_print (FILE *yyo,
+                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   YYFPRINTF (yyo, "%s %s (",
-             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
 
-  yy_symbol_value_print (yyo, yytype, yyvaluep, yyscanner);
+  yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
   YYFPRINTF (yyo, ")");
 }
 
@@ -729,7 +796,7 @@ yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t
 `------------------------------------------------------------------*/
 
 static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
 {
   YYFPRINTF (stderr, "Stack now");
   for (; yybottom <= yytop; yybottom++)
@@ -752,21 +819,21 @@ do {                                                            \
 `------------------------------------------------*/
 
 static void
-yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, yyscan_t yyscanner)
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+                 int yyrule, yyscan_t yyscanner)
 {
-  unsigned long yylno = yyrline[yyrule];
+  int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
   int yyi;
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
              yyrule - 1, yylno);
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr,
-                       yystos[yyssp[yyi + 1 - yynrhs]],
-                       &yyvsp[(yyi + 1) - (yynrhs)]
-                                              , yyscanner);
+                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+                       &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -781,8 +848,8 @@ do {                                    \
    multiple parsers can coexist.  */
 int yydebug;
 #else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
 # define YY_STACK_PRINT(Bottom, Top)
 # define YY_REDUCE_PRINT(Rule)
 #endif /* !YYDEBUG */
@@ -805,28 +872,76 @@ int yydebug;
 #endif
 
 
-#if YYERROR_VERBOSE
+/* Context of a parse error.  */
+typedef struct
+{
+  yy_state_t *yyssp;
+  yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+   current YYCTX, and return the number of tokens stored in YYARG.  If
+   YYARG is null, return the number of expected tokens (guaranteed to
+   be less than YYNTOKENS).  Return YYENOMEM on memory exhaustion.
+   Return 0 if there are more than YYARGN expected tokens, yet fill
+   YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+                            yysymbol_kind_t yyarg[], int yyargn)
+{
+  /* Actual size of YYARG. */
+  int yycount = 0;
+  int yyn = yypact[+*yyctx->yyssp];
+  if (!yypact_value_is_default (yyn))
+    {
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+         YYCHECK.  In other words, skip the first -YYN actions for
+         this state because they are default actions.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yyx;
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+        if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+            && !yytable_value_is_error (yytable[yyx + yyn]))
+          {
+            if (!yyarg)
+              ++yycount;
+            else if (yycount == yyargn)
+              return 0;
+            else
+              yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+          }
+    }
+  if (yyarg && yycount == 0 && 0 < yyargn)
+    yyarg[0] = YYSYMBOL_YYEMPTY;
+  return yycount;
+}
+
+
 
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+#  define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
 /* Return the length of YYSTR.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yystrlen (const char *yystr)
 {
-  YYSIZE_T yylen;
+  YYPTRDIFF_T yylen;
   for (yylen = 0; yystr[yylen]; yylen++)
     continue;
   return yylen;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#  define yystpcpy stpcpy
+# else
 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    YYDEST.  */
 static char *
@@ -840,10 +955,10 @@ yystpcpy (char *yydest, const char *yysrc)
 
   return yyd - 1;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yytnamerr
+#ifndef yytnamerr
 /* Copy to YYRES the contents of YYSTR after stripping away unnecessary
    quotes and backslashes, so that it's suitable for yyerror.  The
    heuristic is that double-quoting is unnecessary unless the string
@@ -851,14 +966,13 @@ yystpcpy (char *yydest, const char *yysrc)
    backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
    null, do not copy; instead, return the length of what the result
    would have been.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yytnamerr (char *yyres, const char *yystr)
 {
   if (*yystr == '"')
     {
-      YYSIZE_T yyn = 0;
+      YYPTRDIFF_T yyn = 0;
       char const *yyp = yystr;
-
       for (;;)
         switch (*++yyp)
           {
@@ -887,36 +1001,20 @@ yytnamerr (char *yyres, const char *yystr)
     do_not_strip_quotes: ;
     }
 
-  if (! yyres)
+  if (yyres)
+    return yystpcpy (yyres, yystr) - yyres;
+  else
     return yystrlen (yystr);
-
-  return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres);
 }
-# endif
+#endif
 
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN for the state stack whose top is
-   YYSSP.
 
-   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
-   not large enough to hold the message.  In that case, also set
-   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
-   required number of bytes is too large to store.  */
 static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                yytype_int16 *yyssp, int yytoken)
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+                           yysymbol_kind_t yyarg[], int yyargn)
 {
-  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
-  YYSIZE_T yysize = yysize0;
-  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-  /* Internationalized format string. */
-  const char *yyformat = YY_NULLPTR;
-  /* Arguments of yyformat. */
-  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-  /* Number of reported tokens (one for the "unexpected", one per
-     "expected"). */
+  /* Actual size of YYARG. */
   int yycount = 0;
-
   /* There are many possibilities here to consider:
      - If this state is a consistent state with a default action, then
        the only way this function was invoked is if the default action
@@ -940,49 +1038,54 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
        one exception: it will still contain any token that will not be
        accepted due to an error action in a later state.
   */
-  if (yytoken != YYEMPTY)
+  if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
     {
-      int yyn = yypact[*yyssp];
-      yyarg[yycount++] = yytname[yytoken];
-      if (!yypact_value_is_default (yyn))
-        {
-          /* Start YYX at -YYN if negative to avoid negative indexes in
-             YYCHECK.  In other words, skip the first -YYN actions for
-             this state because they are default actions.  */
-          int yyxbegin = yyn < 0 ? -yyn : 0;
-          /* Stay within bounds of both yycheck and yytname.  */
-          int yychecklim = YYLAST - yyn + 1;
-          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-          int yyx;
-
-          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
-                && !yytable_value_is_error (yytable[yyx + yyn]))
-              {
-                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-                  {
-                    yycount = 1;
-                    yysize = yysize0;
-                    break;
-                  }
-                yyarg[yycount++] = yytname[yyx];
-                {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
-                  if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-                    yysize = yysize1;
-                  else
-                    return 2;
-                }
-              }
-        }
+      int yyn;
+      if (yyarg)
+        yyarg[yycount] = yyctx->yytoken;
+      ++yycount;
+      yyn = yypcontext_expected_tokens (yyctx,
+                                        yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+      if (yyn == YYENOMEM)
+        return YYENOMEM;
+      else
+        yycount += yyn;
     }
+  return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return -1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return YYENOMEM if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+                const yypcontext_t *yyctx)
+{
+  enum { YYARGS_MAX = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat: reported tokens (one for the "unexpected",
+     one per "expected"). */
+  yysymbol_kind_t yyarg[YYARGS_MAX];
+  /* Cumulated lengths of YYARG.  */
+  YYPTRDIFF_T yysize = 0;
+
+  /* Actual size of YYARG. */
+  int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+  if (yycount == YYENOMEM)
+    return YYENOMEM;
 
   switch (yycount)
     {
-# define YYCASE_(N, S)                      \
+#define YYCASE_(N, S)                       \
       case N:                               \
         yyformat = S;                       \
-      break
+        break
     default: /* Avoid compiler warnings. */
       YYCASE_(0, YY_("syntax error"));
       YYCASE_(1, YY_("syntax error, unexpected %s"));
@@ -990,15 +1093,23 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
+#undef YYCASE_
     }
 
+  /* Compute error message size.  Don't count the "%s"s, but reserve
+     room for the terminator.  */
+  yysize = yystrlen (yyformat) - 2 * yycount + 1;
   {
-    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
-    if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-      yysize = yysize1;
-    else
-      return 2;
+    int yyi;
+    for (yyi = 0; yyi < yycount; ++yyi)
+      {
+        YYPTRDIFF_T yysize1
+          = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+        if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+          yysize = yysize1;
+        else
+          return YYENOMEM;
+      }
   }
 
   if (*yymsg_alloc < yysize)
@@ -1007,7 +1118,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       if (! (yysize <= *yymsg_alloc
              && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
         *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
-      return 1;
+      return -1;
     }
 
   /* Avoid sprintf, as that infringes on the user's name space.
@@ -1019,40 +1130,43 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
     while ((*yyp = *yyformat) != '\0')
       if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
         {
-          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
           yyformat += 2;
         }
       else
         {
-          yyp++;
-          yyformat++;
+          ++yyp;
+          ++yyformat;
         }
   }
   return 0;
 }
-#endif /* YYERROR_VERBOSE */
+
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
 `-----------------------------------------------*/
 
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+yydestruct (const char *yymsg,
+            yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
 {
   YYUSE (yyvaluep);
   YYUSE (yyscanner);
   if (!yymsg)
     yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
 
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
 
 
+
+
 /*----------.
 | yyparse.  |
 `----------*/
@@ -1060,7 +1174,7 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner
 int
 yyparse (yyscan_t yyscanner)
 {
-/* The lookahead symbol.  */
+/* Lookahead token kind.  */
 int yychar;
 
 
@@ -1071,45 +1185,41 @@ YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
 YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
 
     /* Number of syntax errors so far.  */
-    int yynerrs;
+    int yynerrs = 0;
 
-    int yystate;
+    yy_state_fast_t yystate = 0;
     /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus;
+    int yyerrstatus = 0;
 
-    /* The stacks and their tools:
-       'yyss': related to states.
-       'yyvs': related to semantic values.
-
-       Refer to the stacks through separate pointers, to allow yyoverflow
+    /* Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
 
-    /* The state stack.  */
-    yytype_int16 yyssa[YYINITDEPTH];
-    yytype_int16 *yyss;
-    yytype_int16 *yyssp;
+    /* Their size.  */
+    YYPTRDIFF_T yystacksize = YYINITDEPTH;
 
-    /* The semantic value stack.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs;
-    YYSTYPE *yyvsp;
+    /* The state stack: array, bottom, top.  */
+    yy_state_t yyssa[YYINITDEPTH];
+    yy_state_t *yyss = yyssa;
+    yy_state_t *yyssp = yyss;
 
-    YYSIZE_T yystacksize;
+    /* The semantic value stack: array, bottom, top.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs = yyvsa;
+    YYSTYPE *yyvsp = yyvs;
 
   int yyn;
+  /* The return value of yyparse.  */
   int yyresult;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken = 0;
+  /* Lookahead symbol kind.  */
+  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
 
-#if YYERROR_VERBOSE
   /* Buffer for error messages, and its allocated size.  */
   char yymsgbuf[128];
   char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
+  YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
 
 #define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
 
@@ -1117,15 +1227,8 @@ YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
 
-  yyssp = yyss = yyssa;
-  yyvsp = yyvs = yyvsa;
-  yystacksize = YYINITDEPTH;
-
   YYDPRINTF ((stderr, "Starting parse\n"));
 
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
   yychar = YYEMPTY; /* Cause a token to be read.  */
   goto yysetstate;
 
@@ -1140,12 +1243,15 @@ yynewstate:
 
 
 /*--------------------------------------------------------------------.
-| yynewstate -- set current state (the top of the stack) to yystate.  |
+| yysetstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
   YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
-  *yyssp = (yytype_int16) yystate;
+  YY_IGNORE_USELESS_CAST_BEGIN
+  *yyssp = YY_CAST (yy_state_t, yystate);
+  YY_IGNORE_USELESS_CAST_END
+  YY_STACK_PRINT (yyss, yyssp);
 
   if (yyss + yystacksize - 1 <= yyssp)
 #if !defined yyoverflow && !defined YYSTACK_RELOCATE
@@ -1153,23 +1259,23 @@ yysetstate:
 #else
     {
       /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1);
+      YYPTRDIFF_T yysize = yyssp - yyss + 1;
 
 # if defined yyoverflow
       {
         /* Give user a chance to reallocate the stack.  Use copies of
            these so that the &'s don't force the real ones into
            memory.  */
+        yy_state_t *yyss1 = yyss;
         YYSTYPE *yyvs1 = yyvs;
-        yytype_int16 *yyss1 = yyss;
 
         /* Each stack pointer address is followed by the size of the
            data in use in that stack, in bytes.  This used to be a
            conditional around just the two extra args, but that might
            be undefined if yyoverflow is a macro.  */
         yyoverflow (YY_("memory exhausted"),
-                    &yyss1, yysize * sizeof (*yyssp),
-                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yyss1, yysize * YYSIZEOF (*yyssp),
+                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
                     &yystacksize);
         yyss = yyss1;
         yyvs = yyvs1;
@@ -1183,14 +1289,15 @@ yysetstate:
         yystacksize = YYMAXDEPTH;
 
       {
-        yytype_int16 *yyss1 = yyss;
+        yy_state_t *yyss1 = yyss;
         union yyalloc *yyptr =
-          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+          YY_CAST (union yyalloc *,
+                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
         if (! yyptr)
           goto yyexhaustedlab;
         YYSTACK_RELOCATE (yyss_alloc, yyss);
         YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-# undef YYSTACK_RELOCATE
+#  undef YYSTACK_RELOCATE
         if (yyss1 != yyssa)
           YYSTACK_FREE (yyss1);
       }
@@ -1199,8 +1306,10 @@ yysetstate:
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
 
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                  (unsigned long) yystacksize));
+      YY_IGNORE_USELESS_CAST_BEGIN
+      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+                  YY_CAST (long, yystacksize)));
+      YY_IGNORE_USELESS_CAST_END
 
       if (yyss + yystacksize - 1 <= yyssp)
         YYABORT;
@@ -1227,18 +1336,29 @@ yybackup:
 
   /* Not known => get a lookahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
   if (yychar == YYEMPTY)
     {
-      YYDPRINTF ((stderr, "Reading a token"));
+      YYDPRINTF ((stderr, "Reading a token\n"));
       yychar = yylex (&yylval, yyscanner);
     }
 
   if (yychar <= YYEOF)
     {
-      yychar = yytoken = YYEOF;
+      yychar = YYEOF;
+      yytoken = YYSYMBOL_YYEOF;
       YYDPRINTF ((stderr, "Now at end of input.\n"));
     }
+  else if (yychar == YYerror)
+    {
+      /* The scanner already issued an error message, process directly
+         to error recovery.  But do not keep the error token as
+         lookahead, it is too special and may lead us to an endless
+         loop in error recovery. */
+      yychar = YYUNDEF;
+      yytoken = YYSYMBOL_YYerror;
+      goto yyerrlab1;
+    }
   else
     {
       yytoken = YYTRANSLATE (yychar);
@@ -1266,14 +1386,13 @@ yybackup:
 
   /* Shift the lookahead token.  */
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-
   yystate = yyn;
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
   goto yynewstate;
 
 
@@ -1308,193 +1427,193 @@ yyreduce:
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-  case 2:
-#line 99 "cmCommandArgumentParser.y"
-    {
+  case 2: /* Start: GoalWithOptionalBackSlash  */
+#line 97 "cmCommandArgumentParser.y"
+                            {
     (yyval.str) = 0;
     yyGetParser->SetResult((yyvsp[0].str));
   }
-#line 1318 "cmCommandArgumentParser.cxx"
+#line 1437 "cmCommandArgumentParser.cxx"
     break;
 
-  case 3:
-#line 105 "cmCommandArgumentParser.y"
-    {
+  case 3: /* GoalWithOptionalBackSlash: Goal  */
+#line 103 "cmCommandArgumentParser.y"
+       {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1326 "cmCommandArgumentParser.cxx"
+#line 1445 "cmCommandArgumentParser.cxx"
     break;
 
-  case 4:
-#line 108 "cmCommandArgumentParser.y"
-    {
+  case 4: /* GoalWithOptionalBackSlash: Goal "\\"  */
+#line 106 "cmCommandArgumentParser.y"
+                  {
     (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
   }
-#line 1334 "cmCommandArgumentParser.cxx"
+#line 1453 "cmCommandArgumentParser.cxx"
     break;
 
-  case 5:
-#line 113 "cmCommandArgumentParser.y"
-    {
+  case 5: /* Goal: %empty  */
+#line 111 "cmCommandArgumentParser.y"
+  {
     (yyval.str) = 0;
   }
-#line 1342 "cmCommandArgumentParser.cxx"
+#line 1461 "cmCommandArgumentParser.cxx"
     break;
 
-  case 6:
-#line 116 "cmCommandArgumentParser.y"
-    {
+  case 6: /* Goal: String Goal  */
+#line 114 "cmCommandArgumentParser.y"
+              {
     (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
   }
-#line 1350 "cmCommandArgumentParser.cxx"
+#line 1469 "cmCommandArgumentParser.cxx"
     break;
 
-  case 7:
-#line 121 "cmCommandArgumentParser.y"
-    {
+  case 7: /* String: OuterText  */
+#line 119 "cmCommandArgumentParser.y"
+            {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1358 "cmCommandArgumentParser.cxx"
+#line 1477 "cmCommandArgumentParser.cxx"
     break;
 
-  case 8:
-#line 124 "cmCommandArgumentParser.y"
-    {
+  case 8: /* String: Variable  */
+#line 122 "cmCommandArgumentParser.y"
+           {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1366 "cmCommandArgumentParser.cxx"
+#line 1485 "cmCommandArgumentParser.cxx"
     break;
 
-  case 9:
-#line 129 "cmCommandArgumentParser.y"
-    {
+  case 9: /* OuterText: cal_NAME  */
+#line 127 "cmCommandArgumentParser.y"
+           {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1374 "cmCommandArgumentParser.cxx"
+#line 1493 "cmCommandArgumentParser.cxx"
     break;
 
-  case 10:
-#line 132 "cmCommandArgumentParser.y"
-    {
+  case 10: /* OuterText: "@"  */
+#line 130 "cmCommandArgumentParser.y"
+         {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1382 "cmCommandArgumentParser.cxx"
+#line 1501 "cmCommandArgumentParser.cxx"
     break;
 
-  case 11:
-#line 135 "cmCommandArgumentParser.y"
-    {
+  case 11: /* OuterText: "$"  */
+#line 133 "cmCommandArgumentParser.y"
+             {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1390 "cmCommandArgumentParser.cxx"
+#line 1509 "cmCommandArgumentParser.cxx"
     break;
 
-  case 12:
-#line 138 "cmCommandArgumentParser.y"
-    {
+  case 12: /* OuterText: "{"  */
+#line 136 "cmCommandArgumentParser.y"
+             {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1398 "cmCommandArgumentParser.cxx"
+#line 1517 "cmCommandArgumentParser.cxx"
     break;
 
-  case 13:
-#line 141 "cmCommandArgumentParser.y"
-    {
+  case 13: /* OuterText: "}"  */
+#line 139 "cmCommandArgumentParser.y"
+             {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1406 "cmCommandArgumentParser.cxx"
+#line 1525 "cmCommandArgumentParser.cxx"
     break;
 
-  case 14:
-#line 144 "cmCommandArgumentParser.y"
-    {
+  case 14: /* OuterText: cal_SYMBOL  */
+#line 142 "cmCommandArgumentParser.y"
+             {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1414 "cmCommandArgumentParser.cxx"
+#line 1533 "cmCommandArgumentParser.cxx"
     break;
 
-  case 15:
-#line 149 "cmCommandArgumentParser.y"
-    {
+  case 15: /* Variable: cal_ENVCURLY EnvVarName "}"  */
+#line 147 "cmCommandArgumentParser.y"
+                                     {
     (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str));
   }
-#line 1422 "cmCommandArgumentParser.cxx"
+#line 1541 "cmCommandArgumentParser.cxx"
     break;
 
-  case 16:
-#line 152 "cmCommandArgumentParser.y"
-    {
+  case 16: /* Variable: cal_NCURLY MultipleIds "}"  */
+#line 150 "cmCommandArgumentParser.y"
+                                    {
     (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str));
   }
-#line 1430 "cmCommandArgumentParser.cxx"
+#line 1549 "cmCommandArgumentParser.cxx"
     break;
 
-  case 17:
-#line 155 "cmCommandArgumentParser.y"
-    {
+  case 17: /* Variable: cal_DCURLY MultipleIds "}"  */
+#line 153 "cmCommandArgumentParser.y"
+                                    {
     (yyval.str) = yyGetParser->ExpandVariable((yyvsp[-1].str));
   }
-#line 1438 "cmCommandArgumentParser.cxx"
+#line 1557 "cmCommandArgumentParser.cxx"
     break;
 
-  case 18:
-#line 158 "cmCommandArgumentParser.y"
-    {
+  case 18: /* Variable: cal_ATNAME  */
+#line 156 "cmCommandArgumentParser.y"
+             {
     (yyval.str) = yyGetParser->ExpandVariableForAt((yyvsp[0].str));
   }
-#line 1446 "cmCommandArgumentParser.cxx"
+#line 1565 "cmCommandArgumentParser.cxx"
     break;
 
-  case 19:
-#line 163 "cmCommandArgumentParser.y"
-    {
+  case 19: /* EnvVarName: MultipleIds  */
+#line 161 "cmCommandArgumentParser.y"
+              {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1454 "cmCommandArgumentParser.cxx"
+#line 1573 "cmCommandArgumentParser.cxx"
     break;
 
-  case 20:
-#line 166 "cmCommandArgumentParser.y"
-    {
+  case 20: /* EnvVarName: cal_SYMBOL EnvVarName  */
+#line 164 "cmCommandArgumentParser.y"
+                        {
     (yyval.str) = (yyvsp[-1].str);
   }
-#line 1462 "cmCommandArgumentParser.cxx"
+#line 1581 "cmCommandArgumentParser.cxx"
     break;
 
-  case 21:
-#line 171 "cmCommandArgumentParser.y"
-    {
+  case 21: /* MultipleIds: %empty  */
+#line 169 "cmCommandArgumentParser.y"
+  {
     (yyval.str) = 0;
   }
-#line 1470 "cmCommandArgumentParser.cxx"
+#line 1589 "cmCommandArgumentParser.cxx"
     break;
 
-  case 22:
-#line 174 "cmCommandArgumentParser.y"
-    {
+  case 22: /* MultipleIds: ID MultipleIds  */
+#line 172 "cmCommandArgumentParser.y"
+                 {
     (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
   }
-#line 1478 "cmCommandArgumentParser.cxx"
+#line 1597 "cmCommandArgumentParser.cxx"
     break;
 
-  case 23:
-#line 179 "cmCommandArgumentParser.y"
-    {
+  case 23: /* ID: cal_NAME  */
+#line 177 "cmCommandArgumentParser.y"
+           {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1486 "cmCommandArgumentParser.cxx"
+#line 1605 "cmCommandArgumentParser.cxx"
     break;
 
-  case 24:
-#line 182 "cmCommandArgumentParser.y"
-    {
+  case 24: /* ID: Variable  */
+#line 180 "cmCommandArgumentParser.y"
+           {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1494 "cmCommandArgumentParser.cxx"
+#line 1613 "cmCommandArgumentParser.cxx"
     break;
 
 
-#line 1498 "cmCommandArgumentParser.cxx"
+#line 1617 "cmCommandArgumentParser.cxx"
 
       default: break;
     }
@@ -1509,11 +1628,10 @@ yyreduce:
      case of YYERROR or YYBACKUP, subsequent parser actions might lead
      to an incorrect destructor call or verbose syntax error message
      before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
   yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
 
   *++yyvsp = yyval;
 
@@ -1537,50 +1655,44 @@ yyreduce:
 yyerrlab:
   /* Make sure we have latest lookahead translation.  See comments at
      user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
+  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
       ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (yyscanner, YY_("syntax error"));
-#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
-                                        yyssp, yytoken)
       {
+        yypcontext_t yyctx
+          = {yyssp, yytoken};
         char const *yymsgp = YY_("syntax error");
         int yysyntax_error_status;
-        yysyntax_error_status = YYSYNTAX_ERROR;
+        yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
-        else if (yysyntax_error_status == 1)
+        else if (yysyntax_error_status == -1)
           {
             if (yymsg != yymsgbuf)
               YYSTACK_FREE (yymsg);
-            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
-            if (!yymsg)
+            yymsg = YY_CAST (char *,
+                             YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+            if (yymsg)
               {
-                yymsg = yymsgbuf;
-                yymsg_alloc = sizeof yymsgbuf;
-                yysyntax_error_status = 2;
+                yysyntax_error_status
+                  = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+                yymsgp = yymsg;
               }
             else
               {
-                yysyntax_error_status = YYSYNTAX_ERROR;
-                yymsgp = yymsg;
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = YYENOMEM;
               }
           }
         yyerror (yyscanner, yymsgp);
-        if (yysyntax_error_status == 2)
+        if (yysyntax_error_status == YYENOMEM)
           goto yyexhaustedlab;
       }
-# undef YYSYNTAX_ERROR
-#endif
     }
 
-
-
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
@@ -1600,7 +1712,6 @@ yyerrlab:
         }
     }
 
-#if 0
   /* Else will try to reuse lookahead token after shifting the error
      token.  */
   goto yyerrlab1;
@@ -1628,16 +1739,16 @@ yyerrorlab:
 | yyerrlab1 -- common code for both syntax error and YYERROR.  |
 `-------------------------------------------------------------*/
 yyerrlab1:
-#endif
   yyerrstatus = 3;      /* Each real token shifted decrements this.  */
 
+  /* Pop stack until we find a state that shifts the error token.  */
   for (;;)
     {
       yyn = yypact[yystate];
       if (!yypact_value_is_default (yyn))
         {
-          yyn += YYTERROR;
-          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+          yyn += YYSYMBOL_YYerror;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
             {
               yyn = yytable[yyn];
               if (0 < yyn)
@@ -1651,7 +1762,7 @@ yyerrlab1:
 
 
       yydestruct ("Error: popping",
-                  yystos[yystate], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -1663,7 +1774,7 @@ yyerrlab1:
 
 
   /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
 
   yystate = yyn;
   goto yynewstate;
@@ -1685,20 +1796,20 @@ yyabortlab:
   goto yyreturn;
 
 
-#if !defined yyoverflow || YYERROR_VERBOSE
+#if 1
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
   yyerror (yyscanner, YY_("memory exhausted"));
   yyresult = 2;
-  /* Fall through.  */
+  goto yyreturn;
 #endif
 
 
-/*-----------------------------------------------------.
-| yyreturn -- parsing is finished, return the result.  |
-`-----------------------------------------------------*/
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return.  |
+`-------------------------------------------------------*/
 yyreturn:
   if (yychar != YYEMPTY)
     {
@@ -1715,20 +1826,19 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                  yystos[*yyssp], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
   if (yyss != yyssa)
     YYSTACK_FREE (yyss);
 #endif
-#if YYERROR_VERBOSE
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
-#endif
   return yyresult;
 }
-#line 187 "cmCommandArgumentParser.y"
+
+#line 185 "cmCommandArgumentParser.y"
 
 /* End of grammar */
 
index 0c6aad5..2689415 100644 (file)
@@ -7,10 +7,7 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
-
-Modify cmCommandArgumentParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+  bison --name-prefix=cmCommandArgument_yy --defines=cmCommandArgumentParserTokens.h -ocmCommandArgumentParser.cxx cmCommandArgumentParser.y
 
 */
 
@@ -25,6 +22,7 @@ Modify cmCommandArgumentParser.cxx:
 # include <malloc.h>
 #endif
 
+#include <stdint.h>
 /* Make sure the parser uses standard memory allocation.  The default
    generated parser malloc/free declarations do not work on all
    platforms.  */
@@ -35,7 +33,6 @@ Modify cmCommandArgumentParser.cxx:
 /*-------------------------------------------------------------------------*/
 #include "cmCommandArgumentParserHelper.h" /* Interface to parser object.  */
 #include "cmCommandArgumentLexer.h"  /* Interface to lexer object.  */
-#include "cmCommandArgumentParserTokens.h" /* Need YYSTYPE for YY_DECL.  */
 
 /* Forward declare the lexer entry point.  */
 YY_DECL;
@@ -57,6 +54,7 @@ static void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message);
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
 #endif
 %}
 
index 033b899..578f793 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -31,8 +31,9 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
 
 #ifndef YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
 # define YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
 extern int cmCommandArgument_yydebug;
 #endif
 
-/* Token type.  */
+/* Token kinds.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
   enum yytokentype
   {
-    cal_ENVCURLY = 258,
-    cal_NCURLY = 259,
-    cal_DCURLY = 260,
-    cal_DOLLAR = 261,
-    cal_LCURLY = 262,
-    cal_RCURLY = 263,
-    cal_NAME = 264,
-    cal_BSLASH = 265,
-    cal_SYMBOL = 266,
-    cal_AT = 267,
-    cal_ERROR = 268,
-    cal_ATNAME = 269
+    YYEMPTY = -2,
+    YYEOF = 0,                     /* "end of file"  */
+    YYerror = 256,                 /* error  */
+    YYUNDEF = 257,                 /* "invalid token"  */
+    cal_ENVCURLY = 258,            /* cal_ENVCURLY  */
+    cal_NCURLY = 259,              /* cal_NCURLY  */
+    cal_DCURLY = 260,              /* cal_DCURLY  */
+    cal_DOLLAR = 261,              /* "$"  */
+    cal_LCURLY = 262,              /* "{"  */
+    cal_RCURLY = 263,              /* "}"  */
+    cal_NAME = 264,                /* cal_NAME  */
+    cal_BSLASH = 265,              /* "\\"  */
+    cal_SYMBOL = 266,              /* cal_SYMBOL  */
+    cal_AT = 267,                  /* "@"  */
+    cal_ERROR = 268,               /* cal_ERROR  */
+    cal_ATNAME = 269               /* cal_ATNAME  */
   };
+  typedef enum yytokentype yytoken_kind_t;
 #endif
-/* Tokens.  */
-#define cal_ENVCURLY 258
-#define cal_NCURLY 259
-#define cal_DCURLY 260
-#define cal_DOLLAR 261
-#define cal_LCURLY 262
-#define cal_RCURLY 263
-#define cal_NAME 264
-#define cal_BSLASH 265
-#define cal_SYMBOL 266
-#define cal_AT 267
-#define cal_ERROR 268
-#define cal_ATNAME 269
 
 /* Value type.  */
 
index b15082d..27cc177 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
 /* C LALR(1) parser skeleton written by Richard Stallman, by
    simplifying the original so-called "semantic" parser.  */
 
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
 /* All symbols defined below should begin with yy or YY, to avoid
    infringing on user name space.  This should be done even for local
    variables, as they might otherwise be expanded by user macros.
    define necessary library symbols; they are noted "INFRINGES ON
    USER NAME SPACE" below.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
+/* Identify Bison output, and Bison version.  */
+#define YYBISON 30704
 
-/* Bison version.  */
-#define YYBISON_VERSION "3.4.2"
+/* Bison version string.  */
+#define YYBISON_VERSION "3.7.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -70,7 +71,6 @@
 #define yydebug         cmDependsJava_yydebug
 #define yynerrs         cmDependsJava_yynerrs
 
-
 /* First part of user prologue.  */
 #line 1 "cmDependsJavaParser.y"
 
@@ -82,15 +82,13 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmDependsJava_yy --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx cmDependsJavaParser.y
-
-Modify cmDependsJavaParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+  bison --name-prefix=cmDependsJava_yy --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx cmDependsJavaParser.y
 
 */
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string>
@@ -100,7 +98,6 @@ Modify cmDependsJavaParser.cxx:
 /*-------------------------------------------------------------------------*/
 #include "cmDependsJavaParserHelper.h" /* Interface to parser object.  */
 #include "cmDependsJavaLexer.h"  /* Interface to lexer object.  */
-#include "cmDependsJavaParserTokens.h" /* Need YYSTYPE for YY_DECL.  */
 
 /* Forward declare the lexer entry point.  */
 YY_DECL;
@@ -121,10 +118,20 @@ static void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message);
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
 #endif
 
-#line 127 "cmDependsJavaParser.cxx"
+#line 125 "cmDependsJavaParser.cxx"
 
+# ifndef YY_CAST
+#  ifdef __cplusplus
+#   define YY_CAST(Type, Val) static_cast<Type> (Val)
+#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+#  else
+#   define YY_CAST(Type, Val) ((Type) (Val))
+#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+#  endif
+# endif
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -137,248 +144,278 @@ static void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message);
 #  endif
 # endif
 
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Use api.header.include to #include this header
-   instead of duplicating it here.  */
-#ifndef YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
-# define YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
-/* Debug traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int cmDependsJava_yydebug;
-#endif
+#include "cmDependsJavaParserTokens.h"
+/* Symbol kind.  */
+enum yysymbol_kind_t
+{
+  YYSYMBOL_YYEMPTY = -2,
+  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
+  YYSYMBOL_YYerror = 1,                    /* error  */
+  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
+  YYSYMBOL_jp_ABSTRACT = 3,                /* jp_ABSTRACT  */
+  YYSYMBOL_jp_ASSERT = 4,                  /* jp_ASSERT  */
+  YYSYMBOL_jp_BOOLEAN_TYPE = 5,            /* jp_BOOLEAN_TYPE  */
+  YYSYMBOL_jp_BREAK = 6,                   /* jp_BREAK  */
+  YYSYMBOL_jp_BYTE_TYPE = 7,               /* jp_BYTE_TYPE  */
+  YYSYMBOL_jp_CASE = 8,                    /* jp_CASE  */
+  YYSYMBOL_jp_CATCH = 9,                   /* jp_CATCH  */
+  YYSYMBOL_jp_CHAR_TYPE = 10,              /* jp_CHAR_TYPE  */
+  YYSYMBOL_jp_CLASS = 11,                  /* jp_CLASS  */
+  YYSYMBOL_jp_CONTINUE = 12,               /* jp_CONTINUE  */
+  YYSYMBOL_jp_DEFAULT = 13,                /* jp_DEFAULT  */
+  YYSYMBOL_jp_DO = 14,                     /* jp_DO  */
+  YYSYMBOL_jp_DOUBLE_TYPE = 15,            /* jp_DOUBLE_TYPE  */
+  YYSYMBOL_jp_ELSE = 16,                   /* jp_ELSE  */
+  YYSYMBOL_jp_EXTENDS = 17,                /* jp_EXTENDS  */
+  YYSYMBOL_jp_FINAL = 18,                  /* jp_FINAL  */
+  YYSYMBOL_jp_FINALLY = 19,                /* jp_FINALLY  */
+  YYSYMBOL_jp_FLOAT_TYPE = 20,             /* jp_FLOAT_TYPE  */
+  YYSYMBOL_jp_FOR = 21,                    /* jp_FOR  */
+  YYSYMBOL_jp_IF = 22,                     /* jp_IF  */
+  YYSYMBOL_jp_IMPLEMENTS = 23,             /* jp_IMPLEMENTS  */
+  YYSYMBOL_jp_IMPORT = 24,                 /* jp_IMPORT  */
+  YYSYMBOL_jp_INSTANCEOF = 25,             /* jp_INSTANCEOF  */
+  YYSYMBOL_jp_INT_TYPE = 26,               /* jp_INT_TYPE  */
+  YYSYMBOL_jp_INTERFACE = 27,              /* jp_INTERFACE  */
+  YYSYMBOL_jp_LONG_TYPE = 28,              /* jp_LONG_TYPE  */
+  YYSYMBOL_jp_NATIVE = 29,                 /* jp_NATIVE  */
+  YYSYMBOL_jp_NEW = 30,                    /* jp_NEW  */
+  YYSYMBOL_jp_PACKAGE = 31,                /* jp_PACKAGE  */
+  YYSYMBOL_jp_PRIVATE = 32,                /* jp_PRIVATE  */
+  YYSYMBOL_jp_PROTECTED = 33,              /* jp_PROTECTED  */
+  YYSYMBOL_jp_PUBLIC = 34,                 /* jp_PUBLIC  */
+  YYSYMBOL_jp_RETURN = 35,                 /* jp_RETURN  */
+  YYSYMBOL_jp_SHORT_TYPE = 36,             /* jp_SHORT_TYPE  */
+  YYSYMBOL_jp_STATIC = 37,                 /* jp_STATIC  */
+  YYSYMBOL_jp_STRICTFP = 38,               /* jp_STRICTFP  */
+  YYSYMBOL_jp_SUPER = 39,                  /* jp_SUPER  */
+  YYSYMBOL_jp_SWITCH = 40,                 /* jp_SWITCH  */
+  YYSYMBOL_jp_SYNCHRONIZED = 41,           /* jp_SYNCHRONIZED  */
+  YYSYMBOL_jp_THIS = 42,                   /* jp_THIS  */
+  YYSYMBOL_jp_THROW = 43,                  /* jp_THROW  */
+  YYSYMBOL_jp_THROWS = 44,                 /* jp_THROWS  */
+  YYSYMBOL_jp_TRANSIENT = 45,              /* jp_TRANSIENT  */
+  YYSYMBOL_jp_TRY = 46,                    /* jp_TRY  */
+  YYSYMBOL_jp_VOID = 47,                   /* jp_VOID  */
+  YYSYMBOL_jp_VOLATILE = 48,               /* jp_VOLATILE  */
+  YYSYMBOL_jp_WHILE = 49,                  /* jp_WHILE  */
+  YYSYMBOL_jp_BOOLEANLITERAL = 50,         /* jp_BOOLEANLITERAL  */
+  YYSYMBOL_jp_CHARACTERLITERAL = 51,       /* jp_CHARACTERLITERAL  */
+  YYSYMBOL_jp_DECIMALINTEGERLITERAL = 52,  /* jp_DECIMALINTEGERLITERAL  */
+  YYSYMBOL_jp_FLOATINGPOINTLITERAL = 53,   /* jp_FLOATINGPOINTLITERAL  */
+  YYSYMBOL_jp_HEXINTEGERLITERAL = 54,      /* jp_HEXINTEGERLITERAL  */
+  YYSYMBOL_jp_NULLLITERAL = 55,            /* jp_NULLLITERAL  */
+  YYSYMBOL_jp_STRINGLITERAL = 56,          /* jp_STRINGLITERAL  */
+  YYSYMBOL_jp_NAME = 57,                   /* jp_NAME  */
+  YYSYMBOL_jp_AND = 58,                    /* jp_AND  */
+  YYSYMBOL_jp_ANDAND = 59,                 /* jp_ANDAND  */
+  YYSYMBOL_jp_ANDEQUALS = 60,              /* jp_ANDEQUALS  */
+  YYSYMBOL_jp_BRACKETEND = 61,             /* jp_BRACKETEND  */
+  YYSYMBOL_jp_BRACKETSTART = 62,           /* jp_BRACKETSTART  */
+  YYSYMBOL_jp_CARROT = 63,                 /* jp_CARROT  */
+  YYSYMBOL_jp_CARROTEQUALS = 64,           /* jp_CARROTEQUALS  */
+  YYSYMBOL_jp_COLON = 65,                  /* jp_COLON  */
+  YYSYMBOL_jp_COMMA = 66,                  /* jp_COMMA  */
+  YYSYMBOL_jp_CURLYEND = 67,               /* jp_CURLYEND  */
+  YYSYMBOL_jp_CURLYSTART = 68,             /* jp_CURLYSTART  */
+  YYSYMBOL_jp_DIVIDE = 69,                 /* jp_DIVIDE  */
+  YYSYMBOL_jp_DIVIDEEQUALS = 70,           /* jp_DIVIDEEQUALS  */
+  YYSYMBOL_jp_DOLLAR = 71,                 /* jp_DOLLAR  */
+  YYSYMBOL_jp_DOT = 72,                    /* jp_DOT  */
+  YYSYMBOL_jp_EQUALS = 73,                 /* jp_EQUALS  */
+  YYSYMBOL_jp_EQUALSEQUALS = 74,           /* jp_EQUALSEQUALS  */
+  YYSYMBOL_jp_EXCLAMATION = 75,            /* jp_EXCLAMATION  */
+  YYSYMBOL_jp_EXCLAMATIONEQUALS = 76,      /* jp_EXCLAMATIONEQUALS  */
+  YYSYMBOL_jp_GREATER = 77,                /* jp_GREATER  */
+  YYSYMBOL_jp_GTEQUALS = 78,               /* jp_GTEQUALS  */
+  YYSYMBOL_jp_GTGT = 79,                   /* jp_GTGT  */
+  YYSYMBOL_jp_GTGTEQUALS = 80,             /* jp_GTGTEQUALS  */
+  YYSYMBOL_jp_GTGTGT = 81,                 /* jp_GTGTGT  */
+  YYSYMBOL_jp_GTGTGTEQUALS = 82,           /* jp_GTGTGTEQUALS  */
+  YYSYMBOL_jp_LESLESEQUALS = 83,           /* jp_LESLESEQUALS  */
+  YYSYMBOL_jp_LESSTHAN = 84,               /* jp_LESSTHAN  */
+  YYSYMBOL_jp_LTEQUALS = 85,               /* jp_LTEQUALS  */
+  YYSYMBOL_jp_LTLT = 86,                   /* jp_LTLT  */
+  YYSYMBOL_jp_MINUS = 87,                  /* jp_MINUS  */
+  YYSYMBOL_jp_MINUSEQUALS = 88,            /* jp_MINUSEQUALS  */
+  YYSYMBOL_jp_MINUSMINUS = 89,             /* jp_MINUSMINUS  */
+  YYSYMBOL_jp_PAREEND = 90,                /* jp_PAREEND  */
+  YYSYMBOL_jp_PARESTART = 91,              /* jp_PARESTART  */
+  YYSYMBOL_jp_PERCENT = 92,                /* jp_PERCENT  */
+  YYSYMBOL_jp_PERCENTEQUALS = 93,          /* jp_PERCENTEQUALS  */
+  YYSYMBOL_jp_PIPE = 94,                   /* jp_PIPE  */
+  YYSYMBOL_jp_PIPEEQUALS = 95,             /* jp_PIPEEQUALS  */
+  YYSYMBOL_jp_PIPEPIPE = 96,               /* jp_PIPEPIPE  */
+  YYSYMBOL_jp_PLUS = 97,                   /* jp_PLUS  */
+  YYSYMBOL_jp_PLUSEQUALS = 98,             /* jp_PLUSEQUALS  */
+  YYSYMBOL_jp_PLUSPLUS = 99,               /* jp_PLUSPLUS  */
+  YYSYMBOL_jp_QUESTION = 100,              /* jp_QUESTION  */
+  YYSYMBOL_jp_SEMICOL = 101,               /* jp_SEMICOL  */
+  YYSYMBOL_jp_TILDE = 102,                 /* jp_TILDE  */
+  YYSYMBOL_jp_TIMES = 103,                 /* jp_TIMES  */
+  YYSYMBOL_jp_TIMESEQUALS = 104,           /* jp_TIMESEQUALS  */
+  YYSYMBOL_jp_ERROR = 105,                 /* jp_ERROR  */
+  YYSYMBOL_YYACCEPT = 106,                 /* $accept  */
+  YYSYMBOL_Goal = 107,                     /* Goal  */
+  YYSYMBOL_Literal = 108,                  /* Literal  */
+  YYSYMBOL_IntegerLiteral = 109,           /* IntegerLiteral  */
+  YYSYMBOL_Type = 110,                     /* Type  */
+  YYSYMBOL_PrimitiveType = 111,            /* PrimitiveType  */
+  YYSYMBOL_ReferenceType = 112,            /* ReferenceType  */
+  YYSYMBOL_ClassOrInterfaceType = 113,     /* ClassOrInterfaceType  */
+  YYSYMBOL_ClassType = 114,                /* ClassType  */
+  YYSYMBOL_InterfaceType = 115,            /* InterfaceType  */
+  YYSYMBOL_ArrayType = 116,                /* ArrayType  */
+  YYSYMBOL_Name = 117,                     /* Name  */
+  YYSYMBOL_SimpleName = 118,               /* SimpleName  */
+  YYSYMBOL_Identifier = 119,               /* Identifier  */
+  YYSYMBOL_QualifiedName = 120,            /* QualifiedName  */
+  YYSYMBOL_SimpleType = 121,               /* SimpleType  */
+  YYSYMBOL_CompilationUnit = 122,          /* CompilationUnit  */
+  YYSYMBOL_PackageDeclarationopt = 123,    /* PackageDeclarationopt  */
+  YYSYMBOL_ImportDeclarations = 124,       /* ImportDeclarations  */
+  YYSYMBOL_TypeDeclarations = 125,         /* TypeDeclarations  */
+  YYSYMBOL_PackageDeclaration = 126,       /* PackageDeclaration  */
+  YYSYMBOL_ImportDeclaration = 127,        /* ImportDeclaration  */
+  YYSYMBOL_SingleTypeImportDeclaration = 128, /* SingleTypeImportDeclaration  */
+  YYSYMBOL_TypeImportOnDemandDeclaration = 129, /* TypeImportOnDemandDeclaration  */
+  YYSYMBOL_TypeDeclaration = 130,          /* TypeDeclaration  */
+  YYSYMBOL_Modifiers = 131,                /* Modifiers  */
+  YYSYMBOL_Modifier = 132,                 /* Modifier  */
+  YYSYMBOL_ClassHeader = 133,              /* ClassHeader  */
+  YYSYMBOL_ClassDeclaration = 134,         /* ClassDeclaration  */
+  YYSYMBOL_Modifiersopt = 135,             /* Modifiersopt  */
+  YYSYMBOL_Super = 136,                    /* Super  */
+  YYSYMBOL_Interfaces = 137,               /* Interfaces  */
+  YYSYMBOL_InterfaceTypeList = 138,        /* InterfaceTypeList  */
+  YYSYMBOL_ClassBody = 139,                /* ClassBody  */
+  YYSYMBOL_ClassBodyDeclarations = 140,    /* ClassBodyDeclarations  */
+  YYSYMBOL_ClassBodyDeclaration = 141,     /* ClassBodyDeclaration  */
+  YYSYMBOL_ClassMemberDeclaration = 142,   /* ClassMemberDeclaration  */
+  YYSYMBOL_FieldDeclaration = 143,         /* FieldDeclaration  */
+  YYSYMBOL_VariableDeclarators = 144,      /* VariableDeclarators  */
+  YYSYMBOL_VariableDeclarator = 145,       /* VariableDeclarator  */
+  YYSYMBOL_VariableDeclaratorId = 146,     /* VariableDeclaratorId  */
+  YYSYMBOL_VariableInitializer = 147,      /* VariableInitializer  */
+  YYSYMBOL_MethodDeclaration = 148,        /* MethodDeclaration  */
+  YYSYMBOL_MethodHeader = 149,             /* MethodHeader  */
+  YYSYMBOL_Throwsopt = 150,                /* Throwsopt  */
+  YYSYMBOL_MethodDeclarator = 151,         /* MethodDeclarator  */
+  YYSYMBOL_FormalParameterListopt = 152,   /* FormalParameterListopt  */
+  YYSYMBOL_FormalParameterList = 153,      /* FormalParameterList  */
+  YYSYMBOL_FormalParameter = 154,          /* FormalParameter  */
+  YYSYMBOL_Throws = 155,                   /* Throws  */
+  YYSYMBOL_ClassTypeList = 156,            /* ClassTypeList  */
+  YYSYMBOL_MethodBody = 157,               /* MethodBody  */
+  YYSYMBOL_StaticInitializer = 158,        /* StaticInitializer  */
+  YYSYMBOL_ConstructorDeclaration = 159,   /* ConstructorDeclaration  */
+  YYSYMBOL_ConstructorDeclarator = 160,    /* ConstructorDeclarator  */
+  YYSYMBOL_ConstructorBody = 161,          /* ConstructorBody  */
+  YYSYMBOL_ExplicitConstructorInvocationopt = 162, /* ExplicitConstructorInvocationopt  */
+  YYSYMBOL_ExplicitConstructorInvocation = 163, /* ExplicitConstructorInvocation  */
+  YYSYMBOL_InterfaceHeader = 164,          /* InterfaceHeader  */
+  YYSYMBOL_InterfaceDeclaration = 165,     /* InterfaceDeclaration  */
+  YYSYMBOL_ExtendsInterfacesopt = 166,     /* ExtendsInterfacesopt  */
+  YYSYMBOL_ExtendsInterfaces = 167,        /* ExtendsInterfaces  */
+  YYSYMBOL_InterfaceBody = 168,            /* InterfaceBody  */
+  YYSYMBOL_InterfaceMemberDeclarations = 169, /* InterfaceMemberDeclarations  */
+  YYSYMBOL_InterfaceMemberDeclaration = 170, /* InterfaceMemberDeclaration  */
+  YYSYMBOL_ConstantDeclaration = 171,      /* ConstantDeclaration  */
+  YYSYMBOL_AbstractMethodDeclaration = 172, /* AbstractMethodDeclaration  */
+  YYSYMBOL_Semicols = 173,                 /* Semicols  */
+  YYSYMBOL_ArrayInitializer = 174,         /* ArrayInitializer  */
+  YYSYMBOL_VariableInitializersOptional = 175, /* VariableInitializersOptional  */
+  YYSYMBOL_VariableInitializers = 176,     /* VariableInitializers  */
+  YYSYMBOL_Block = 177,                    /* Block  */
+  YYSYMBOL_BlockStatementsopt = 178,       /* BlockStatementsopt  */
+  YYSYMBOL_BlockStatements = 179,          /* BlockStatements  */
+  YYSYMBOL_BlockStatement = 180,           /* BlockStatement  */
+  YYSYMBOL_LocalVariableDeclarationStatement = 181, /* LocalVariableDeclarationStatement  */
+  YYSYMBOL_LocalVariableDeclaration = 182, /* LocalVariableDeclaration  */
+  YYSYMBOL_Statement = 183,                /* Statement  */
+  YYSYMBOL_StatementNoShortIf = 184,       /* StatementNoShortIf  */
+  YYSYMBOL_StatementWithoutTrailingSubstatement = 185, /* StatementWithoutTrailingSubstatement  */
+  YYSYMBOL_EmptyStatement = 186,           /* EmptyStatement  */
+  YYSYMBOL_LabeledStatement = 187,         /* LabeledStatement  */
+  YYSYMBOL_LabeledStatementNoShortIf = 188, /* LabeledStatementNoShortIf  */
+  YYSYMBOL_ExpressionStatement = 189,      /* ExpressionStatement  */
+  YYSYMBOL_StatementExpression = 190,      /* StatementExpression  */
+  YYSYMBOL_IfThenStatement = 191,          /* IfThenStatement  */
+  YYSYMBOL_IfThenElseStatement = 192,      /* IfThenElseStatement  */
+  YYSYMBOL_IfThenElseStatementNoShortIf = 193, /* IfThenElseStatementNoShortIf  */
+  YYSYMBOL_SwitchStatement = 194,          /* SwitchStatement  */
+  YYSYMBOL_SwitchBlock = 195,              /* SwitchBlock  */
+  YYSYMBOL_SwitchLabelsopt = 196,          /* SwitchLabelsopt  */
+  YYSYMBOL_SwitchBlockStatementGroups = 197, /* SwitchBlockStatementGroups  */
+  YYSYMBOL_SwitchBlockStatementGroup = 198, /* SwitchBlockStatementGroup  */
+  YYSYMBOL_SwitchLabels = 199,             /* SwitchLabels  */
+  YYSYMBOL_SwitchLabel = 200,              /* SwitchLabel  */
+  YYSYMBOL_WhileStatement = 201,           /* WhileStatement  */
+  YYSYMBOL_WhileStatementNoShortIf = 202,  /* WhileStatementNoShortIf  */
+  YYSYMBOL_DoStatement = 203,              /* DoStatement  */
+  YYSYMBOL_ForStatement = 204,             /* ForStatement  */
+  YYSYMBOL_ForUpdateopt = 205,             /* ForUpdateopt  */
+  YYSYMBOL_ForInitopt = 206,               /* ForInitopt  */
+  YYSYMBOL_ForStatementNoShortIf = 207,    /* ForStatementNoShortIf  */
+  YYSYMBOL_Expressionopt = 208,            /* Expressionopt  */
+  YYSYMBOL_ForInit = 209,                  /* ForInit  */
+  YYSYMBOL_ForUpdate = 210,                /* ForUpdate  */
+  YYSYMBOL_StatementExpressionList = 211,  /* StatementExpressionList  */
+  YYSYMBOL_AssertStatement = 212,          /* AssertStatement  */
+  YYSYMBOL_BreakStatement = 213,           /* BreakStatement  */
+  YYSYMBOL_Identifieropt = 214,            /* Identifieropt  */
+  YYSYMBOL_ContinueStatement = 215,        /* ContinueStatement  */
+  YYSYMBOL_ReturnStatement = 216,          /* ReturnStatement  */
+  YYSYMBOL_ThrowStatement = 217,           /* ThrowStatement  */
+  YYSYMBOL_SynchronizedStatement = 218,    /* SynchronizedStatement  */
+  YYSYMBOL_TryStatement = 219,             /* TryStatement  */
+  YYSYMBOL_Catchesopt = 220,               /* Catchesopt  */
+  YYSYMBOL_Catches = 221,                  /* Catches  */
+  YYSYMBOL_CatchClause = 222,              /* CatchClause  */
+  YYSYMBOL_Finally = 223,                  /* Finally  */
+  YYSYMBOL_Primary = 224,                  /* Primary  */
+  YYSYMBOL_PrimaryNoNewArray = 225,        /* PrimaryNoNewArray  */
+  YYSYMBOL_ClassInstanceCreationExpression = 226, /* ClassInstanceCreationExpression  */
+  YYSYMBOL_ClassBodyOpt = 227,             /* ClassBodyOpt  */
+  YYSYMBOL_ArgumentListopt = 228,          /* ArgumentListopt  */
+  YYSYMBOL_ArgumentList = 229,             /* ArgumentList  */
+  YYSYMBOL_ArrayCreationExpression = 230,  /* ArrayCreationExpression  */
+  YYSYMBOL_Dimsopt = 231,                  /* Dimsopt  */
+  YYSYMBOL_DimExprs = 232,                 /* DimExprs  */
+  YYSYMBOL_DimExpr = 233,                  /* DimExpr  */
+  YYSYMBOL_Dims = 234,                     /* Dims  */
+  YYSYMBOL_FieldAccess = 235,              /* FieldAccess  */
+  YYSYMBOL_MethodInvocation = 236,         /* MethodInvocation  */
+  YYSYMBOL_ArrayAccess = 237,              /* ArrayAccess  */
+  YYSYMBOL_PostfixExpression = 238,        /* PostfixExpression  */
+  YYSYMBOL_PostIncrementExpression = 239,  /* PostIncrementExpression  */
+  YYSYMBOL_PostDecrementExpression = 240,  /* PostDecrementExpression  */
+  YYSYMBOL_UnaryExpression = 241,          /* UnaryExpression  */
+  YYSYMBOL_PreIncrementExpression = 242,   /* PreIncrementExpression  */
+  YYSYMBOL_PreDecrementExpression = 243,   /* PreDecrementExpression  */
+  YYSYMBOL_UnaryExpressionNotPlusMinus = 244, /* UnaryExpressionNotPlusMinus  */
+  YYSYMBOL_CastExpression = 245,           /* CastExpression  */
+  YYSYMBOL_MultiplicativeExpression = 246, /* MultiplicativeExpression  */
+  YYSYMBOL_AdditiveExpression = 247,       /* AdditiveExpression  */
+  YYSYMBOL_ShiftExpression = 248,          /* ShiftExpression  */
+  YYSYMBOL_RelationalExpression = 249,     /* RelationalExpression  */
+  YYSYMBOL_EqualityExpression = 250,       /* EqualityExpression  */
+  YYSYMBOL_AndExpression = 251,            /* AndExpression  */
+  YYSYMBOL_ExclusiveOrExpression = 252,    /* ExclusiveOrExpression  */
+  YYSYMBOL_InclusiveOrExpression = 253,    /* InclusiveOrExpression  */
+  YYSYMBOL_ConditionalAndExpression = 254, /* ConditionalAndExpression  */
+  YYSYMBOL_ConditionalOrExpression = 255,  /* ConditionalOrExpression  */
+  YYSYMBOL_ConditionalExpression = 256,    /* ConditionalExpression  */
+  YYSYMBOL_AssignmentExpression = 257,     /* AssignmentExpression  */
+  YYSYMBOL_Assignment = 258,               /* Assignment  */
+  YYSYMBOL_LeftHandSide = 259,             /* LeftHandSide  */
+  YYSYMBOL_AssignmentOperator = 260,       /* AssignmentOperator  */
+  YYSYMBOL_Expression = 261,               /* Expression  */
+  YYSYMBOL_ConstantExpression = 262,       /* ConstantExpression  */
+  YYSYMBOL_New = 263                       /* New  */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
 
-/* Token type.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-  enum yytokentype
-  {
-    jp_ABSTRACT = 258,
-    jp_ASSERT = 259,
-    jp_BOOLEAN_TYPE = 260,
-    jp_BREAK = 261,
-    jp_BYTE_TYPE = 262,
-    jp_CASE = 263,
-    jp_CATCH = 264,
-    jp_CHAR_TYPE = 265,
-    jp_CLASS = 266,
-    jp_CONTINUE = 267,
-    jp_DEFAULT = 268,
-    jp_DO = 269,
-    jp_DOUBLE_TYPE = 270,
-    jp_ELSE = 271,
-    jp_EXTENDS = 272,
-    jp_FINAL = 273,
-    jp_FINALLY = 274,
-    jp_FLOAT_TYPE = 275,
-    jp_FOR = 276,
-    jp_IF = 277,
-    jp_IMPLEMENTS = 278,
-    jp_IMPORT = 279,
-    jp_INSTANCEOF = 280,
-    jp_INT_TYPE = 281,
-    jp_INTERFACE = 282,
-    jp_LONG_TYPE = 283,
-    jp_NATIVE = 284,
-    jp_NEW = 285,
-    jp_PACKAGE = 286,
-    jp_PRIVATE = 287,
-    jp_PROTECTED = 288,
-    jp_PUBLIC = 289,
-    jp_RETURN = 290,
-    jp_SHORT_TYPE = 291,
-    jp_STATIC = 292,
-    jp_STRICTFP = 293,
-    jp_SUPER = 294,
-    jp_SWITCH = 295,
-    jp_SYNCHRONIZED = 296,
-    jp_THIS = 297,
-    jp_THROW = 298,
-    jp_THROWS = 299,
-    jp_TRANSIENT = 300,
-    jp_TRY = 301,
-    jp_VOID = 302,
-    jp_VOLATILE = 303,
-    jp_WHILE = 304,
-    jp_BOOLEANLITERAL = 305,
-    jp_CHARACTERLITERAL = 306,
-    jp_DECIMALINTEGERLITERAL = 307,
-    jp_FLOATINGPOINTLITERAL = 308,
-    jp_HEXINTEGERLITERAL = 309,
-    jp_NULLLITERAL = 310,
-    jp_STRINGLITERAL = 311,
-    jp_NAME = 312,
-    jp_AND = 313,
-    jp_ANDAND = 314,
-    jp_ANDEQUALS = 315,
-    jp_BRACKETEND = 316,
-    jp_BRACKETSTART = 317,
-    jp_CARROT = 318,
-    jp_CARROTEQUALS = 319,
-    jp_COLON = 320,
-    jp_COMMA = 321,
-    jp_CURLYEND = 322,
-    jp_CURLYSTART = 323,
-    jp_DIVIDE = 324,
-    jp_DIVIDEEQUALS = 325,
-    jp_DOLLAR = 326,
-    jp_DOT = 327,
-    jp_EQUALS = 328,
-    jp_EQUALSEQUALS = 329,
-    jp_EXCLAMATION = 330,
-    jp_EXCLAMATIONEQUALS = 331,
-    jp_GREATER = 332,
-    jp_GTEQUALS = 333,
-    jp_GTGT = 334,
-    jp_GTGTEQUALS = 335,
-    jp_GTGTGT = 336,
-    jp_GTGTGTEQUALS = 337,
-    jp_LESLESEQUALS = 338,
-    jp_LESSTHAN = 339,
-    jp_LTEQUALS = 340,
-    jp_LTLT = 341,
-    jp_MINUS = 342,
-    jp_MINUSEQUALS = 343,
-    jp_MINUSMINUS = 344,
-    jp_PAREEND = 345,
-    jp_PARESTART = 346,
-    jp_PERCENT = 347,
-    jp_PERCENTEQUALS = 348,
-    jp_PIPE = 349,
-    jp_PIPEEQUALS = 350,
-    jp_PIPEPIPE = 351,
-    jp_PLUS = 352,
-    jp_PLUSEQUALS = 353,
-    jp_PLUSPLUS = 354,
-    jp_QUESTION = 355,
-    jp_SEMICOL = 356,
-    jp_TILDE = 357,
-    jp_TIMES = 358,
-    jp_TIMESEQUALS = 359,
-    jp_ERROR = 360
-  };
-#endif
-/* Tokens.  */
-#define jp_ABSTRACT 258
-#define jp_ASSERT 259
-#define jp_BOOLEAN_TYPE 260
-#define jp_BREAK 261
-#define jp_BYTE_TYPE 262
-#define jp_CASE 263
-#define jp_CATCH 264
-#define jp_CHAR_TYPE 265
-#define jp_CLASS 266
-#define jp_CONTINUE 267
-#define jp_DEFAULT 268
-#define jp_DO 269
-#define jp_DOUBLE_TYPE 270
-#define jp_ELSE 271
-#define jp_EXTENDS 272
-#define jp_FINAL 273
-#define jp_FINALLY 274
-#define jp_FLOAT_TYPE 275
-#define jp_FOR 276
-#define jp_IF 277
-#define jp_IMPLEMENTS 278
-#define jp_IMPORT 279
-#define jp_INSTANCEOF 280
-#define jp_INT_TYPE 281
-#define jp_INTERFACE 282
-#define jp_LONG_TYPE 283
-#define jp_NATIVE 284
-#define jp_NEW 285
-#define jp_PACKAGE 286
-#define jp_PRIVATE 287
-#define jp_PROTECTED 288
-#define jp_PUBLIC 289
-#define jp_RETURN 290
-#define jp_SHORT_TYPE 291
-#define jp_STATIC 292
-#define jp_STRICTFP 293
-#define jp_SUPER 294
-#define jp_SWITCH 295
-#define jp_SYNCHRONIZED 296
-#define jp_THIS 297
-#define jp_THROW 298
-#define jp_THROWS 299
-#define jp_TRANSIENT 300
-#define jp_TRY 301
-#define jp_VOID 302
-#define jp_VOLATILE 303
-#define jp_WHILE 304
-#define jp_BOOLEANLITERAL 305
-#define jp_CHARACTERLITERAL 306
-#define jp_DECIMALINTEGERLITERAL 307
-#define jp_FLOATINGPOINTLITERAL 308
-#define jp_HEXINTEGERLITERAL 309
-#define jp_NULLLITERAL 310
-#define jp_STRINGLITERAL 311
-#define jp_NAME 312
-#define jp_AND 313
-#define jp_ANDAND 314
-#define jp_ANDEQUALS 315
-#define jp_BRACKETEND 316
-#define jp_BRACKETSTART 317
-#define jp_CARROT 318
-#define jp_CARROTEQUALS 319
-#define jp_COLON 320
-#define jp_COMMA 321
-#define jp_CURLYEND 322
-#define jp_CURLYSTART 323
-#define jp_DIVIDE 324
-#define jp_DIVIDEEQUALS 325
-#define jp_DOLLAR 326
-#define jp_DOT 327
-#define jp_EQUALS 328
-#define jp_EQUALSEQUALS 329
-#define jp_EXCLAMATION 330
-#define jp_EXCLAMATIONEQUALS 331
-#define jp_GREATER 332
-#define jp_GTEQUALS 333
-#define jp_GTGT 334
-#define jp_GTGTEQUALS 335
-#define jp_GTGTGT 336
-#define jp_GTGTGTEQUALS 337
-#define jp_LESLESEQUALS 338
-#define jp_LESSTHAN 339
-#define jp_LTEQUALS 340
-#define jp_LTLT 341
-#define jp_MINUS 342
-#define jp_MINUSEQUALS 343
-#define jp_MINUSMINUS 344
-#define jp_PAREEND 345
-#define jp_PARESTART 346
-#define jp_PERCENT 347
-#define jp_PERCENTEQUALS 348
-#define jp_PIPE 349
-#define jp_PIPEEQUALS 350
-#define jp_PIPEPIPE 351
-#define jp_PLUS 352
-#define jp_PLUSEQUALS 353
-#define jp_PLUSPLUS 354
-#define jp_QUESTION 355
-#define jp_SEMICOL 356
-#define jp_TILDE 357
-#define jp_TIMES 358
-#define jp_TIMESEQUALS 359
-#define jp_ERROR 360
-
-/* Value type.  */
-
-
-
-int cmDependsJava_yyparse (yyscan_t yyscanner);
-
-#endif /* !YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED  */
 
 
 
@@ -386,28 +423,75 @@ int cmDependsJava_yyparse (yyscan_t yyscanner);
 # undef short
 #endif
 
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+   <limits.h> and (if available) <stdint.h> are included
+   so that the code can choose integer types of a good width.  */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+#  define YY_STDINT_H
+# endif
 #endif
 
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
+/* Narrow types that promote to a signed type and that can represent a
+   signed or unsigned integer of at least N bits.  In tables they can
+   save space and decrease cache pressure.  Promoting to a signed type
+   helps avoid bugs in integer arithmetic.  */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
 #else
 typedef signed char yytype_int8;
 #endif
 
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
 #else
-typedef unsigned short yytype_uint16;
+typedef short yytype_int16;
 #endif
 
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
 #else
-typedef short yytype_int16;
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+#  define YYPTRDIFF_T __PTRDIFF_TYPE__
+#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+#  ifndef ptrdiff_t
+#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  endif
+#  define YYPTRDIFF_T ptrdiff_t
+#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+#  define YYPTRDIFF_T long
+#  define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
 #endif
 
 #ifndef YYSIZE_T
@@ -415,7 +499,7 @@ typedef short yytype_int16;
 #  define YYSIZE_T __SIZE_TYPE__
 # elif defined size_t
 #  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
 #  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
 #  define YYSIZE_T size_t
 # else
@@ -423,7 +507,20 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+#define YYSIZE_MAXIMUM                                  \
+  YY_CAST (YYPTRDIFF_T,                                 \
+           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
+            ? YYPTRDIFF_MAXIMUM                         \
+            : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int16 yy_state_t;
+
+/* State numbers in computations.  */
+typedef int yy_state_fast_t;
 
 #ifndef YY_
 # if defined YYENABLE_NLS && YYENABLE_NLS
@@ -437,22 +534,21 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#ifndef YY_ATTRIBUTE
-# if (defined __GNUC__                                               \
-      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
-     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
-#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
-# else
-#  define YY_ATTRIBUTE(Spec) /* empty */
-# endif
-#endif
 
 #ifndef YY_ATTRIBUTE_PURE
-# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define YY_ATTRIBUTE_PURE
+# endif
 #endif
 
 #ifndef YY_ATTRIBUTE_UNUSED
-# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+#  define YY_ATTRIBUTE_UNUSED
+# endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
@@ -464,11 +560,11 @@ typedef short yytype_int16;
 
 #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
 /* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
-    _Pragma ("GCC diagnostic push") \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                            \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
     _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
     _Pragma ("GCC diagnostic pop")
 #else
 # define YY_INITIAL_VALUE(Value) Value
@@ -481,10 +577,22 @@ typedef short yytype_int16;
 # define YY_INITIAL_VALUE(Value) /* Nothing. */
 #endif
 
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN                          \
+    _Pragma ("GCC diagnostic push")                            \
+    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END            \
+    _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
 
 #define YY_ASSERT(E) ((void) (0 && (E)))
 
-#if ! defined yyoverflow || YYERROR_VERBOSE
+#if 1
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
@@ -549,8 +657,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 # endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
+#endif /* 1 */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus \
@@ -559,17 +666,17 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  yytype_int16 yyss_alloc;
+  yy_state_t yyss_alloc;
   YYSTYPE yyvs_alloc;
 };
 
 /* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
 
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
       + YYSTACK_GAP_MAXIMUM)
 
 # define YYCOPY_NEEDED 1
@@ -582,11 +689,11 @@ union yyalloc
 # define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
     do                                                                  \
       {                                                                 \
-        YYSIZE_T yynewbytes;                                            \
+        YYPTRDIFF_T yynewbytes;                                         \
         YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
         Stack = &yyptr->Stack_alloc;                                    \
-        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-        yyptr += yynewbytes / sizeof (*yyptr);                          \
+        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
       }                                                                 \
     while (0)
 
@@ -598,12 +705,12 @@ union yyalloc
 # ifndef YYCOPY
 #  if defined __GNUC__ && 1 < __GNUC__
 #   define YYCOPY(Dst, Src, Count) \
-      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
 #  else
 #   define YYCOPY(Dst, Src, Count)              \
       do                                        \
         {                                       \
-          YYSIZE_T yyi;                         \
+          YYPTRDIFF_T yyi;                      \
           for (yyi = 0; yyi < (Count); yyi++)   \
             (Dst)[yyi] = (Src)[yyi];            \
         }                                       \
@@ -626,17 +733,20 @@ union yyalloc
 /* YYNSTATES -- Number of states.  */
 #define YYNSTATES  575
 
-#define YYUNDEFTOK  2
+/* YYMAXUTOK -- Last valid token kind.  */
 #define YYMAXUTOK   360
 
+
 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex, with out-of-bounds checking.  */
-#define YYTRANSLATE(YYX)                                                \
-  ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+#define YYTRANSLATE(YYX)                                \
+  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
+   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
+   : YYSYMBOL_YYUNDEF)
 
 /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex.  */
-static const yytype_uint8 yytranslate[] =
+static const yytype_int8 yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -679,63 +789,70 @@ static const yytype_uint8 yytranslate[] =
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
-static const yytype_uint16 yyrline[] =
-{
-       0,   182,   182,   191,   199,   207,   215,   223,   231,   240,
-     248,   257,   265,   274,   279,   284,   289,   294,   299,   304,
-     309,   315,   323,   332,   342,   351,   360,   368,   378,   384,
-     391,   398,   404,   411,   420,   430,   440,   449,   457,   466,
-     475,   481,   490,   496,   505,   511,   520,   532,   540,   549,
-     561,   574,   582,   590,   599,   607,   616,   616,   616,   617,
-     618,   618,   618,   618,   618,   618,   619,   622,   632,   641,
-     650,   659,   669,   675,   684,   693,   702,   710,   719,   728,
-     734,   743,   751,   759,   767,   776,   784,   793,   799,   807,
-     816,   824,   833,   842,   851,   859,   868,   876,   884,   893,
-     902,   912,   919,   929,   939,   946,   953,   956,   962,   972,
-     982,   992,   998,  1008,  1018,  1028,  1037,  1047,  1058,  1068,
-    1075,  1085,  1094,  1104,  1113,  1123,  1129,  1139,  1148,  1158,
-    1168,  1175,  1184,  1193,  1202,  1211,  1219,  1228,  1237,  1247,
-    1257,  1266,  1276,  1286,  1293,  1302,  1312,  1321,  1331,  1340,
-    1347,  1357,  1366,  1376,  1385,  1394,  1404,  1414,  1423,  1433,
-    1442,  1451,  1460,  1469,  1478,  1488,  1497,  1506,  1515,  1524,
-    1534,  1543,  1552,  1561,  1570,  1579,  1588,  1597,  1606,  1615,
-    1624,  1633,  1643,  1653,  1664,  1674,  1684,  1693,  1702,  1711,
-    1720,  1729,  1738,  1748,  1758,  1768,  1778,  1785,  1792,  1799,
-    1809,  1816,  1826,  1836,  1845,  1855,  1864,  1874,  1881,  1888,
-    1895,  1903,  1910,  1920,  1927,  1937,  1947,  1954,  1964,  1973,
-    1983,  1993,  2002,  2012,  2021,  2031,  2042,  2049,  2056,  2067,
-    2077,  2087,  2097,  2106,  2116,  2123,  2133,  2142,  2152,  2159,
-    2169,  2178,  2188,  2197,  2203,  2212,  2221,  2230,  2239,  2249,
-    2259,  2266,  2276,  2283,  2293,  2302,  2312,  2321,  2330,  2339,
-    2349,  2356,  2366,  2375,  2385,  2395,  2401,  2408,  2418,  2428,
-    2438,  2449,  2459,  2470,  2480,  2491,  2501,  2511,  2520,  2529,
-    2538,  2547,  2557,  2567,  2577,  2586,  2595,  2604,  2613,  2623,
-    2633,  2643,  2652,  2661,  2670,  2680,  2689,  2698,  2705,  2714,
-    2723,  2732,  2742,  2751,  2760,  2770,  2779,  2788,  2797,  2807,
-    2816,  2825,  2834,  2843,  2852,  2862,  2871,  2880,  2890,  2899,
-    2909,  2918,  2928,  2937,  2947,  2956,  2966,  2975,  2985,  2994,
-    3004,  3013,  3023,  3033,  3043,  3052,  3062,  3071,  3080,  3089,
-    3098,  3107,  3116,  3125,  3134,  3143,  3152,  3161,  3171,  3181,
-    3191,  3200
+static const yytype_int16 yyrline[] =
+{
+       0,   180,   180,   189,   197,   205,   213,   221,   229,   238,
+     246,   255,   263,   272,   277,   282,   287,   292,   297,   302,
+     307,   313,   321,   330,   340,   349,   358,   366,   376,   382,
+     389,   396,   402,   409,   418,   428,   438,   447,   455,   464,
+     473,   479,   488,   494,   503,   509,   518,   530,   538,   547,
+     559,   572,   580,   588,   597,   605,   614,   614,   614,   615,
+     616,   616,   616,   616,   616,   616,   617,   620,   630,   639,
+     648,   657,   667,   673,   682,   691,   700,   708,   717,   726,
+     732,   741,   749,   757,   765,   774,   782,   791,   797,   805,
+     814,   822,   831,   840,   849,   857,   866,   874,   882,   891,
+     900,   910,   917,   927,   937,   944,   951,   954,   960,   970,
+     980,   990,   996,  1006,  1016,  1026,  1035,  1045,  1056,  1066,
+    1073,  1083,  1092,  1102,  1111,  1121,  1127,  1137,  1146,  1156,
+    1166,  1173,  1182,  1191,  1200,  1209,  1217,  1226,  1235,  1245,
+    1255,  1264,  1274,  1284,  1291,  1300,  1310,  1319,  1329,  1338,
+    1345,  1355,  1364,  1374,  1383,  1392,  1402,  1412,  1421,  1431,
+    1440,  1449,  1458,  1467,  1476,  1486,  1495,  1504,  1513,  1522,
+    1532,  1541,  1550,  1559,  1568,  1577,  1586,  1595,  1604,  1613,
+    1622,  1631,  1641,  1651,  1662,  1672,  1682,  1691,  1700,  1709,
+    1718,  1727,  1736,  1746,  1756,  1766,  1776,  1783,  1790,  1797,
+    1807,  1814,  1824,  1834,  1843,  1853,  1862,  1872,  1879,  1886,
+    1893,  1901,  1908,  1918,  1925,  1935,  1945,  1952,  1962,  1971,
+    1981,  1991,  2000,  2010,  2019,  2029,  2040,  2047,  2054,  2065,
+    2075,  2085,  2095,  2104,  2114,  2121,  2131,  2140,  2150,  2157,
+    2167,  2176,  2186,  2195,  2201,  2210,  2219,  2228,  2237,  2247,
+    2257,  2264,  2274,  2281,  2291,  2300,  2310,  2319,  2328,  2337,
+    2347,  2354,  2364,  2373,  2383,  2393,  2399,  2406,  2416,  2426,
+    2436,  2447,  2457,  2468,  2478,  2489,  2499,  2509,  2518,  2527,
+    2536,  2545,  2555,  2565,  2575,  2584,  2593,  2602,  2611,  2621,
+    2631,  2641,  2650,  2659,  2668,  2678,  2687,  2696,  2703,  2712,
+    2721,  2730,  2740,  2749,  2758,  2768,  2777,  2786,  2795,  2805,
+    2814,  2823,  2832,  2841,  2850,  2860,  2869,  2878,  2888,  2897,
+    2907,  2916,  2926,  2935,  2945,  2954,  2964,  2973,  2983,  2992,
+    3002,  3011,  3021,  3031,  3041,  3050,  3060,  3069,  3078,  3087,
+    3096,  3105,  3114,  3123,  3132,  3141,  3150,  3159,  3169,  3179,
+    3189,  3198
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || 1
+/** Accessing symbol of state STATE.  */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+   YYSYMBOL.  No bounds checking.  */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "jp_ABSTRACT", "jp_ASSERT",
-  "jp_BOOLEAN_TYPE", "jp_BREAK", "jp_BYTE_TYPE", "jp_CASE", "jp_CATCH",
-  "jp_CHAR_TYPE", "jp_CLASS", "jp_CONTINUE", "jp_DEFAULT", "jp_DO",
-  "jp_DOUBLE_TYPE", "jp_ELSE", "jp_EXTENDS", "jp_FINAL", "jp_FINALLY",
-  "jp_FLOAT_TYPE", "jp_FOR", "jp_IF", "jp_IMPLEMENTS", "jp_IMPORT",
-  "jp_INSTANCEOF", "jp_INT_TYPE", "jp_INTERFACE", "jp_LONG_TYPE",
-  "jp_NATIVE", "jp_NEW", "jp_PACKAGE", "jp_PRIVATE", "jp_PROTECTED",
-  "jp_PUBLIC", "jp_RETURN", "jp_SHORT_TYPE", "jp_STATIC", "jp_STRICTFP",
-  "jp_SUPER", "jp_SWITCH", "jp_SYNCHRONIZED", "jp_THIS", "jp_THROW",
-  "jp_THROWS", "jp_TRANSIENT", "jp_TRY", "jp_VOID", "jp_VOLATILE",
-  "jp_WHILE", "jp_BOOLEANLITERAL", "jp_CHARACTERLITERAL",
+  "\"end of file\"", "error", "\"invalid token\"", "jp_ABSTRACT",
+  "jp_ASSERT", "jp_BOOLEAN_TYPE", "jp_BREAK", "jp_BYTE_TYPE", "jp_CASE",
+  "jp_CATCH", "jp_CHAR_TYPE", "jp_CLASS", "jp_CONTINUE", "jp_DEFAULT",
+  "jp_DO", "jp_DOUBLE_TYPE", "jp_ELSE", "jp_EXTENDS", "jp_FINAL",
+  "jp_FINALLY", "jp_FLOAT_TYPE", "jp_FOR", "jp_IF", "jp_IMPLEMENTS",
+  "jp_IMPORT", "jp_INSTANCEOF", "jp_INT_TYPE", "jp_INTERFACE",
+  "jp_LONG_TYPE", "jp_NATIVE", "jp_NEW", "jp_PACKAGE", "jp_PRIVATE",
+  "jp_PROTECTED", "jp_PUBLIC", "jp_RETURN", "jp_SHORT_TYPE", "jp_STATIC",
+  "jp_STRICTFP", "jp_SUPER", "jp_SWITCH", "jp_SYNCHRONIZED", "jp_THIS",
+  "jp_THROW", "jp_THROWS", "jp_TRANSIENT", "jp_TRY", "jp_VOID",
+  "jp_VOLATILE", "jp_WHILE", "jp_BOOLEANLITERAL", "jp_CHARACTERLITERAL",
   "jp_DECIMALINTEGERLITERAL", "jp_FLOATINGPOINTLITERAL",
   "jp_HEXINTEGERLITERAL", "jp_NULLLITERAL", "jp_STRINGLITERAL", "jp_NAME",
   "jp_AND", "jp_ANDAND", "jp_ANDEQUALS", "jp_BRACKETEND",
@@ -801,12 +918,18 @@ static const char *const yytname[] =
   "LeftHandSide", "AssignmentOperator", "Expression", "ConstantExpression",
   "New", YY_NULLPTR
 };
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+  return yytname[yysymbol];
+}
 #endif
 
-# ifdef YYPRINT
+#ifdef YYPRINT
 /* YYTOKNUM[NUM] -- (External) token number corresponding to the
    (internal) symbol number NUM (which must be that of a token).  */
-static const yytype_uint16 yytoknum[] =
+static const yytype_int16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
@@ -820,16 +943,16 @@ static const yytype_uint16 yytoknum[] =
      345,   346,   347,   348,   349,   350,   351,   352,   353,   354,
      355,   356,   357,   358,   359,   360
 };
-# endif
+#endif
 
-#define YYPACT_NINF -503
+#define YYPACT_NINF (-503)
 
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-503)))
+#define yypact_value_is_default(Yyn) \
+  ((Yyn) == YYPACT_NINF)
 
-#define YYTABLE_NINF -336
+#define YYTABLE_NINF (-336)
 
-#define yytable_value_is_error(Yytable_value) \
+#define yytable_value_is_error(Yyn) \
   0
 
   /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
@@ -899,7 +1022,7 @@ static const yytype_int16 yypact[] =
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
      Performed when YYTABLE does not specify something else to do.  Zero
      means the default is an error.  */
-static const yytype_uint16 yydefact[] =
+static const yytype_int16 yydefact[] =
 {
       40,     0,     0,     2,    42,    41,    20,    13,    17,    19,
       18,    15,    16,    14,    38,    31,     0,    37,     0,    28,
@@ -1460,7 +1583,7 @@ static const yytype_int16 yycheck[] =
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
-static const yytype_uint16 yystos[] =
+static const yytype_int16 yystos[] =
 {
        0,    31,   107,   122,   123,   126,     5,     7,    10,    15,
       20,    26,    28,    36,    47,    57,    71,   111,   117,   118,
@@ -1523,7 +1646,7 @@ static const yytype_uint16 yystos[] =
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint16 yyr1[] =
+static const yytype_int16 yyr1[] =
 {
        0,   106,   107,   108,   108,   108,   108,   108,   108,   109,
      109,   110,   110,   111,   111,   111,   111,   111,   111,   111,
@@ -1564,7 +1687,7 @@ static const yytype_uint16 yyr1[] =
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
+static const yytype_int8 yyr2[] =
 {
        0,     2,     1,     1,     1,     1,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
@@ -1605,10 +1728,10 @@ static const yytype_uint8 yyr2[] =
 };
 
 
+enum { YYENOMEM = -2 };
+
 #define yyerrok         (yyerrstatus = 0)
 #define yyclearin       (yychar = YYEMPTY)
-#define YYEMPTY         (-2)
-#define YYEOF           0
 
 #define YYACCEPT        goto yyacceptlab
 #define YYABORT         goto yyabortlab
@@ -1634,10 +1757,9 @@ static const yytype_uint8 yyr2[] =
       }                                                           \
   while (0)
 
-/* Error token number */
-#define YYTERROR        1
-#define YYERRCODE       256
-
+/* Backward compatibility with an undocumented macro.
+   Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
 
 
 /* Enable debugging if requested.  */
@@ -1655,18 +1777,18 @@ do {                                            \
 } while (0)
 
 /* This macro is provided for backward compatibility. */
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
+# ifndef YY_LOCATION_PRINT
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
 
 
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
 do {                                                                      \
   if (yydebug)                                                            \
     {                                                                     \
       YYFPRINTF (stderr, "%s ", Title);                                   \
       yy_symbol_print (stderr,                                            \
-                  Type, Value, yyscanner); \
+                  Kind, Value, yyscanner); \
       YYFPRINTF (stderr, "\n");                                           \
     }                                                                     \
 } while (0)
@@ -1677,7 +1799,8 @@ do {                                                                      \
 `-----------------------------------*/
 
 static void
-yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_value_print (FILE *yyo,
+                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   FILE *yyoutput = yyo;
   YYUSE (yyoutput);
@@ -1685,11 +1808,11 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
   if (!yyvaluep)
     return;
 # ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
+  if (yykind < YYNTOKENS)
+    YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
 # endif
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
@@ -1699,12 +1822,13 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
 `---------------------------*/
 
 static void
-yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_print (FILE *yyo,
+                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   YYFPRINTF (yyo, "%s %s (",
-             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
 
-  yy_symbol_value_print (yyo, yytype, yyvaluep, yyscanner);
+  yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
   YYFPRINTF (yyo, ")");
 }
 
@@ -1714,7 +1838,7 @@ yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t
 `------------------------------------------------------------------*/
 
 static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
 {
   YYFPRINTF (stderr, "Stack now");
   for (; yybottom <= yytop; yybottom++)
@@ -1737,21 +1861,21 @@ do {                                                            \
 `------------------------------------------------*/
 
 static void
-yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, yyscan_t yyscanner)
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+                 int yyrule, yyscan_t yyscanner)
 {
-  unsigned long yylno = yyrline[yyrule];
+  int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
   int yyi;
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
              yyrule - 1, yylno);
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr,
-                       yystos[yyssp[yyi + 1 - yynrhs]],
-                       &yyvsp[(yyi + 1) - (yynrhs)]
-                                              , yyscanner);
+                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+                       &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -1766,8 +1890,8 @@ do {                                    \
    multiple parsers can coexist.  */
 int yydebug;
 #else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
 # define YY_STACK_PRINT(Bottom, Top)
 # define YY_REDUCE_PRINT(Rule)
 #endif /* !YYDEBUG */
@@ -1790,28 +1914,76 @@ int yydebug;
 #endif
 
 
-#if YYERROR_VERBOSE
+/* Context of a parse error.  */
+typedef struct
+{
+  yy_state_t *yyssp;
+  yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+   current YYCTX, and return the number of tokens stored in YYARG.  If
+   YYARG is null, return the number of expected tokens (guaranteed to
+   be less than YYNTOKENS).  Return YYENOMEM on memory exhaustion.
+   Return 0 if there are more than YYARGN expected tokens, yet fill
+   YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+                            yysymbol_kind_t yyarg[], int yyargn)
+{
+  /* Actual size of YYARG. */
+  int yycount = 0;
+  int yyn = yypact[+*yyctx->yyssp];
+  if (!yypact_value_is_default (yyn))
+    {
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+         YYCHECK.  In other words, skip the first -YYN actions for
+         this state because they are default actions.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yyx;
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+        if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+            && !yytable_value_is_error (yytable[yyx + yyn]))
+          {
+            if (!yyarg)
+              ++yycount;
+            else if (yycount == yyargn)
+              return 0;
+            else
+              yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+          }
+    }
+  if (yyarg && yycount == 0 && 0 < yyargn)
+    yyarg[0] = YYSYMBOL_YYEMPTY;
+  return yycount;
+}
+
+
 
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+#  define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
 /* Return the length of YYSTR.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yystrlen (const char *yystr)
 {
-  YYSIZE_T yylen;
+  YYPTRDIFF_T yylen;
   for (yylen = 0; yystr[yylen]; yylen++)
     continue;
   return yylen;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#  define yystpcpy stpcpy
+# else
 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    YYDEST.  */
 static char *
@@ -1825,10 +1997,10 @@ yystpcpy (char *yydest, const char *yysrc)
 
   return yyd - 1;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yytnamerr
+#ifndef yytnamerr
 /* Copy to YYRES the contents of YYSTR after stripping away unnecessary
    quotes and backslashes, so that it's suitable for yyerror.  The
    heuristic is that double-quoting is unnecessary unless the string
@@ -1836,14 +2008,13 @@ yystpcpy (char *yydest, const char *yysrc)
    backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
    null, do not copy; instead, return the length of what the result
    would have been.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yytnamerr (char *yyres, const char *yystr)
 {
   if (*yystr == '"')
     {
-      YYSIZE_T yyn = 0;
+      YYPTRDIFF_T yyn = 0;
       char const *yyp = yystr;
-
       for (;;)
         switch (*++yyp)
           {
@@ -1872,36 +2043,20 @@ yytnamerr (char *yyres, const char *yystr)
     do_not_strip_quotes: ;
     }
 
-  if (! yyres)
+  if (yyres)
+    return yystpcpy (yyres, yystr) - yyres;
+  else
     return yystrlen (yystr);
-
-  return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres);
 }
-# endif
+#endif
 
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN for the state stack whose top is
-   YYSSP.
 
-   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
-   not large enough to hold the message.  In that case, also set
-   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
-   required number of bytes is too large to store.  */
 static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                yytype_int16 *yyssp, int yytoken)
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+                           yysymbol_kind_t yyarg[], int yyargn)
 {
-  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
-  YYSIZE_T yysize = yysize0;
-  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-  /* Internationalized format string. */
-  const char *yyformat = YY_NULLPTR;
-  /* Arguments of yyformat. */
-  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-  /* Number of reported tokens (one for the "unexpected", one per
-     "expected"). */
+  /* Actual size of YYARG. */
   int yycount = 0;
-
   /* There are many possibilities here to consider:
      - If this state is a consistent state with a default action, then
        the only way this function was invoked is if the default action
@@ -1925,49 +2080,54 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
        one exception: it will still contain any token that will not be
        accepted due to an error action in a later state.
   */
-  if (yytoken != YYEMPTY)
-    {
-      int yyn = yypact[*yyssp];
-      yyarg[yycount++] = yytname[yytoken];
-      if (!yypact_value_is_default (yyn))
-        {
-          /* Start YYX at -YYN if negative to avoid negative indexes in
-             YYCHECK.  In other words, skip the first -YYN actions for
-             this state because they are default actions.  */
-          int yyxbegin = yyn < 0 ? -yyn : 0;
-          /* Stay within bounds of both yycheck and yytname.  */
-          int yychecklim = YYLAST - yyn + 1;
-          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-          int yyx;
-
-          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
-                && !yytable_value_is_error (yytable[yyx + yyn]))
-              {
-                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-                  {
-                    yycount = 1;
-                    yysize = yysize0;
-                    break;
-                  }
-                yyarg[yycount++] = yytname[yyx];
-                {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
-                  if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-                    yysize = yysize1;
-                  else
-                    return 2;
-                }
-              }
-        }
+  if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+    {
+      int yyn;
+      if (yyarg)
+        yyarg[yycount] = yyctx->yytoken;
+      ++yycount;
+      yyn = yypcontext_expected_tokens (yyctx,
+                                        yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+      if (yyn == YYENOMEM)
+        return YYENOMEM;
+      else
+        yycount += yyn;
     }
+  return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return -1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return YYENOMEM if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+                const yypcontext_t *yyctx)
+{
+  enum { YYARGS_MAX = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat: reported tokens (one for the "unexpected",
+     one per "expected"). */
+  yysymbol_kind_t yyarg[YYARGS_MAX];
+  /* Cumulated lengths of YYARG.  */
+  YYPTRDIFF_T yysize = 0;
+
+  /* Actual size of YYARG. */
+  int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+  if (yycount == YYENOMEM)
+    return YYENOMEM;
 
   switch (yycount)
     {
-# define YYCASE_(N, S)                      \
+#define YYCASE_(N, S)                       \
       case N:                               \
         yyformat = S;                       \
-      break
+        break
     default: /* Avoid compiler warnings. */
       YYCASE_(0, YY_("syntax error"));
       YYCASE_(1, YY_("syntax error, unexpected %s"));
@@ -1975,15 +2135,23 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
+#undef YYCASE_
     }
 
+  /* Compute error message size.  Don't count the "%s"s, but reserve
+     room for the terminator.  */
+  yysize = yystrlen (yyformat) - 2 * yycount + 1;
   {
-    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
-    if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-      yysize = yysize1;
-    else
-      return 2;
+    int yyi;
+    for (yyi = 0; yyi < yycount; ++yyi)
+      {
+        YYPTRDIFF_T yysize1
+          = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+        if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+          yysize = yysize1;
+        else
+          return YYENOMEM;
+      }
   }
 
   if (*yymsg_alloc < yysize)
@@ -1992,7 +2160,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       if (! (yysize <= *yymsg_alloc
              && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
         *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
-      return 1;
+      return -1;
     }
 
   /* Avoid sprintf, as that infringes on the user's name space.
@@ -2004,40 +2172,43 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
     while ((*yyp = *yyformat) != '\0')
       if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
         {
-          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
           yyformat += 2;
         }
       else
         {
-          yyp++;
-          yyformat++;
+          ++yyp;
+          ++yyformat;
         }
   }
   return 0;
 }
-#endif /* YYERROR_VERBOSE */
+
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
 `-----------------------------------------------*/
 
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+yydestruct (const char *yymsg,
+            yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
 {
   YYUSE (yyvaluep);
   YYUSE (yyscanner);
   if (!yymsg)
     yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
 
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
 
 
+
+
 /*----------.
 | yyparse.  |
 `----------*/
@@ -2045,7 +2216,7 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner
 int
 yyparse (yyscan_t yyscanner)
 {
-/* The lookahead symbol.  */
+/* Lookahead token kind.  */
 int yychar;
 
 
@@ -2056,45 +2227,41 @@ YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
 YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
 
     /* Number of syntax errors so far.  */
-    int yynerrs;
+    int yynerrs = 0;
 
-    int yystate;
+    yy_state_fast_t yystate = 0;
     /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus;
-
-    /* The stacks and their tools:
-       'yyss': related to states.
-       'yyvs': related to semantic values.
+    int yyerrstatus = 0;
 
-       Refer to the stacks through separate pointers, to allow yyoverflow
+    /* Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
 
-    /* The state stack.  */
-    yytype_int16 yyssa[YYINITDEPTH];
-    yytype_int16 *yyss;
-    yytype_int16 *yyssp;
+    /* Their size.  */
+    YYPTRDIFF_T yystacksize = YYINITDEPTH;
 
-    /* The semantic value stack.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs;
-    YYSTYPE *yyvsp;
+    /* The state stack: array, bottom, top.  */
+    yy_state_t yyssa[YYINITDEPTH];
+    yy_state_t *yyss = yyssa;
+    yy_state_t *yyssp = yyss;
 
-    YYSIZE_T yystacksize;
+    /* The semantic value stack: array, bottom, top.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs = yyvsa;
+    YYSTYPE *yyvsp = yyvs;
 
   int yyn;
+  /* The return value of yyparse.  */
   int yyresult;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken = 0;
+  /* Lookahead symbol kind.  */
+  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
 
-#if YYERROR_VERBOSE
   /* Buffer for error messages, and its allocated size.  */
   char yymsgbuf[128];
   char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
+  YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
 
 #define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
 
@@ -2102,15 +2269,8 @@ YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
 
-  yyssp = yyss = yyssa;
-  yyvsp = yyvs = yyvsa;
-  yystacksize = YYINITDEPTH;
-
   YYDPRINTF ((stderr, "Starting parse\n"));
 
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
   yychar = YYEMPTY; /* Cause a token to be read.  */
   goto yysetstate;
 
@@ -2125,12 +2285,15 @@ yynewstate:
 
 
 /*--------------------------------------------------------------------.
-| yynewstate -- set current state (the top of the stack) to yystate.  |
+| yysetstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
   YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
-  *yyssp = (yytype_int16) yystate;
+  YY_IGNORE_USELESS_CAST_BEGIN
+  *yyssp = YY_CAST (yy_state_t, yystate);
+  YY_IGNORE_USELESS_CAST_END
+  YY_STACK_PRINT (yyss, yyssp);
 
   if (yyss + yystacksize - 1 <= yyssp)
 #if !defined yyoverflow && !defined YYSTACK_RELOCATE
@@ -2138,23 +2301,23 @@ yysetstate:
 #else
     {
       /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1);
+      YYPTRDIFF_T yysize = yyssp - yyss + 1;
 
 # if defined yyoverflow
       {
         /* Give user a chance to reallocate the stack.  Use copies of
            these so that the &'s don't force the real ones into
            memory.  */
+        yy_state_t *yyss1 = yyss;
         YYSTYPE *yyvs1 = yyvs;
-        yytype_int16 *yyss1 = yyss;
 
         /* Each stack pointer address is followed by the size of the
            data in use in that stack, in bytes.  This used to be a
            conditional around just the two extra args, but that might
            be undefined if yyoverflow is a macro.  */
         yyoverflow (YY_("memory exhausted"),
-                    &yyss1, yysize * sizeof (*yyssp),
-                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yyss1, yysize * YYSIZEOF (*yyssp),
+                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
                     &yystacksize);
         yyss = yyss1;
         yyvs = yyvs1;
@@ -2168,14 +2331,15 @@ yysetstate:
         yystacksize = YYMAXDEPTH;
 
       {
-        yytype_int16 *yyss1 = yyss;
+        yy_state_t *yyss1 = yyss;
         union yyalloc *yyptr =
-          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+          YY_CAST (union yyalloc *,
+                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
         if (! yyptr)
           goto yyexhaustedlab;
         YYSTACK_RELOCATE (yyss_alloc, yyss);
         YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-# undef YYSTACK_RELOCATE
+#  undef YYSTACK_RELOCATE
         if (yyss1 != yyssa)
           YYSTACK_FREE (yyss1);
       }
@@ -2184,8 +2348,10 @@ yysetstate:
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
 
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                  (unsigned long) yystacksize));
+      YY_IGNORE_USELESS_CAST_BEGIN
+      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+                  YY_CAST (long, yystacksize)));
+      YY_IGNORE_USELESS_CAST_END
 
       if (yyss + yystacksize - 1 <= yyssp)
         YYABORT;
@@ -2212,18 +2378,29 @@ yybackup:
 
   /* Not known => get a lookahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
   if (yychar == YYEMPTY)
     {
-      YYDPRINTF ((stderr, "Reading a token"));
+      YYDPRINTF ((stderr, "Reading a token\n"));
       yychar = yylex (&yylval, yyscanner);
     }
 
   if (yychar <= YYEOF)
     {
-      yychar = yytoken = YYEOF;
+      yychar = YYEOF;
+      yytoken = YYSYMBOL_YYEOF;
       YYDPRINTF ((stderr, "Now at end of input.\n"));
     }
+  else if (yychar == YYerror)
+    {
+      /* The scanner already issued an error message, process directly
+         to error recovery.  But do not keep the error token as
+         lookahead, it is too special and may lead us to an endless
+         loop in error recovery. */
+      yychar = YYUNDEF;
+      yytoken = YYSYMBOL_YYerror;
+      goto yyerrlab1;
+    }
   else
     {
       yytoken = YYTRANSLATE (yychar);
@@ -2251,14 +2428,13 @@ yybackup:
 
   /* Shift the lookahead token.  */
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-
   yystate = yyn;
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
   goto yynewstate;
 
 
@@ -2293,330 +2469,330 @@ yyreduce:
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-  case 2:
-#line 183 "cmDependsJavaParser.y"
-    {
+  case 2: /* Goal: CompilationUnit  */
+#line 181 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2305 "cmDependsJavaParser.cxx"
+#line 2481 "cmDependsJavaParser.cxx"
     break;
 
-  case 3:
-#line 192 "cmDependsJavaParser.y"
-    {
+  case 3: /* Literal: IntegerLiteral  */
+#line 190 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2316 "cmDependsJavaParser.cxx"
+#line 2492 "cmDependsJavaParser.cxx"
     break;
 
-  case 4:
-#line 200 "cmDependsJavaParser.y"
-    {
+  case 4: /* Literal: jp_FLOATINGPOINTLITERAL  */
+#line 198 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2327 "cmDependsJavaParser.cxx"
+#line 2503 "cmDependsJavaParser.cxx"
     break;
 
-  case 5:
-#line 208 "cmDependsJavaParser.y"
-    {
+  case 5: /* Literal: jp_BOOLEANLITERAL  */
+#line 206 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2338 "cmDependsJavaParser.cxx"
+#line 2514 "cmDependsJavaParser.cxx"
     break;
 
-  case 6:
-#line 216 "cmDependsJavaParser.y"
-    {
+  case 6: /* Literal: jp_CHARACTERLITERAL  */
+#line 214 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2349 "cmDependsJavaParser.cxx"
+#line 2525 "cmDependsJavaParser.cxx"
     break;
 
-  case 7:
-#line 224 "cmDependsJavaParser.y"
-    {
+  case 7: /* Literal: jp_STRINGLITERAL  */
+#line 222 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2360 "cmDependsJavaParser.cxx"
+#line 2536 "cmDependsJavaParser.cxx"
     break;
 
-  case 8:
-#line 232 "cmDependsJavaParser.y"
-    {
+  case 8: /* Literal: jp_NULLLITERAL  */
+#line 230 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2371 "cmDependsJavaParser.cxx"
+#line 2547 "cmDependsJavaParser.cxx"
     break;
 
-  case 9:
-#line 241 "cmDependsJavaParser.y"
-    {
+  case 9: /* IntegerLiteral: jp_DECIMALINTEGERLITERAL  */
+#line 239 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2382 "cmDependsJavaParser.cxx"
+#line 2558 "cmDependsJavaParser.cxx"
     break;
 
-  case 10:
-#line 249 "cmDependsJavaParser.y"
-    {
+  case 10: /* IntegerLiteral: jp_HEXINTEGERLITERAL  */
+#line 247 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2393 "cmDependsJavaParser.cxx"
+#line 2569 "cmDependsJavaParser.cxx"
     break;
 
-  case 11:
-#line 258 "cmDependsJavaParser.y"
-    {
+  case 11: /* Type: PrimitiveType  */
+#line 256 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2404 "cmDependsJavaParser.cxx"
+#line 2580 "cmDependsJavaParser.cxx"
     break;
 
-  case 12:
-#line 266 "cmDependsJavaParser.y"
-    {
+  case 12: /* Type: ReferenceType  */
+#line 264 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2415 "cmDependsJavaParser.cxx"
+#line 2591 "cmDependsJavaParser.cxx"
     break;
 
-  case 13:
-#line 275 "cmDependsJavaParser.y"
-    {
+  case 13: /* PrimitiveType: jp_BYTE_TYPE  */
+#line 273 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2423 "cmDependsJavaParser.cxx"
+#line 2599 "cmDependsJavaParser.cxx"
     break;
 
-  case 14:
-#line 280 "cmDependsJavaParser.y"
-    {
+  case 14: /* PrimitiveType: jp_SHORT_TYPE  */
+#line 278 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2431 "cmDependsJavaParser.cxx"
+#line 2607 "cmDependsJavaParser.cxx"
     break;
 
-  case 15:
-#line 285 "cmDependsJavaParser.y"
-    {
+  case 15: /* PrimitiveType: jp_INT_TYPE  */
+#line 283 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2439 "cmDependsJavaParser.cxx"
+#line 2615 "cmDependsJavaParser.cxx"
     break;
 
-  case 16:
-#line 290 "cmDependsJavaParser.y"
-    {
+  case 16: /* PrimitiveType: jp_LONG_TYPE  */
+#line 288 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2447 "cmDependsJavaParser.cxx"
+#line 2623 "cmDependsJavaParser.cxx"
     break;
 
-  case 17:
-#line 295 "cmDependsJavaParser.y"
-    {
+  case 17: /* PrimitiveType: jp_CHAR_TYPE  */
+#line 293 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2455 "cmDependsJavaParser.cxx"
+#line 2631 "cmDependsJavaParser.cxx"
     break;
 
-  case 18:
-#line 300 "cmDependsJavaParser.y"
-    {
+  case 18: /* PrimitiveType: jp_FLOAT_TYPE  */
+#line 298 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2463 "cmDependsJavaParser.cxx"
+#line 2639 "cmDependsJavaParser.cxx"
     break;
 
-  case 19:
-#line 305 "cmDependsJavaParser.y"
-    {
+  case 19: /* PrimitiveType: jp_DOUBLE_TYPE  */
+#line 303 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2471 "cmDependsJavaParser.cxx"
+#line 2647 "cmDependsJavaParser.cxx"
     break;
 
-  case 20:
-#line 310 "cmDependsJavaParser.y"
-    {
+  case 20: /* PrimitiveType: jp_BOOLEAN_TYPE  */
+#line 308 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
 }
-#line 2479 "cmDependsJavaParser.cxx"
+#line 2655 "cmDependsJavaParser.cxx"
     break;
 
-  case 21:
-#line 316 "cmDependsJavaParser.y"
-    {
+  case 21: /* ReferenceType: ClassOrInterfaceType  */
+#line 314 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2490 "cmDependsJavaParser.cxx"
+#line 2666 "cmDependsJavaParser.cxx"
     break;
 
-  case 22:
-#line 324 "cmDependsJavaParser.y"
-    {
+  case 22: /* ReferenceType: ArrayType  */
+#line 322 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2501 "cmDependsJavaParser.cxx"
+#line 2677 "cmDependsJavaParser.cxx"
     break;
 
-  case 23:
-#line 333 "cmDependsJavaParser.y"
-    {
+  case 23: /* ClassOrInterfaceType: Name  */
+#line 331 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpStoreClass((yyvsp[0].str));
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2513 "cmDependsJavaParser.cxx"
+#line 2689 "cmDependsJavaParser.cxx"
     break;
 
-  case 24:
-#line 343 "cmDependsJavaParser.y"
-    {
+  case 24: /* ClassType: ClassOrInterfaceType  */
+#line 341 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2524 "cmDependsJavaParser.cxx"
+#line 2700 "cmDependsJavaParser.cxx"
     break;
 
-  case 25:
-#line 352 "cmDependsJavaParser.y"
-    {
+  case 25: /* InterfaceType: ClassOrInterfaceType  */
+#line 350 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2535 "cmDependsJavaParser.cxx"
+#line 2711 "cmDependsJavaParser.cxx"
     break;
 
-  case 26:
-#line 361 "cmDependsJavaParser.y"
-    {
+  case 26: /* ArrayType: PrimitiveType Dims  */
+#line 359 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2546 "cmDependsJavaParser.cxx"
+#line 2722 "cmDependsJavaParser.cxx"
     break;
 
-  case 27:
-#line 369 "cmDependsJavaParser.y"
-    {
+  case 27: /* ArrayType: Name Dims  */
+#line 367 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpStoreClass((yyvsp[-1].str));
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2558 "cmDependsJavaParser.cxx"
+#line 2734 "cmDependsJavaParser.cxx"
     break;
 
-  case 28:
-#line 379 "cmDependsJavaParser.y"
-    {
+  case 28: /* Name: SimpleName  */
+#line 377 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2567 "cmDependsJavaParser.cxx"
+#line 2743 "cmDependsJavaParser.cxx"
     break;
 
-  case 29:
-#line 385 "cmDependsJavaParser.y"
-    {
+  case 29: /* Name: QualifiedName  */
+#line 383 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2576 "cmDependsJavaParser.cxx"
+#line 2752 "cmDependsJavaParser.cxx"
     break;
 
-  case 30:
-#line 392 "cmDependsJavaParser.y"
-    {
+  case 30: /* SimpleName: Identifier  */
+#line 390 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2585 "cmDependsJavaParser.cxx"
+#line 2761 "cmDependsJavaParser.cxx"
     break;
 
-  case 31:
-#line 399 "cmDependsJavaParser.y"
-    {
+  case 31: /* Identifier: jp_NAME  */
+#line 397 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2594 "cmDependsJavaParser.cxx"
+#line 2770 "cmDependsJavaParser.cxx"
     break;
 
-  case 32:
-#line 405 "cmDependsJavaParser.y"
-    {
+  case 32: /* Identifier: jp_DOLLAR jp_NAME  */
+#line 403 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2603 "cmDependsJavaParser.cxx"
+#line 2779 "cmDependsJavaParser.cxx"
     break;
 
-  case 33:
-#line 412 "cmDependsJavaParser.y"
-    {
+  case 33: /* QualifiedName: Name jp_DOT Identifier  */
+#line 410 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->AddClassFound((yyvsp[-2].str));
   yyGetParser->UpdateCombine((yyvsp[-2].str), (yyvsp[0].str));
   yyGetParser->DeallocateParserType(&((yyvsp[-2].str)));
   (yyval.str) = const_cast<char*>(yyGetParser->GetCurrentCombine());
 }
-#line 2615 "cmDependsJavaParser.cxx"
+#line 2791 "cmDependsJavaParser.cxx"
     break;
 
-  case 34:
-#line 421 "cmDependsJavaParser.y"
-    {
+  case 34: /* QualifiedName: Name jp_DOT jp_CLASS  */
+#line 419 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpStoreClass((yyvsp[-2].str));
   jpCheckEmpty(3);
@@ -2624,12 +2800,12 @@ yyreduce:
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2628 "cmDependsJavaParser.cxx"
+#line 2804 "cmDependsJavaParser.cxx"
     break;
 
-  case 35:
-#line 431 "cmDependsJavaParser.y"
-    {
+  case 35: /* QualifiedName: Name jp_DOT jp_THIS  */
+#line 429 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpStoreClass((yyvsp[-2].str));
   yyGetParser->SetCurrentCombine("");
@@ -2637,119 +2813,119 @@ yyreduce:
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2641 "cmDependsJavaParser.cxx"
+#line 2817 "cmDependsJavaParser.cxx"
     break;
 
-  case 36:
-#line 441 "cmDependsJavaParser.y"
-    {
+  case 36: /* QualifiedName: SimpleType jp_DOT jp_CLASS  */
+#line 439 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2652 "cmDependsJavaParser.cxx"
+#line 2828 "cmDependsJavaParser.cxx"
     break;
 
-  case 37:
-#line 450 "cmDependsJavaParser.y"
-    {
+  case 37: /* SimpleType: PrimitiveType  */
+#line 448 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2663 "cmDependsJavaParser.cxx"
+#line 2839 "cmDependsJavaParser.cxx"
     break;
 
-  case 38:
-#line 458 "cmDependsJavaParser.y"
-    {
+  case 38: /* SimpleType: jp_VOID  */
+#line 456 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2674 "cmDependsJavaParser.cxx"
+#line 2850 "cmDependsJavaParser.cxx"
     break;
 
-  case 39:
-#line 467 "cmDependsJavaParser.y"
-    {
+  case 39: /* CompilationUnit: PackageDeclarationopt ImportDeclarations TypeDeclarations  */
+#line 465 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2685 "cmDependsJavaParser.cxx"
+#line 2861 "cmDependsJavaParser.cxx"
     break;
 
-  case 40:
-#line 475 "cmDependsJavaParser.y"
-    {
+  case 40: /* PackageDeclarationopt: %empty  */
+#line 473 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2695 "cmDependsJavaParser.cxx"
+#line 2871 "cmDependsJavaParser.cxx"
     break;
 
-  case 41:
-#line 482 "cmDependsJavaParser.y"
-    {
+  case 41: /* PackageDeclarationopt: PackageDeclaration  */
+#line 480 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2706 "cmDependsJavaParser.cxx"
+#line 2882 "cmDependsJavaParser.cxx"
     break;
 
-  case 42:
-#line 490 "cmDependsJavaParser.y"
-    {
+  case 42: /* ImportDeclarations: %empty  */
+#line 488 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2716 "cmDependsJavaParser.cxx"
+#line 2892 "cmDependsJavaParser.cxx"
     break;
 
-  case 43:
-#line 497 "cmDependsJavaParser.y"
-    {
+  case 43: /* ImportDeclarations: ImportDeclarations ImportDeclaration  */
+#line 495 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2727 "cmDependsJavaParser.cxx"
+#line 2903 "cmDependsJavaParser.cxx"
     break;
 
-  case 44:
-#line 505 "cmDependsJavaParser.y"
-    {
+  case 44: /* TypeDeclarations: %empty  */
+#line 503 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2737 "cmDependsJavaParser.cxx"
+#line 2913 "cmDependsJavaParser.cxx"
     break;
 
-  case 45:
-#line 512 "cmDependsJavaParser.y"
-    {
+  case 45: /* TypeDeclarations: TypeDeclarations TypeDeclaration  */
+#line 510 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2748 "cmDependsJavaParser.cxx"
+#line 2924 "cmDependsJavaParser.cxx"
     break;
 
-  case 46:
-#line 521 "cmDependsJavaParser.y"
-    {
+  case 46: /* PackageDeclaration: jp_PACKAGE Name jp_SEMICOL  */
+#line 519 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->SetCurrentPackage((yyvsp[-1].str));
   yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
@@ -2758,34 +2934,34 @@ yyreduce:
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2762 "cmDependsJavaParser.cxx"
+#line 2938 "cmDependsJavaParser.cxx"
     break;
 
-  case 47:
-#line 533 "cmDependsJavaParser.y"
-    {
+  case 47: /* ImportDeclaration: SingleTypeImportDeclaration  */
+#line 531 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2773 "cmDependsJavaParser.cxx"
+#line 2949 "cmDependsJavaParser.cxx"
     break;
 
-  case 48:
-#line 541 "cmDependsJavaParser.y"
-    {
+  case 48: /* ImportDeclaration: TypeImportOnDemandDeclaration  */
+#line 539 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2784 "cmDependsJavaParser.cxx"
+#line 2960 "cmDependsJavaParser.cxx"
     break;
 
-  case 49:
-#line 550 "cmDependsJavaParser.y"
-    {
+  case 49: /* SingleTypeImportDeclaration: jp_IMPORT Name jp_SEMICOL  */
+#line 548 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->AddPackagesImport((yyvsp[-1].str));
   yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
@@ -2794,12 +2970,12 @@ yyreduce:
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2798 "cmDependsJavaParser.cxx"
+#line 2974 "cmDependsJavaParser.cxx"
     break;
 
-  case 50:
-#line 562 "cmDependsJavaParser.y"
-    {
+  case 50: /* TypeImportOnDemandDeclaration: jp_IMPORT Name jp_DOT jp_TIMES jp_SEMICOL  */
+#line 560 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   std::string str = (yyvsp[-3].str);
   str += ".*";
@@ -2809,466 +2985,466 @@ yyreduce:
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2813 "cmDependsJavaParser.cxx"
+#line 2989 "cmDependsJavaParser.cxx"
     break;
 
-  case 51:
-#line 575 "cmDependsJavaParser.y"
-    {
+  case 51: /* TypeDeclaration: ClassDeclaration  */
+#line 573 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2824 "cmDependsJavaParser.cxx"
+#line 3000 "cmDependsJavaParser.cxx"
     break;
 
-  case 52:
-#line 583 "cmDependsJavaParser.y"
-    {
+  case 52: /* TypeDeclaration: InterfaceDeclaration  */
+#line 581 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2835 "cmDependsJavaParser.cxx"
+#line 3011 "cmDependsJavaParser.cxx"
     break;
 
-  case 53:
-#line 591 "cmDependsJavaParser.y"
-    {
+  case 53: /* TypeDeclaration: jp_SEMICOL  */
+#line 589 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2846 "cmDependsJavaParser.cxx"
+#line 3022 "cmDependsJavaParser.cxx"
     break;
 
-  case 54:
-#line 600 "cmDependsJavaParser.y"
-    {
+  case 54: /* Modifiers: Modifier  */
+#line 598 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2857 "cmDependsJavaParser.cxx"
+#line 3033 "cmDependsJavaParser.cxx"
     break;
 
-  case 55:
-#line 608 "cmDependsJavaParser.y"
-    {
+  case 55: /* Modifiers: Modifiers Modifier  */
+#line 606 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2868 "cmDependsJavaParser.cxx"
+#line 3044 "cmDependsJavaParser.cxx"
     break;
 
-  case 67:
-#line 623 "cmDependsJavaParser.y"
-    {
+  case 67: /* ClassHeader: Modifiersopt jp_CLASS Identifier  */
+#line 621 "cmDependsJavaParser.y"
+{
   yyGetParser->StartClass((yyvsp[0].str));
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
 }
-#line 2879 "cmDependsJavaParser.cxx"
+#line 3055 "cmDependsJavaParser.cxx"
     break;
 
-  case 68:
-#line 633 "cmDependsJavaParser.y"
-    {
+  case 68: /* ClassDeclaration: ClassHeader ClassBody  */
+#line 631 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2891 "cmDependsJavaParser.cxx"
+#line 3067 "cmDependsJavaParser.cxx"
     break;
 
-  case 69:
-#line 642 "cmDependsJavaParser.y"
-    {
+  case 69: /* ClassDeclaration: ClassHeader Interfaces ClassBody  */
+#line 640 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2903 "cmDependsJavaParser.cxx"
+#line 3079 "cmDependsJavaParser.cxx"
     break;
 
-  case 70:
-#line 651 "cmDependsJavaParser.y"
-    {
+  case 70: /* ClassDeclaration: ClassHeader Super ClassBody  */
+#line 649 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2915 "cmDependsJavaParser.cxx"
+#line 3091 "cmDependsJavaParser.cxx"
     break;
 
-  case 71:
-#line 660 "cmDependsJavaParser.y"
-    {
+  case 71: /* ClassDeclaration: ClassHeader Super Interfaces ClassBody  */
+#line 658 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2927 "cmDependsJavaParser.cxx"
+#line 3103 "cmDependsJavaParser.cxx"
     break;
 
-  case 72:
-#line 669 "cmDependsJavaParser.y"
-    {
+  case 72: /* Modifiersopt: %empty  */
+#line 667 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2937 "cmDependsJavaParser.cxx"
+#line 3113 "cmDependsJavaParser.cxx"
     break;
 
-  case 73:
-#line 676 "cmDependsJavaParser.y"
-    {
+  case 73: /* Modifiersopt: Modifiers  */
+#line 674 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2948 "cmDependsJavaParser.cxx"
+#line 3124 "cmDependsJavaParser.cxx"
     break;
 
-  case 74:
-#line 685 "cmDependsJavaParser.y"
-    {
+  case 74: /* Super: jp_EXTENDS ClassType  */
+#line 683 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2959 "cmDependsJavaParser.cxx"
+#line 3135 "cmDependsJavaParser.cxx"
     break;
 
-  case 75:
-#line 694 "cmDependsJavaParser.y"
-    {
+  case 75: /* Interfaces: jp_IMPLEMENTS InterfaceTypeList  */
+#line 692 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2970 "cmDependsJavaParser.cxx"
+#line 3146 "cmDependsJavaParser.cxx"
     break;
 
-  case 76:
-#line 703 "cmDependsJavaParser.y"
-    {
+  case 76: /* InterfaceTypeList: InterfaceType  */
+#line 701 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2981 "cmDependsJavaParser.cxx"
+#line 3157 "cmDependsJavaParser.cxx"
     break;
 
-  case 77:
-#line 711 "cmDependsJavaParser.y"
-    {
+  case 77: /* InterfaceTypeList: InterfaceTypeList jp_COMMA InterfaceType  */
+#line 709 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2992 "cmDependsJavaParser.cxx"
+#line 3168 "cmDependsJavaParser.cxx"
     break;
 
-  case 78:
-#line 720 "cmDependsJavaParser.y"
-    {
+  case 78: /* ClassBody: jp_CURLYSTART ClassBodyDeclarations jp_CURLYEND  */
+#line 718 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3003 "cmDependsJavaParser.cxx"
+#line 3179 "cmDependsJavaParser.cxx"
     break;
 
-  case 79:
-#line 728 "cmDependsJavaParser.y"
-    {
+  case 79: /* ClassBodyDeclarations: %empty  */
+#line 726 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3013 "cmDependsJavaParser.cxx"
+#line 3189 "cmDependsJavaParser.cxx"
     break;
 
-  case 80:
-#line 735 "cmDependsJavaParser.y"
-    {
+  case 80: /* ClassBodyDeclarations: ClassBodyDeclarations ClassBodyDeclaration  */
+#line 733 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3024 "cmDependsJavaParser.cxx"
+#line 3200 "cmDependsJavaParser.cxx"
     break;
 
-  case 81:
-#line 744 "cmDependsJavaParser.y"
-    {
+  case 81: /* ClassBodyDeclaration: ClassMemberDeclaration  */
+#line 742 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3035 "cmDependsJavaParser.cxx"
+#line 3211 "cmDependsJavaParser.cxx"
     break;
 
-  case 82:
-#line 752 "cmDependsJavaParser.y"
-    {
+  case 82: /* ClassBodyDeclaration: StaticInitializer  */
+#line 750 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3046 "cmDependsJavaParser.cxx"
+#line 3222 "cmDependsJavaParser.cxx"
     break;
 
-  case 83:
-#line 760 "cmDependsJavaParser.y"
-    {
+  case 83: /* ClassBodyDeclaration: ConstructorDeclaration  */
+#line 758 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3057 "cmDependsJavaParser.cxx"
+#line 3233 "cmDependsJavaParser.cxx"
     break;
 
-  case 84:
-#line 768 "cmDependsJavaParser.y"
-    {
+  case 84: /* ClassBodyDeclaration: TypeDeclaration  */
+#line 766 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3068 "cmDependsJavaParser.cxx"
+#line 3244 "cmDependsJavaParser.cxx"
     break;
 
-  case 85:
-#line 777 "cmDependsJavaParser.y"
-    {
+  case 85: /* ClassMemberDeclaration: FieldDeclaration  */
+#line 775 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3079 "cmDependsJavaParser.cxx"
+#line 3255 "cmDependsJavaParser.cxx"
     break;
 
-  case 86:
-#line 785 "cmDependsJavaParser.y"
-    {
+  case 86: /* ClassMemberDeclaration: MethodDeclaration  */
+#line 783 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3090 "cmDependsJavaParser.cxx"
+#line 3266 "cmDependsJavaParser.cxx"
     break;
 
-  case 87:
-#line 794 "cmDependsJavaParser.y"
-    {
+  case 87: /* FieldDeclaration: Modifiersopt Type VariableDeclarators jp_SEMICOL  */
+#line 792 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
 }
-#line 3098 "cmDependsJavaParser.cxx"
+#line 3274 "cmDependsJavaParser.cxx"
     break;
 
-  case 88:
-#line 800 "cmDependsJavaParser.y"
-    {
+  case 88: /* VariableDeclarators: VariableDeclarator  */
+#line 798 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3109 "cmDependsJavaParser.cxx"
+#line 3285 "cmDependsJavaParser.cxx"
     break;
 
-  case 89:
-#line 808 "cmDependsJavaParser.y"
-    {
+  case 89: /* VariableDeclarators: VariableDeclarators jp_COMMA VariableDeclarator  */
+#line 806 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3120 "cmDependsJavaParser.cxx"
+#line 3296 "cmDependsJavaParser.cxx"
     break;
 
-  case 90:
-#line 817 "cmDependsJavaParser.y"
-    {
+  case 90: /* VariableDeclarator: VariableDeclaratorId  */
+#line 815 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3131 "cmDependsJavaParser.cxx"
+#line 3307 "cmDependsJavaParser.cxx"
     break;
 
-  case 91:
-#line 825 "cmDependsJavaParser.y"
-    {
+  case 91: /* VariableDeclarator: VariableDeclaratorId jp_EQUALS VariableInitializer  */
+#line 823 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3142 "cmDependsJavaParser.cxx"
+#line 3318 "cmDependsJavaParser.cxx"
     break;
 
-  case 92:
-#line 834 "cmDependsJavaParser.y"
-    {
+  case 92: /* VariableDeclaratorId: Identifier  */
+#line 832 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3154 "cmDependsJavaParser.cxx"
+#line 3330 "cmDependsJavaParser.cxx"
     break;
 
-  case 93:
-#line 843 "cmDependsJavaParser.y"
-    {
+  case 93: /* VariableDeclaratorId: VariableDeclaratorId jp_BRACKETSTART jp_BRACKETEND  */
+#line 841 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3165 "cmDependsJavaParser.cxx"
+#line 3341 "cmDependsJavaParser.cxx"
     break;
 
-  case 94:
-#line 852 "cmDependsJavaParser.y"
-    {
+  case 94: /* VariableInitializer: Expression  */
+#line 850 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3176 "cmDependsJavaParser.cxx"
+#line 3352 "cmDependsJavaParser.cxx"
     break;
 
-  case 95:
-#line 860 "cmDependsJavaParser.y"
-    {
+  case 95: /* VariableInitializer: ArrayInitializer  */
+#line 858 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3187 "cmDependsJavaParser.cxx"
+#line 3363 "cmDependsJavaParser.cxx"
     break;
 
-  case 96:
-#line 869 "cmDependsJavaParser.y"
-    {
+  case 96: /* MethodDeclaration: MethodHeader jp_SEMICOL  */
+#line 867 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3198 "cmDependsJavaParser.cxx"
+#line 3374 "cmDependsJavaParser.cxx"
     break;
 
-  case 97:
-#line 877 "cmDependsJavaParser.y"
-    {
+  case 97: /* MethodDeclaration: MethodHeader MethodBody  */
+#line 875 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3209 "cmDependsJavaParser.cxx"
+#line 3385 "cmDependsJavaParser.cxx"
     break;
 
-  case 98:
-#line 885 "cmDependsJavaParser.y"
-    {
+  case 98: /* MethodDeclaration: MethodHeader MethodBody jp_SEMICOL  */
+#line 883 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3220 "cmDependsJavaParser.cxx"
+#line 3396 "cmDependsJavaParser.cxx"
     break;
 
-  case 99:
-#line 894 "cmDependsJavaParser.y"
-    {
+  case 99: /* MethodHeader: Modifiersopt Type MethodDeclarator Throwsopt  */
+#line 892 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3232 "cmDependsJavaParser.cxx"
+#line 3408 "cmDependsJavaParser.cxx"
     break;
 
-  case 100:
-#line 903 "cmDependsJavaParser.y"
-    {
+  case 100: /* MethodHeader: Modifiersopt jp_VOID MethodDeclarator Throwsopt  */
+#line 901 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3244 "cmDependsJavaParser.cxx"
+#line 3420 "cmDependsJavaParser.cxx"
     break;
 
-  case 101:
-#line 912 "cmDependsJavaParser.y"
-    {
+  case 101: /* Throwsopt: %empty  */
+#line 910 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3255 "cmDependsJavaParser.cxx"
+#line 3431 "cmDependsJavaParser.cxx"
     break;
 
-  case 102:
-#line 920 "cmDependsJavaParser.y"
-    {
+  case 102: /* Throwsopt: Throws  */
+#line 918 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3267 "cmDependsJavaParser.cxx"
+#line 3443 "cmDependsJavaParser.cxx"
     break;
 
-  case 103:
-#line 930 "cmDependsJavaParser.y"
-    {
+  case 103: /* MethodDeclarator: Identifier jp_PARESTART FormalParameterListopt jp_PAREEND  */
+#line 928 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
   jpCheckEmpty(4);
@@ -3276,146 +3452,146 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3280 "cmDependsJavaParser.cxx"
+#line 3456 "cmDependsJavaParser.cxx"
     break;
 
-  case 104:
-#line 940 "cmDependsJavaParser.y"
-    {
+  case 104: /* MethodDeclarator: MethodDeclarator jp_BRACKETSTART jp_BRACKETEND  */
+#line 938 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
 
 }
-#line 3289 "cmDependsJavaParser.cxx"
+#line 3465 "cmDependsJavaParser.cxx"
     break;
 
-  case 105:
-#line 946 "cmDependsJavaParser.y"
-    {
+  case 105: /* FormalParameterListopt: %empty  */
+#line 944 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3300 "cmDependsJavaParser.cxx"
+#line 3476 "cmDependsJavaParser.cxx"
     break;
 
-  case 107:
-#line 957 "cmDependsJavaParser.y"
-    {
+  case 107: /* FormalParameterList: FormalParameter  */
+#line 955 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
 
 }
-#line 3309 "cmDependsJavaParser.cxx"
+#line 3485 "cmDependsJavaParser.cxx"
     break;
 
-  case 108:
-#line 963 "cmDependsJavaParser.y"
-    {
+  case 108: /* FormalParameterList: FormalParameterList jp_COMMA FormalParameter  */
+#line 961 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3321 "cmDependsJavaParser.cxx"
+#line 3497 "cmDependsJavaParser.cxx"
     break;
 
-  case 109:
-#line 973 "cmDependsJavaParser.y"
-    {
+  case 109: /* FormalParameter: Modifiersopt Type VariableDeclaratorId  */
+#line 971 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3333 "cmDependsJavaParser.cxx"
+#line 3509 "cmDependsJavaParser.cxx"
     break;
 
-  case 110:
-#line 983 "cmDependsJavaParser.y"
-    {
+  case 110: /* Throws: jp_THROWS ClassTypeList  */
+#line 981 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3345 "cmDependsJavaParser.cxx"
+#line 3521 "cmDependsJavaParser.cxx"
     break;
 
-  case 111:
-#line 993 "cmDependsJavaParser.y"
-    {
+  case 111: /* ClassTypeList: ClassType  */
+#line 991 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
 
 }
-#line 3354 "cmDependsJavaParser.cxx"
+#line 3530 "cmDependsJavaParser.cxx"
     break;
 
-  case 112:
-#line 999 "cmDependsJavaParser.y"
-    {
+  case 112: /* ClassTypeList: ClassTypeList jp_COMMA ClassType  */
+#line 997 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3366 "cmDependsJavaParser.cxx"
+#line 3542 "cmDependsJavaParser.cxx"
     break;
 
-  case 113:
-#line 1009 "cmDependsJavaParser.y"
-    {
+  case 113: /* MethodBody: Block  */
+#line 1007 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3378 "cmDependsJavaParser.cxx"
+#line 3554 "cmDependsJavaParser.cxx"
     break;
 
-  case 114:
-#line 1019 "cmDependsJavaParser.y"
-    {
+  case 114: /* StaticInitializer: jp_STATIC Block  */
+#line 1017 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3390 "cmDependsJavaParser.cxx"
+#line 3566 "cmDependsJavaParser.cxx"
     break;
 
-  case 115:
-#line 1029 "cmDependsJavaParser.y"
-    {
+  case 115: /* ConstructorDeclaration: Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody  */
+#line 1027 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3402 "cmDependsJavaParser.cxx"
+#line 3578 "cmDependsJavaParser.cxx"
     break;
 
-  case 116:
-#line 1038 "cmDependsJavaParser.y"
-    {
+  case 116: /* ConstructorDeclaration: Modifiersopt ConstructorDeclarator Throwsopt ConstructorBody jp_SEMICOL  */
+#line 1036 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3414 "cmDependsJavaParser.cxx"
+#line 3590 "cmDependsJavaParser.cxx"
     break;
 
-  case 117:
-#line 1048 "cmDependsJavaParser.y"
-    {
+  case 117: /* ConstructorDeclarator: SimpleName jp_PARESTART FormalParameterListopt jp_PAREEND  */
+#line 1046 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
   jpCheckEmpty(4);
@@ -3423,781 +3599,781 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3427 "cmDependsJavaParser.cxx"
+#line 3603 "cmDependsJavaParser.cxx"
     break;
 
-  case 118:
-#line 1059 "cmDependsJavaParser.y"
-    {
+  case 118: /* ConstructorBody: jp_CURLYSTART ExplicitConstructorInvocationopt BlockStatementsopt jp_CURLYEND  */
+#line 1057 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3439 "cmDependsJavaParser.cxx"
+#line 3615 "cmDependsJavaParser.cxx"
     break;
 
-  case 119:
-#line 1068 "cmDependsJavaParser.y"
-    {
+  case 119: /* ExplicitConstructorInvocationopt: %empty  */
+#line 1066 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3450 "cmDependsJavaParser.cxx"
+#line 3626 "cmDependsJavaParser.cxx"
     break;
 
-  case 120:
-#line 1076 "cmDependsJavaParser.y"
-    {
+  case 120: /* ExplicitConstructorInvocationopt: ExplicitConstructorInvocationopt ExplicitConstructorInvocation  */
+#line 1074 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3462 "cmDependsJavaParser.cxx"
+#line 3638 "cmDependsJavaParser.cxx"
     break;
 
-  case 121:
-#line 1086 "cmDependsJavaParser.y"
-    {
+  case 121: /* ExplicitConstructorInvocation: jp_THIS jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL  */
+#line 1084 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3474 "cmDependsJavaParser.cxx"
+#line 3650 "cmDependsJavaParser.cxx"
     break;
 
-  case 122:
-#line 1095 "cmDependsJavaParser.y"
-    {
+  case 122: /* ExplicitConstructorInvocation: jp_SUPER jp_PARESTART ArgumentListopt jp_PAREEND jp_SEMICOL  */
+#line 1093 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3486 "cmDependsJavaParser.cxx"
+#line 3662 "cmDependsJavaParser.cxx"
     break;
 
-  case 123:
-#line 1105 "cmDependsJavaParser.y"
-    {
+  case 123: /* InterfaceHeader: Modifiersopt jp_INTERFACE Identifier  */
+#line 1103 "cmDependsJavaParser.y"
+{
   yyGetParser->StartClass((yyvsp[0].str));
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
 }
-#line 3497 "cmDependsJavaParser.cxx"
+#line 3673 "cmDependsJavaParser.cxx"
     break;
 
-  case 124:
-#line 1114 "cmDependsJavaParser.y"
-    {
+  case 124: /* InterfaceDeclaration: InterfaceHeader ExtendsInterfacesopt InterfaceBody  */
+#line 1112 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 3509 "cmDependsJavaParser.cxx"
+#line 3685 "cmDependsJavaParser.cxx"
     break;
 
-  case 125:
-#line 1123 "cmDependsJavaParser.y"
-    {
+  case 125: /* ExtendsInterfacesopt: %empty  */
+#line 1121 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3519 "cmDependsJavaParser.cxx"
+#line 3695 "cmDependsJavaParser.cxx"
     break;
 
-  case 126:
-#line 1130 "cmDependsJavaParser.y"
-    {
+  case 126: /* ExtendsInterfacesopt: ExtendsInterfaces  */
+#line 1128 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3531 "cmDependsJavaParser.cxx"
+#line 3707 "cmDependsJavaParser.cxx"
     break;
 
-  case 127:
-#line 1140 "cmDependsJavaParser.y"
-    {
+  case 127: /* ExtendsInterfaces: jp_EXTENDS InterfaceType  */
+#line 1138 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3543 "cmDependsJavaParser.cxx"
+#line 3719 "cmDependsJavaParser.cxx"
     break;
 
-  case 128:
-#line 1149 "cmDependsJavaParser.y"
-    {
+  case 128: /* ExtendsInterfaces: ExtendsInterfaces jp_COMMA InterfaceType  */
+#line 1147 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3555 "cmDependsJavaParser.cxx"
+#line 3731 "cmDependsJavaParser.cxx"
     break;
 
-  case 129:
-#line 1159 "cmDependsJavaParser.y"
-    {
+  case 129: /* InterfaceBody: jp_CURLYSTART InterfaceMemberDeclarations jp_CURLYEND  */
+#line 1157 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3567 "cmDependsJavaParser.cxx"
+#line 3743 "cmDependsJavaParser.cxx"
     break;
 
-  case 130:
-#line 1168 "cmDependsJavaParser.y"
-    {
+  case 130: /* InterfaceMemberDeclarations: %empty  */
+#line 1166 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3578 "cmDependsJavaParser.cxx"
+#line 3754 "cmDependsJavaParser.cxx"
     break;
 
-  case 131:
-#line 1176 "cmDependsJavaParser.y"
-    {
+  case 131: /* InterfaceMemberDeclarations: InterfaceMemberDeclarations InterfaceMemberDeclaration  */
+#line 1174 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3589 "cmDependsJavaParser.cxx"
+#line 3765 "cmDependsJavaParser.cxx"
     break;
 
-  case 132:
-#line 1185 "cmDependsJavaParser.y"
-    {
+  case 132: /* InterfaceMemberDeclaration: ConstantDeclaration  */
+#line 1183 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3601 "cmDependsJavaParser.cxx"
+#line 3777 "cmDependsJavaParser.cxx"
     break;
 
-  case 133:
-#line 1194 "cmDependsJavaParser.y"
-    {
+  case 133: /* InterfaceMemberDeclaration: AbstractMethodDeclaration  */
+#line 1192 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3613 "cmDependsJavaParser.cxx"
+#line 3789 "cmDependsJavaParser.cxx"
     break;
 
-  case 134:
-#line 1203 "cmDependsJavaParser.y"
-    {
+  case 134: /* InterfaceMemberDeclaration: ClassDeclaration  */
+#line 1201 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3625 "cmDependsJavaParser.cxx"
+#line 3801 "cmDependsJavaParser.cxx"
     break;
 
-  case 135:
-#line 1212 "cmDependsJavaParser.y"
-    {
+  case 135: /* InterfaceMemberDeclaration: ClassDeclaration jp_SEMICOL  */
+#line 1210 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3636 "cmDependsJavaParser.cxx"
+#line 3812 "cmDependsJavaParser.cxx"
     break;
 
-  case 136:
-#line 1220 "cmDependsJavaParser.y"
-    {
+  case 136: /* InterfaceMemberDeclaration: InterfaceDeclaration  */
+#line 1218 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3648 "cmDependsJavaParser.cxx"
+#line 3824 "cmDependsJavaParser.cxx"
     break;
 
-  case 137:
-#line 1229 "cmDependsJavaParser.y"
-    {
+  case 137: /* InterfaceMemberDeclaration: InterfaceDeclaration jp_SEMICOL  */
+#line 1227 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3659 "cmDependsJavaParser.cxx"
+#line 3835 "cmDependsJavaParser.cxx"
     break;
 
-  case 138:
-#line 1238 "cmDependsJavaParser.y"
-    {
+  case 138: /* ConstantDeclaration: FieldDeclaration  */
+#line 1236 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3671 "cmDependsJavaParser.cxx"
+#line 3847 "cmDependsJavaParser.cxx"
     break;
 
-  case 139:
-#line 1248 "cmDependsJavaParser.y"
-    {
+  case 139: /* AbstractMethodDeclaration: MethodHeader Semicols  */
+#line 1246 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3683 "cmDependsJavaParser.cxx"
+#line 3859 "cmDependsJavaParser.cxx"
     break;
 
-  case 140:
-#line 1258 "cmDependsJavaParser.y"
-    {
+  case 140: /* Semicols: jp_SEMICOL  */
+#line 1256 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3695 "cmDependsJavaParser.cxx"
+#line 3871 "cmDependsJavaParser.cxx"
     break;
 
-  case 141:
-#line 1267 "cmDependsJavaParser.y"
-    {
+  case 141: /* Semicols: Semicols jp_SEMICOL  */
+#line 1265 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3707 "cmDependsJavaParser.cxx"
+#line 3883 "cmDependsJavaParser.cxx"
     break;
 
-  case 142:
-#line 1277 "cmDependsJavaParser.y"
-    {
+  case 142: /* ArrayInitializer: jp_CURLYSTART VariableInitializersOptional jp_CURLYEND  */
+#line 1275 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3719 "cmDependsJavaParser.cxx"
+#line 3895 "cmDependsJavaParser.cxx"
     break;
 
-  case 143:
-#line 1286 "cmDependsJavaParser.y"
-    {
+  case 143: /* VariableInitializersOptional: %empty  */
+#line 1284 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3730 "cmDependsJavaParser.cxx"
+#line 3906 "cmDependsJavaParser.cxx"
     break;
 
-  case 144:
-#line 1294 "cmDependsJavaParser.y"
-    {
+  case 144: /* VariableInitializersOptional: VariableInitializers  */
+#line 1292 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3742 "cmDependsJavaParser.cxx"
+#line 3918 "cmDependsJavaParser.cxx"
     break;
 
-  case 145:
-#line 1303 "cmDependsJavaParser.y"
-    {
+  case 145: /* VariableInitializersOptional: VariableInitializers jp_COMMA  */
+#line 1301 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3754 "cmDependsJavaParser.cxx"
+#line 3930 "cmDependsJavaParser.cxx"
     break;
 
-  case 146:
-#line 1313 "cmDependsJavaParser.y"
-    {
+  case 146: /* VariableInitializers: VariableInitializer  */
+#line 1311 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3766 "cmDependsJavaParser.cxx"
+#line 3942 "cmDependsJavaParser.cxx"
     break;
 
-  case 147:
-#line 1322 "cmDependsJavaParser.y"
-    {
+  case 147: /* VariableInitializers: VariableInitializers jp_COMMA VariableInitializer  */
+#line 1320 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3778 "cmDependsJavaParser.cxx"
+#line 3954 "cmDependsJavaParser.cxx"
     break;
 
-  case 148:
-#line 1332 "cmDependsJavaParser.y"
-    {
+  case 148: /* Block: jp_CURLYSTART BlockStatementsopt jp_CURLYEND  */
+#line 1330 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3789 "cmDependsJavaParser.cxx"
+#line 3965 "cmDependsJavaParser.cxx"
     break;
 
-  case 149:
-#line 1340 "cmDependsJavaParser.y"
-    {
+  case 149: /* BlockStatementsopt: %empty  */
+#line 1338 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3800 "cmDependsJavaParser.cxx"
+#line 3976 "cmDependsJavaParser.cxx"
     break;
 
-  case 150:
-#line 1348 "cmDependsJavaParser.y"
-    {
+  case 150: /* BlockStatementsopt: BlockStatements  */
+#line 1346 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3812 "cmDependsJavaParser.cxx"
+#line 3988 "cmDependsJavaParser.cxx"
     break;
 
-  case 151:
-#line 1358 "cmDependsJavaParser.y"
-    {
+  case 151: /* BlockStatements: BlockStatement  */
+#line 1356 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3824 "cmDependsJavaParser.cxx"
+#line 4000 "cmDependsJavaParser.cxx"
     break;
 
-  case 152:
-#line 1367 "cmDependsJavaParser.y"
-    {
+  case 152: /* BlockStatements: BlockStatements BlockStatement  */
+#line 1365 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3836 "cmDependsJavaParser.cxx"
+#line 4012 "cmDependsJavaParser.cxx"
     break;
 
-  case 153:
-#line 1377 "cmDependsJavaParser.y"
-    {
+  case 153: /* BlockStatement: LocalVariableDeclarationStatement  */
+#line 1375 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3848 "cmDependsJavaParser.cxx"
+#line 4024 "cmDependsJavaParser.cxx"
     break;
 
-  case 154:
-#line 1386 "cmDependsJavaParser.y"
-    {
+  case 154: /* BlockStatement: Statement  */
+#line 1384 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3860 "cmDependsJavaParser.cxx"
+#line 4036 "cmDependsJavaParser.cxx"
     break;
 
-  case 155:
-#line 1395 "cmDependsJavaParser.y"
-    {
+  case 155: /* BlockStatement: ClassDeclaration  */
+#line 1393 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3872 "cmDependsJavaParser.cxx"
+#line 4048 "cmDependsJavaParser.cxx"
     break;
 
-  case 156:
-#line 1405 "cmDependsJavaParser.y"
-    {
+  case 156: /* LocalVariableDeclarationStatement: LocalVariableDeclaration jp_SEMICOL  */
+#line 1403 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3884 "cmDependsJavaParser.cxx"
+#line 4060 "cmDependsJavaParser.cxx"
     break;
 
-  case 157:
-#line 1415 "cmDependsJavaParser.y"
-    {
+  case 157: /* LocalVariableDeclaration: Modifiers Type VariableDeclarators  */
+#line 1413 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3896 "cmDependsJavaParser.cxx"
+#line 4072 "cmDependsJavaParser.cxx"
     break;
 
-  case 158:
-#line 1424 "cmDependsJavaParser.y"
-    {
+  case 158: /* LocalVariableDeclaration: Type VariableDeclarators  */
+#line 1422 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3908 "cmDependsJavaParser.cxx"
+#line 4084 "cmDependsJavaParser.cxx"
     break;
 
-  case 159:
-#line 1434 "cmDependsJavaParser.y"
-    {
+  case 159: /* Statement: StatementWithoutTrailingSubstatement  */
+#line 1432 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3920 "cmDependsJavaParser.cxx"
+#line 4096 "cmDependsJavaParser.cxx"
     break;
 
-  case 160:
-#line 1443 "cmDependsJavaParser.y"
-    {
+  case 160: /* Statement: LabeledStatement  */
+#line 1441 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3932 "cmDependsJavaParser.cxx"
+#line 4108 "cmDependsJavaParser.cxx"
     break;
 
-  case 161:
-#line 1452 "cmDependsJavaParser.y"
-    {
+  case 161: /* Statement: IfThenStatement  */
+#line 1450 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3944 "cmDependsJavaParser.cxx"
+#line 4120 "cmDependsJavaParser.cxx"
     break;
 
-  case 162:
-#line 1461 "cmDependsJavaParser.y"
-    {
+  case 162: /* Statement: IfThenElseStatement  */
+#line 1459 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3956 "cmDependsJavaParser.cxx"
+#line 4132 "cmDependsJavaParser.cxx"
     break;
 
-  case 163:
-#line 1470 "cmDependsJavaParser.y"
-    {
+  case 163: /* Statement: WhileStatement  */
+#line 1468 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3968 "cmDependsJavaParser.cxx"
+#line 4144 "cmDependsJavaParser.cxx"
     break;
 
-  case 164:
-#line 1479 "cmDependsJavaParser.y"
-    {
+  case 164: /* Statement: ForStatement  */
+#line 1477 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3980 "cmDependsJavaParser.cxx"
+#line 4156 "cmDependsJavaParser.cxx"
     break;
 
-  case 165:
-#line 1489 "cmDependsJavaParser.y"
-    {
+  case 165: /* StatementNoShortIf: StatementWithoutTrailingSubstatement  */
+#line 1487 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3992 "cmDependsJavaParser.cxx"
+#line 4168 "cmDependsJavaParser.cxx"
     break;
 
-  case 166:
-#line 1498 "cmDependsJavaParser.y"
-    {
+  case 166: /* StatementNoShortIf: LabeledStatementNoShortIf  */
+#line 1496 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4004 "cmDependsJavaParser.cxx"
+#line 4180 "cmDependsJavaParser.cxx"
     break;
 
-  case 167:
-#line 1507 "cmDependsJavaParser.y"
-    {
+  case 167: /* StatementNoShortIf: IfThenElseStatementNoShortIf  */
+#line 1505 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4016 "cmDependsJavaParser.cxx"
+#line 4192 "cmDependsJavaParser.cxx"
     break;
 
-  case 168:
-#line 1516 "cmDependsJavaParser.y"
-    {
+  case 168: /* StatementNoShortIf: WhileStatementNoShortIf  */
+#line 1514 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4028 "cmDependsJavaParser.cxx"
+#line 4204 "cmDependsJavaParser.cxx"
     break;
 
-  case 169:
-#line 1525 "cmDependsJavaParser.y"
-    {
+  case 169: /* StatementNoShortIf: ForStatementNoShortIf  */
+#line 1523 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4040 "cmDependsJavaParser.cxx"
+#line 4216 "cmDependsJavaParser.cxx"
     break;
 
-  case 170:
-#line 1535 "cmDependsJavaParser.y"
-    {
+  case 170: /* StatementWithoutTrailingSubstatement: Block  */
+#line 1533 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4052 "cmDependsJavaParser.cxx"
+#line 4228 "cmDependsJavaParser.cxx"
     break;
 
-  case 171:
-#line 1544 "cmDependsJavaParser.y"
-    {
+  case 171: /* StatementWithoutTrailingSubstatement: EmptyStatement  */
+#line 1542 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4064 "cmDependsJavaParser.cxx"
+#line 4240 "cmDependsJavaParser.cxx"
     break;
 
-  case 172:
-#line 1553 "cmDependsJavaParser.y"
-    {
+  case 172: /* StatementWithoutTrailingSubstatement: ExpressionStatement  */
+#line 1551 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4076 "cmDependsJavaParser.cxx"
+#line 4252 "cmDependsJavaParser.cxx"
     break;
 
-  case 173:
-#line 1562 "cmDependsJavaParser.y"
-    {
+  case 173: /* StatementWithoutTrailingSubstatement: SwitchStatement  */
+#line 1560 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4088 "cmDependsJavaParser.cxx"
+#line 4264 "cmDependsJavaParser.cxx"
     break;
 
-  case 174:
-#line 1571 "cmDependsJavaParser.y"
-    {
+  case 174: /* StatementWithoutTrailingSubstatement: DoStatement  */
+#line 1569 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4100 "cmDependsJavaParser.cxx"
+#line 4276 "cmDependsJavaParser.cxx"
     break;
 
-  case 175:
-#line 1580 "cmDependsJavaParser.y"
-    {
+  case 175: /* StatementWithoutTrailingSubstatement: BreakStatement  */
+#line 1578 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4112 "cmDependsJavaParser.cxx"
+#line 4288 "cmDependsJavaParser.cxx"
     break;
 
-  case 176:
-#line 1589 "cmDependsJavaParser.y"
-    {
+  case 176: /* StatementWithoutTrailingSubstatement: ContinueStatement  */
+#line 1587 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4124 "cmDependsJavaParser.cxx"
+#line 4300 "cmDependsJavaParser.cxx"
     break;
 
-  case 177:
-#line 1598 "cmDependsJavaParser.y"
-    {
+  case 177: /* StatementWithoutTrailingSubstatement: ReturnStatement  */
+#line 1596 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4136 "cmDependsJavaParser.cxx"
+#line 4312 "cmDependsJavaParser.cxx"
     break;
 
-  case 178:
-#line 1607 "cmDependsJavaParser.y"
-    {
+  case 178: /* StatementWithoutTrailingSubstatement: SynchronizedStatement  */
+#line 1605 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4148 "cmDependsJavaParser.cxx"
+#line 4324 "cmDependsJavaParser.cxx"
     break;
 
-  case 179:
-#line 1616 "cmDependsJavaParser.y"
-    {
+  case 179: /* StatementWithoutTrailingSubstatement: ThrowStatement  */
+#line 1614 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4160 "cmDependsJavaParser.cxx"
+#line 4336 "cmDependsJavaParser.cxx"
     break;
 
-  case 180:
-#line 1625 "cmDependsJavaParser.y"
-    {
+  case 180: /* StatementWithoutTrailingSubstatement: TryStatement  */
+#line 1623 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4172 "cmDependsJavaParser.cxx"
+#line 4348 "cmDependsJavaParser.cxx"
     break;
 
-  case 181:
-#line 1634 "cmDependsJavaParser.y"
-    {
+  case 181: /* StatementWithoutTrailingSubstatement: AssertStatement  */
+#line 1632 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4184 "cmDependsJavaParser.cxx"
+#line 4360 "cmDependsJavaParser.cxx"
     break;
 
-  case 182:
-#line 1644 "cmDependsJavaParser.y"
-    {
+  case 182: /* EmptyStatement: jp_SEMICOL  */
+#line 1642 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4196 "cmDependsJavaParser.cxx"
+#line 4372 "cmDependsJavaParser.cxx"
     break;
 
-  case 183:
-#line 1654 "cmDependsJavaParser.y"
-    {
+  case 183: /* LabeledStatement: Identifier jp_COLON Statement  */
+#line 1652 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[-2].str)));
   jpCheckEmpty(3);
@@ -4205,480 +4381,480 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4209 "cmDependsJavaParser.cxx"
+#line 4385 "cmDependsJavaParser.cxx"
     break;
 
-  case 184:
-#line 1665 "cmDependsJavaParser.y"
-    {
+  case 184: /* LabeledStatementNoShortIf: Identifier jp_COLON StatementNoShortIf  */
+#line 1663 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4221 "cmDependsJavaParser.cxx"
+#line 4397 "cmDependsJavaParser.cxx"
     break;
 
-  case 185:
-#line 1675 "cmDependsJavaParser.y"
-    {
+  case 185: /* ExpressionStatement: StatementExpression jp_SEMICOL  */
+#line 1673 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4233 "cmDependsJavaParser.cxx"
+#line 4409 "cmDependsJavaParser.cxx"
     break;
 
-  case 186:
-#line 1685 "cmDependsJavaParser.y"
-    {
+  case 186: /* StatementExpression: Assignment  */
+#line 1683 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4245 "cmDependsJavaParser.cxx"
+#line 4421 "cmDependsJavaParser.cxx"
     break;
 
-  case 187:
-#line 1694 "cmDependsJavaParser.y"
-    {
+  case 187: /* StatementExpression: PreIncrementExpression  */
+#line 1692 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4257 "cmDependsJavaParser.cxx"
+#line 4433 "cmDependsJavaParser.cxx"
     break;
 
-  case 188:
-#line 1703 "cmDependsJavaParser.y"
-    {
+  case 188: /* StatementExpression: PreDecrementExpression  */
+#line 1701 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4269 "cmDependsJavaParser.cxx"
+#line 4445 "cmDependsJavaParser.cxx"
     break;
 
-  case 189:
-#line 1712 "cmDependsJavaParser.y"
-    {
+  case 189: /* StatementExpression: PostIncrementExpression  */
+#line 1710 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4281 "cmDependsJavaParser.cxx"
+#line 4457 "cmDependsJavaParser.cxx"
     break;
 
-  case 190:
-#line 1721 "cmDependsJavaParser.y"
-    {
+  case 190: /* StatementExpression: PostDecrementExpression  */
+#line 1719 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4293 "cmDependsJavaParser.cxx"
+#line 4469 "cmDependsJavaParser.cxx"
     break;
 
-  case 191:
-#line 1730 "cmDependsJavaParser.y"
-    {
+  case 191: /* StatementExpression: MethodInvocation  */
+#line 1728 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4305 "cmDependsJavaParser.cxx"
+#line 4481 "cmDependsJavaParser.cxx"
     break;
 
-  case 192:
-#line 1739 "cmDependsJavaParser.y"
-    {
+  case 192: /* StatementExpression: ClassInstanceCreationExpression  */
+#line 1737 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4317 "cmDependsJavaParser.cxx"
+#line 4493 "cmDependsJavaParser.cxx"
     break;
 
-  case 193:
-#line 1749 "cmDependsJavaParser.y"
-    {
+  case 193: /* IfThenStatement: jp_IF jp_PARESTART Expression jp_PAREEND Statement  */
+#line 1747 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4329 "cmDependsJavaParser.cxx"
+#line 4505 "cmDependsJavaParser.cxx"
     break;
 
-  case 194:
-#line 1759 "cmDependsJavaParser.y"
-    {
+  case 194: /* IfThenElseStatement: jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE Statement  */
+#line 1757 "cmDependsJavaParser.y"
+{
   jpElementStart(7);
   jpCheckEmpty(7);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4341 "cmDependsJavaParser.cxx"
+#line 4517 "cmDependsJavaParser.cxx"
     break;
 
-  case 195:
-#line 1769 "cmDependsJavaParser.y"
-    {
+  case 195: /* IfThenElseStatementNoShortIf: jp_IF jp_PARESTART Expression jp_PAREEND StatementNoShortIf jp_ELSE StatementNoShortIf  */
+#line 1767 "cmDependsJavaParser.y"
+{
   jpElementStart(7);
   jpCheckEmpty(7);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4353 "cmDependsJavaParser.cxx"
+#line 4529 "cmDependsJavaParser.cxx"
     break;
 
-  case 196:
-#line 1779 "cmDependsJavaParser.y"
-    {
+  case 196: /* SwitchStatement: jp_SWITCH jp_PARESTART Expression jp_PAREEND SwitchBlock  */
+#line 1777 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
 
 }
-#line 4362 "cmDependsJavaParser.cxx"
+#line 4538 "cmDependsJavaParser.cxx"
     break;
 
-  case 197:
-#line 1786 "cmDependsJavaParser.y"
-    {
+  case 197: /* SwitchBlock: jp_CURLYSTART SwitchBlockStatementGroups SwitchLabelsopt jp_CURLYEND  */
+#line 1784 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
 
 }
-#line 4371 "cmDependsJavaParser.cxx"
+#line 4547 "cmDependsJavaParser.cxx"
     break;
 
-  case 198:
-#line 1792 "cmDependsJavaParser.y"
-    {
+  case 198: /* SwitchLabelsopt: %empty  */
+#line 1790 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4382 "cmDependsJavaParser.cxx"
+#line 4558 "cmDependsJavaParser.cxx"
     break;
 
-  case 199:
-#line 1800 "cmDependsJavaParser.y"
-    {
+  case 199: /* SwitchLabelsopt: SwitchLabels  */
+#line 1798 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4394 "cmDependsJavaParser.cxx"
+#line 4570 "cmDependsJavaParser.cxx"
     break;
 
-  case 200:
-#line 1809 "cmDependsJavaParser.y"
-    {
+  case 200: /* SwitchBlockStatementGroups: %empty  */
+#line 1807 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4405 "cmDependsJavaParser.cxx"
+#line 4581 "cmDependsJavaParser.cxx"
     break;
 
-  case 201:
-#line 1817 "cmDependsJavaParser.y"
-    {
+  case 201: /* SwitchBlockStatementGroups: SwitchBlockStatementGroups SwitchBlockStatementGroup  */
+#line 1815 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4417 "cmDependsJavaParser.cxx"
+#line 4593 "cmDependsJavaParser.cxx"
     break;
 
-  case 202:
-#line 1827 "cmDependsJavaParser.y"
-    {
+  case 202: /* SwitchBlockStatementGroup: SwitchLabels BlockStatements  */
+#line 1825 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4429 "cmDependsJavaParser.cxx"
+#line 4605 "cmDependsJavaParser.cxx"
     break;
 
-  case 203:
-#line 1837 "cmDependsJavaParser.y"
-    {
+  case 203: /* SwitchLabels: SwitchLabel  */
+#line 1835 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4441 "cmDependsJavaParser.cxx"
+#line 4617 "cmDependsJavaParser.cxx"
     break;
 
-  case 204:
-#line 1846 "cmDependsJavaParser.y"
-    {
+  case 204: /* SwitchLabels: SwitchLabels SwitchLabel  */
+#line 1844 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4453 "cmDependsJavaParser.cxx"
+#line 4629 "cmDependsJavaParser.cxx"
     break;
 
-  case 205:
-#line 1856 "cmDependsJavaParser.y"
-    {
+  case 205: /* SwitchLabel: jp_CASE ConstantExpression jp_COLON  */
+#line 1854 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4465 "cmDependsJavaParser.cxx"
+#line 4641 "cmDependsJavaParser.cxx"
     break;
 
-  case 206:
-#line 1865 "cmDependsJavaParser.y"
-    {
+  case 206: /* SwitchLabel: jp_DEFAULT jp_COLON  */
+#line 1863 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4477 "cmDependsJavaParser.cxx"
+#line 4653 "cmDependsJavaParser.cxx"
     break;
 
-  case 207:
-#line 1875 "cmDependsJavaParser.y"
-    {
+  case 207: /* WhileStatement: jp_WHILE jp_PARESTART Expression jp_PAREEND Statement  */
+#line 1873 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
 
 }
-#line 4486 "cmDependsJavaParser.cxx"
+#line 4662 "cmDependsJavaParser.cxx"
     break;
 
-  case 208:
-#line 1882 "cmDependsJavaParser.y"
-    {
+  case 208: /* WhileStatementNoShortIf: jp_WHILE jp_PARESTART Expression jp_PAREEND StatementNoShortIf  */
+#line 1880 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
 
 }
-#line 4495 "cmDependsJavaParser.cxx"
+#line 4671 "cmDependsJavaParser.cxx"
     break;
 
-  case 209:
-#line 1889 "cmDependsJavaParser.y"
-    {
+  case 209: /* DoStatement: jp_DO Statement jp_WHILE jp_PARESTART Expression jp_PAREEND jp_SEMICOL  */
+#line 1887 "cmDependsJavaParser.y"
+{
   jpElementStart(7);
 
 }
-#line 4504 "cmDependsJavaParser.cxx"
+#line 4680 "cmDependsJavaParser.cxx"
     break;
 
-  case 210:
-#line 1897 "cmDependsJavaParser.y"
-    {
+  case 210: /* ForStatement: jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND Statement  */
+#line 1895 "cmDependsJavaParser.y"
+{
   jpElementStart(9);
 
 }
-#line 4513 "cmDependsJavaParser.cxx"
+#line 4689 "cmDependsJavaParser.cxx"
     break;
 
-  case 211:
-#line 1903 "cmDependsJavaParser.y"
-    {
+  case 211: /* ForUpdateopt: %empty  */
+#line 1901 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4524 "cmDependsJavaParser.cxx"
+#line 4700 "cmDependsJavaParser.cxx"
     break;
 
-  case 212:
-#line 1911 "cmDependsJavaParser.y"
-    {
+  case 212: /* ForUpdateopt: ForUpdate  */
+#line 1909 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4536 "cmDependsJavaParser.cxx"
+#line 4712 "cmDependsJavaParser.cxx"
     break;
 
-  case 213:
-#line 1920 "cmDependsJavaParser.y"
-    {
+  case 213: /* ForInitopt: %empty  */
+#line 1918 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4547 "cmDependsJavaParser.cxx"
+#line 4723 "cmDependsJavaParser.cxx"
     break;
 
-  case 214:
-#line 1928 "cmDependsJavaParser.y"
-    {
+  case 214: /* ForInitopt: ForInit  */
+#line 1926 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4559 "cmDependsJavaParser.cxx"
+#line 4735 "cmDependsJavaParser.cxx"
     break;
 
-  case 215:
-#line 1939 "cmDependsJavaParser.y"
-    {
+  case 215: /* ForStatementNoShortIf: jp_FOR jp_PARESTART ForInitopt jp_SEMICOL Expressionopt jp_SEMICOL ForUpdateopt jp_PAREEND StatementNoShortIf  */
+#line 1937 "cmDependsJavaParser.y"
+{
   jpElementStart(9);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4570 "cmDependsJavaParser.cxx"
+#line 4746 "cmDependsJavaParser.cxx"
     break;
 
-  case 216:
-#line 1947 "cmDependsJavaParser.y"
-    {
+  case 216: /* Expressionopt: %empty  */
+#line 1945 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4581 "cmDependsJavaParser.cxx"
+#line 4757 "cmDependsJavaParser.cxx"
     break;
 
-  case 217:
-#line 1955 "cmDependsJavaParser.y"
-    {
+  case 217: /* Expressionopt: Expression  */
+#line 1953 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4593 "cmDependsJavaParser.cxx"
+#line 4769 "cmDependsJavaParser.cxx"
     break;
 
-  case 218:
-#line 1965 "cmDependsJavaParser.y"
-    {
+  case 218: /* ForInit: StatementExpressionList  */
+#line 1963 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4605 "cmDependsJavaParser.cxx"
+#line 4781 "cmDependsJavaParser.cxx"
     break;
 
-  case 219:
-#line 1974 "cmDependsJavaParser.y"
-    {
+  case 219: /* ForInit: LocalVariableDeclaration  */
+#line 1972 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4617 "cmDependsJavaParser.cxx"
+#line 4793 "cmDependsJavaParser.cxx"
     break;
 
-  case 220:
-#line 1984 "cmDependsJavaParser.y"
-    {
+  case 220: /* ForUpdate: StatementExpressionList  */
+#line 1982 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4629 "cmDependsJavaParser.cxx"
+#line 4805 "cmDependsJavaParser.cxx"
     break;
 
-  case 221:
-#line 1994 "cmDependsJavaParser.y"
-    {
+  case 221: /* StatementExpressionList: StatementExpression  */
+#line 1992 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4641 "cmDependsJavaParser.cxx"
+#line 4817 "cmDependsJavaParser.cxx"
     break;
 
-  case 222:
-#line 2003 "cmDependsJavaParser.y"
-    {
+  case 222: /* StatementExpressionList: StatementExpressionList jp_COMMA StatementExpression  */
+#line 2001 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4653 "cmDependsJavaParser.cxx"
+#line 4829 "cmDependsJavaParser.cxx"
     break;
 
-  case 223:
-#line 2013 "cmDependsJavaParser.y"
-    {
+  case 223: /* AssertStatement: jp_ASSERT Expression jp_SEMICOL  */
+#line 2011 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4665 "cmDependsJavaParser.cxx"
+#line 4841 "cmDependsJavaParser.cxx"
     break;
 
-  case 224:
-#line 2022 "cmDependsJavaParser.y"
-    {
+  case 224: /* AssertStatement: jp_ASSERT Expression jp_COLON Expression jp_SEMICOL  */
+#line 2020 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4677 "cmDependsJavaParser.cxx"
+#line 4853 "cmDependsJavaParser.cxx"
     break;
 
-  case 225:
-#line 2032 "cmDependsJavaParser.y"
-    {
+  case 225: /* BreakStatement: jp_BREAK Identifieropt jp_SEMICOL  */
+#line 2030 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
   jpCheckEmpty(3);
@@ -4686,32 +4862,32 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4690 "cmDependsJavaParser.cxx"
+#line 4866 "cmDependsJavaParser.cxx"
     break;
 
-  case 226:
-#line 2042 "cmDependsJavaParser.y"
-    {
+  case 226: /* Identifieropt: %empty  */
+#line 2040 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4701 "cmDependsJavaParser.cxx"
+#line 4877 "cmDependsJavaParser.cxx"
     break;
 
-  case 227:
-#line 2050 "cmDependsJavaParser.y"
-    {
+  case 227: /* Identifieropt: Identifier  */
+#line 2048 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
 
 }
-#line 4710 "cmDependsJavaParser.cxx"
+#line 4886 "cmDependsJavaParser.cxx"
     break;
 
-  case 228:
-#line 2057 "cmDependsJavaParser.y"
-    {
+  case 228: /* ContinueStatement: jp_CONTINUE Identifieropt jp_SEMICOL  */
+#line 2055 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
   jpCheckEmpty(3);
@@ -4719,452 +4895,452 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4723 "cmDependsJavaParser.cxx"
+#line 4899 "cmDependsJavaParser.cxx"
     break;
 
-  case 229:
-#line 2068 "cmDependsJavaParser.y"
-    {
+  case 229: /* ReturnStatement: jp_RETURN Expressionopt jp_SEMICOL  */
+#line 2066 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4735 "cmDependsJavaParser.cxx"
+#line 4911 "cmDependsJavaParser.cxx"
     break;
 
-  case 230:
-#line 2078 "cmDependsJavaParser.y"
-    {
+  case 230: /* ThrowStatement: jp_THROW Expression jp_SEMICOL  */
+#line 2076 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4747 "cmDependsJavaParser.cxx"
+#line 4923 "cmDependsJavaParser.cxx"
     break;
 
-  case 231:
-#line 2088 "cmDependsJavaParser.y"
-    {
+  case 231: /* SynchronizedStatement: jp_SYNCHRONIZED jp_PARESTART Expression jp_PAREEND Block  */
+#line 2086 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4759 "cmDependsJavaParser.cxx"
+#line 4935 "cmDependsJavaParser.cxx"
     break;
 
-  case 232:
-#line 2098 "cmDependsJavaParser.y"
-    {
+  case 232: /* TryStatement: jp_TRY Block Catches  */
+#line 2096 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4771 "cmDependsJavaParser.cxx"
+#line 4947 "cmDependsJavaParser.cxx"
     break;
 
-  case 233:
-#line 2107 "cmDependsJavaParser.y"
-    {
+  case 233: /* TryStatement: jp_TRY Block Catchesopt Finally  */
+#line 2105 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4783 "cmDependsJavaParser.cxx"
+#line 4959 "cmDependsJavaParser.cxx"
     break;
 
-  case 234:
-#line 2116 "cmDependsJavaParser.y"
-    {
+  case 234: /* Catchesopt: %empty  */
+#line 2114 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4794 "cmDependsJavaParser.cxx"
+#line 4970 "cmDependsJavaParser.cxx"
     break;
 
-  case 235:
-#line 2124 "cmDependsJavaParser.y"
-    {
+  case 235: /* Catchesopt: Catches  */
+#line 2122 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4806 "cmDependsJavaParser.cxx"
+#line 4982 "cmDependsJavaParser.cxx"
     break;
 
-  case 236:
-#line 2134 "cmDependsJavaParser.y"
-    {
+  case 236: /* Catches: CatchClause  */
+#line 2132 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4818 "cmDependsJavaParser.cxx"
+#line 4994 "cmDependsJavaParser.cxx"
     break;
 
-  case 237:
-#line 2143 "cmDependsJavaParser.y"
-    {
+  case 237: /* Catches: Catches CatchClause  */
+#line 2141 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4830 "cmDependsJavaParser.cxx"
+#line 5006 "cmDependsJavaParser.cxx"
     break;
 
-  case 238:
-#line 2153 "cmDependsJavaParser.y"
-    {
+  case 238: /* CatchClause: jp_CATCH jp_PARESTART FormalParameter jp_PAREEND Block  */
+#line 2151 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
 
 }
-#line 4839 "cmDependsJavaParser.cxx"
+#line 5015 "cmDependsJavaParser.cxx"
     break;
 
-  case 239:
-#line 2160 "cmDependsJavaParser.y"
-    {
+  case 239: /* Finally: jp_FINALLY Block  */
+#line 2158 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4851 "cmDependsJavaParser.cxx"
+#line 5027 "cmDependsJavaParser.cxx"
     break;
 
-  case 240:
-#line 2170 "cmDependsJavaParser.y"
-    {
+  case 240: /* Primary: PrimaryNoNewArray  */
+#line 2168 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4863 "cmDependsJavaParser.cxx"
+#line 5039 "cmDependsJavaParser.cxx"
     break;
 
-  case 241:
-#line 2179 "cmDependsJavaParser.y"
-    {
+  case 241: /* Primary: ArrayCreationExpression  */
+#line 2177 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4875 "cmDependsJavaParser.cxx"
+#line 5051 "cmDependsJavaParser.cxx"
     break;
 
-  case 242:
-#line 2189 "cmDependsJavaParser.y"
-    {
+  case 242: /* PrimaryNoNewArray: Literal  */
+#line 2187 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4887 "cmDependsJavaParser.cxx"
+#line 5063 "cmDependsJavaParser.cxx"
     break;
 
-  case 243:
-#line 2198 "cmDependsJavaParser.y"
-    {
+  case 243: /* PrimaryNoNewArray: jp_THIS  */
+#line 2196 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
 
 }
-#line 4896 "cmDependsJavaParser.cxx"
+#line 5072 "cmDependsJavaParser.cxx"
     break;
 
-  case 244:
-#line 2204 "cmDependsJavaParser.y"
-    {
+  case 244: /* PrimaryNoNewArray: jp_PARESTART Expression jp_PAREEND  */
+#line 2202 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4908 "cmDependsJavaParser.cxx"
+#line 5084 "cmDependsJavaParser.cxx"
     break;
 
-  case 245:
-#line 2213 "cmDependsJavaParser.y"
-    {
+  case 245: /* PrimaryNoNewArray: ClassInstanceCreationExpression  */
+#line 2211 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4920 "cmDependsJavaParser.cxx"
+#line 5096 "cmDependsJavaParser.cxx"
     break;
 
-  case 246:
-#line 2222 "cmDependsJavaParser.y"
-    {
+  case 246: /* PrimaryNoNewArray: FieldAccess  */
+#line 2220 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4932 "cmDependsJavaParser.cxx"
+#line 5108 "cmDependsJavaParser.cxx"
     break;
 
-  case 247:
-#line 2231 "cmDependsJavaParser.y"
-    {
+  case 247: /* PrimaryNoNewArray: MethodInvocation  */
+#line 2229 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4944 "cmDependsJavaParser.cxx"
+#line 5120 "cmDependsJavaParser.cxx"
     break;
 
-  case 248:
-#line 2240 "cmDependsJavaParser.y"
-    {
+  case 248: /* PrimaryNoNewArray: ArrayAccess  */
+#line 2238 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4956 "cmDependsJavaParser.cxx"
+#line 5132 "cmDependsJavaParser.cxx"
     break;
 
-  case 249:
-#line 2250 "cmDependsJavaParser.y"
-    {
+  case 249: /* ClassInstanceCreationExpression: New ClassType jp_PARESTART ArgumentListopt jp_PAREEND ClassBodyOpt  */
+#line 2248 "cmDependsJavaParser.y"
+{
   jpElementStart(6);
   jpCheckEmpty(6);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4968 "cmDependsJavaParser.cxx"
+#line 5144 "cmDependsJavaParser.cxx"
     break;
 
-  case 250:
-#line 2259 "cmDependsJavaParser.y"
-    {
+  case 250: /* ClassBodyOpt: %empty  */
+#line 2257 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4979 "cmDependsJavaParser.cxx"
+#line 5155 "cmDependsJavaParser.cxx"
     break;
 
-  case 251:
-#line 2267 "cmDependsJavaParser.y"
-    {
+  case 251: /* ClassBodyOpt: ClassBody  */
+#line 2265 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4991 "cmDependsJavaParser.cxx"
+#line 5167 "cmDependsJavaParser.cxx"
     break;
 
-  case 252:
-#line 2276 "cmDependsJavaParser.y"
-    {
+  case 252: /* ArgumentListopt: %empty  */
+#line 2274 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5002 "cmDependsJavaParser.cxx"
+#line 5178 "cmDependsJavaParser.cxx"
     break;
 
-  case 253:
-#line 2284 "cmDependsJavaParser.y"
-    {
+  case 253: /* ArgumentListopt: ArgumentList  */
+#line 2282 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5014 "cmDependsJavaParser.cxx"
+#line 5190 "cmDependsJavaParser.cxx"
     break;
 
-  case 254:
-#line 2294 "cmDependsJavaParser.y"
-    {
+  case 254: /* ArgumentList: Expression  */
+#line 2292 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5026 "cmDependsJavaParser.cxx"
+#line 5202 "cmDependsJavaParser.cxx"
     break;
 
-  case 255:
-#line 2303 "cmDependsJavaParser.y"
-    {
+  case 255: /* ArgumentList: ArgumentList jp_COMMA Expression  */
+#line 2301 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5038 "cmDependsJavaParser.cxx"
+#line 5214 "cmDependsJavaParser.cxx"
     break;
 
-  case 256:
-#line 2313 "cmDependsJavaParser.y"
-    {
+  case 256: /* ArrayCreationExpression: New PrimitiveType DimExprs Dimsopt  */
+#line 2311 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5050 "cmDependsJavaParser.cxx"
+#line 5226 "cmDependsJavaParser.cxx"
     break;
 
-  case 257:
-#line 2322 "cmDependsJavaParser.y"
-    {
+  case 257: /* ArrayCreationExpression: New ClassOrInterfaceType DimExprs Dimsopt  */
+#line 2320 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5062 "cmDependsJavaParser.cxx"
+#line 5238 "cmDependsJavaParser.cxx"
     break;
 
-  case 258:
-#line 2331 "cmDependsJavaParser.y"
-    {
+  case 258: /* ArrayCreationExpression: New PrimitiveType Dims ArrayInitializer  */
+#line 2329 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5074 "cmDependsJavaParser.cxx"
+#line 5250 "cmDependsJavaParser.cxx"
     break;
 
-  case 259:
-#line 2340 "cmDependsJavaParser.y"
-    {
+  case 259: /* ArrayCreationExpression: New ClassOrInterfaceType Dims ArrayInitializer  */
+#line 2338 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5086 "cmDependsJavaParser.cxx"
+#line 5262 "cmDependsJavaParser.cxx"
     break;
 
-  case 260:
-#line 2349 "cmDependsJavaParser.y"
-    {
+  case 260: /* Dimsopt: %empty  */
+#line 2347 "cmDependsJavaParser.y"
+{
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5097 "cmDependsJavaParser.cxx"
+#line 5273 "cmDependsJavaParser.cxx"
     break;
 
-  case 261:
-#line 2357 "cmDependsJavaParser.y"
-    {
+  case 261: /* Dimsopt: Dims  */
+#line 2355 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5109 "cmDependsJavaParser.cxx"
+#line 5285 "cmDependsJavaParser.cxx"
     break;
 
-  case 262:
-#line 2367 "cmDependsJavaParser.y"
-    {
+  case 262: /* DimExprs: DimExpr  */
+#line 2365 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5121 "cmDependsJavaParser.cxx"
+#line 5297 "cmDependsJavaParser.cxx"
     break;
 
-  case 263:
-#line 2376 "cmDependsJavaParser.y"
-    {
+  case 263: /* DimExprs: DimExprs DimExpr  */
+#line 2374 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5133 "cmDependsJavaParser.cxx"
+#line 5309 "cmDependsJavaParser.cxx"
     break;
 
-  case 264:
-#line 2386 "cmDependsJavaParser.y"
-    {
+  case 264: /* DimExpr: jp_BRACKETSTART Expression jp_BRACKETEND  */
+#line 2384 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5145 "cmDependsJavaParser.cxx"
+#line 5321 "cmDependsJavaParser.cxx"
     break;
 
-  case 265:
-#line 2396 "cmDependsJavaParser.y"
-    {
+  case 265: /* Dims: jp_BRACKETSTART jp_BRACKETEND  */
+#line 2394 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
 
 }
-#line 5154 "cmDependsJavaParser.cxx"
+#line 5330 "cmDependsJavaParser.cxx"
     break;
 
-  case 266:
-#line 2402 "cmDependsJavaParser.y"
-    {
+  case 266: /* Dims: Dims jp_BRACKETSTART jp_BRACKETEND  */
+#line 2400 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
 
 }
-#line 5163 "cmDependsJavaParser.cxx"
+#line 5339 "cmDependsJavaParser.cxx"
     break;
 
-  case 267:
-#line 2409 "cmDependsJavaParser.y"
-    {
+  case 267: /* FieldAccess: Primary jp_DOT Identifier  */
+#line 2407 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
@@ -5172,12 +5348,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5176 "cmDependsJavaParser.cxx"
+#line 5352 "cmDependsJavaParser.cxx"
     break;
 
-  case 268:
-#line 2419 "cmDependsJavaParser.y"
-    {
+  case 268: /* FieldAccess: jp_SUPER jp_DOT Identifier  */
+#line 2417 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
@@ -5185,12 +5361,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5189 "cmDependsJavaParser.cxx"
+#line 5365 "cmDependsJavaParser.cxx"
     break;
 
-  case 269:
-#line 2429 "cmDependsJavaParser.y"
-    {
+  case 269: /* FieldAccess: jp_THIS jp_DOT Identifier  */
+#line 2427 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
@@ -5198,12 +5374,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5202 "cmDependsJavaParser.cxx"
+#line 5378 "cmDependsJavaParser.cxx"
     break;
 
-  case 270:
-#line 2439 "cmDependsJavaParser.y"
-    {
+  case 270: /* FieldAccess: Primary jp_DOT jp_THIS  */
+#line 2437 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
@@ -5211,12 +5387,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5215 "cmDependsJavaParser.cxx"
+#line 5391 "cmDependsJavaParser.cxx"
     break;
 
-  case 271:
-#line 2450 "cmDependsJavaParser.y"
-    {
+  case 271: /* MethodInvocation: Name jp_PARESTART ArgumentListopt jp_PAREEND  */
+#line 2448 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
   jpCheckEmpty(4);
@@ -5224,12 +5400,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5228 "cmDependsJavaParser.cxx"
+#line 5404 "cmDependsJavaParser.cxx"
     break;
 
-  case 272:
-#line 2460 "cmDependsJavaParser.y"
-    {
+  case 272: /* MethodInvocation: Primary jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND  */
+#line 2458 "cmDependsJavaParser.y"
+{
   jpElementStart(6);
   yyGetParser->DeallocateParserType(&((yyvsp[-5].str)));
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
@@ -5238,12 +5414,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5242 "cmDependsJavaParser.cxx"
+#line 5418 "cmDependsJavaParser.cxx"
     break;
 
-  case 273:
-#line 2471 "cmDependsJavaParser.y"
-    {
+  case 273: /* MethodInvocation: jp_SUPER jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND  */
+#line 2469 "cmDependsJavaParser.y"
+{
   jpElementStart(6);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
   jpCheckEmpty(6);
@@ -5251,12 +5427,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5255 "cmDependsJavaParser.cxx"
+#line 5431 "cmDependsJavaParser.cxx"
     break;
 
-  case 274:
-#line 2481 "cmDependsJavaParser.y"
-    {
+  case 274: /* MethodInvocation: jp_THIS jp_DOT Identifier jp_PARESTART ArgumentListopt jp_PAREEND  */
+#line 2479 "cmDependsJavaParser.y"
+{
   jpElementStart(6);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
   jpCheckEmpty(6);
@@ -5264,12 +5440,12 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5268 "cmDependsJavaParser.cxx"
+#line 5444 "cmDependsJavaParser.cxx"
     break;
 
-  case 275:
-#line 2492 "cmDependsJavaParser.y"
-    {
+  case 275: /* ArrayAccess: Name jp_BRACKETSTART Expression jp_BRACKETEND  */
+#line 2490 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
   jpCheckEmpty(4);
@@ -5277,693 +5453,693 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5281 "cmDependsJavaParser.cxx"
+#line 5457 "cmDependsJavaParser.cxx"
     break;
 
-  case 276:
-#line 2502 "cmDependsJavaParser.y"
-    {
+  case 276: /* ArrayAccess: PrimaryNoNewArray jp_BRACKETSTART Expression jp_BRACKETEND  */
+#line 2500 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5293 "cmDependsJavaParser.cxx"
+#line 5469 "cmDependsJavaParser.cxx"
     break;
 
-  case 277:
-#line 2512 "cmDependsJavaParser.y"
-    {
+  case 277: /* PostfixExpression: Primary  */
+#line 2510 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5305 "cmDependsJavaParser.cxx"
+#line 5481 "cmDependsJavaParser.cxx"
     break;
 
-  case 278:
-#line 2521 "cmDependsJavaParser.y"
-    {
+  case 278: /* PostfixExpression: Name  */
+#line 2519 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5317 "cmDependsJavaParser.cxx"
+#line 5493 "cmDependsJavaParser.cxx"
     break;
 
-  case 279:
-#line 2530 "cmDependsJavaParser.y"
-    {
+  case 279: /* PostfixExpression: ArrayType jp_DOT jp_CLASS  */
+#line 2528 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5329 "cmDependsJavaParser.cxx"
+#line 5505 "cmDependsJavaParser.cxx"
     break;
 
-  case 280:
-#line 2539 "cmDependsJavaParser.y"
-    {
+  case 280: /* PostfixExpression: PostIncrementExpression  */
+#line 2537 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5341 "cmDependsJavaParser.cxx"
+#line 5517 "cmDependsJavaParser.cxx"
     break;
 
-  case 281:
-#line 2548 "cmDependsJavaParser.y"
-    {
+  case 281: /* PostfixExpression: PostDecrementExpression  */
+#line 2546 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5353 "cmDependsJavaParser.cxx"
+#line 5529 "cmDependsJavaParser.cxx"
     break;
 
-  case 282:
-#line 2558 "cmDependsJavaParser.y"
-    {
+  case 282: /* PostIncrementExpression: PostfixExpression jp_PLUSPLUS  */
+#line 2556 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5365 "cmDependsJavaParser.cxx"
+#line 5541 "cmDependsJavaParser.cxx"
     break;
 
-  case 283:
-#line 2568 "cmDependsJavaParser.y"
-    {
+  case 283: /* PostDecrementExpression: PostfixExpression jp_MINUSMINUS  */
+#line 2566 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5377 "cmDependsJavaParser.cxx"
+#line 5553 "cmDependsJavaParser.cxx"
     break;
 
-  case 284:
-#line 2578 "cmDependsJavaParser.y"
-    {
+  case 284: /* UnaryExpression: PreIncrementExpression  */
+#line 2576 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5389 "cmDependsJavaParser.cxx"
+#line 5565 "cmDependsJavaParser.cxx"
     break;
 
-  case 285:
-#line 2587 "cmDependsJavaParser.y"
-    {
+  case 285: /* UnaryExpression: PreDecrementExpression  */
+#line 2585 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5401 "cmDependsJavaParser.cxx"
+#line 5577 "cmDependsJavaParser.cxx"
     break;
 
-  case 286:
-#line 2596 "cmDependsJavaParser.y"
-    {
+  case 286: /* UnaryExpression: jp_PLUS UnaryExpression  */
+#line 2594 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5413 "cmDependsJavaParser.cxx"
+#line 5589 "cmDependsJavaParser.cxx"
     break;
 
-  case 287:
-#line 2605 "cmDependsJavaParser.y"
-    {
+  case 287: /* UnaryExpression: jp_MINUS UnaryExpression  */
+#line 2603 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5425 "cmDependsJavaParser.cxx"
+#line 5601 "cmDependsJavaParser.cxx"
     break;
 
-  case 288:
-#line 2614 "cmDependsJavaParser.y"
-    {
+  case 288: /* UnaryExpression: UnaryExpressionNotPlusMinus  */
+#line 2612 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5437 "cmDependsJavaParser.cxx"
+#line 5613 "cmDependsJavaParser.cxx"
     break;
 
-  case 289:
-#line 2624 "cmDependsJavaParser.y"
-    {
+  case 289: /* PreIncrementExpression: jp_PLUSPLUS UnaryExpression  */
+#line 2622 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5449 "cmDependsJavaParser.cxx"
+#line 5625 "cmDependsJavaParser.cxx"
     break;
 
-  case 290:
-#line 2634 "cmDependsJavaParser.y"
-    {
+  case 290: /* PreDecrementExpression: jp_MINUSMINUS UnaryExpression  */
+#line 2632 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5461 "cmDependsJavaParser.cxx"
+#line 5637 "cmDependsJavaParser.cxx"
     break;
 
-  case 291:
-#line 2644 "cmDependsJavaParser.y"
-    {
+  case 291: /* UnaryExpressionNotPlusMinus: PostfixExpression  */
+#line 2642 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5473 "cmDependsJavaParser.cxx"
+#line 5649 "cmDependsJavaParser.cxx"
     break;
 
-  case 292:
-#line 2653 "cmDependsJavaParser.y"
-    {
+  case 292: /* UnaryExpressionNotPlusMinus: jp_TILDE UnaryExpression  */
+#line 2651 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5485 "cmDependsJavaParser.cxx"
+#line 5661 "cmDependsJavaParser.cxx"
     break;
 
-  case 293:
-#line 2662 "cmDependsJavaParser.y"
-    {
+  case 293: /* UnaryExpressionNotPlusMinus: jp_EXCLAMATION UnaryExpression  */
+#line 2660 "cmDependsJavaParser.y"
+{
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5497 "cmDependsJavaParser.cxx"
+#line 5673 "cmDependsJavaParser.cxx"
     break;
 
-  case 294:
-#line 2671 "cmDependsJavaParser.y"
-    {
+  case 294: /* UnaryExpressionNotPlusMinus: CastExpression  */
+#line 2669 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5509 "cmDependsJavaParser.cxx"
+#line 5685 "cmDependsJavaParser.cxx"
     break;
 
-  case 295:
-#line 2681 "cmDependsJavaParser.y"
-    {
+  case 295: /* CastExpression: jp_PARESTART PrimitiveType Dimsopt jp_PAREEND UnaryExpression  */
+#line 2679 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5521 "cmDependsJavaParser.cxx"
+#line 5697 "cmDependsJavaParser.cxx"
     break;
 
-  case 296:
-#line 2690 "cmDependsJavaParser.y"
-    {
+  case 296: /* CastExpression: jp_PARESTART Expression jp_PAREEND UnaryExpressionNotPlusMinus  */
+#line 2688 "cmDependsJavaParser.y"
+{
   jpElementStart(4);
   jpCheckEmpty(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5533 "cmDependsJavaParser.cxx"
+#line 5709 "cmDependsJavaParser.cxx"
     break;
 
-  case 297:
-#line 2699 "cmDependsJavaParser.y"
-    {
+  case 297: /* CastExpression: jp_PARESTART Name Dims jp_PAREEND UnaryExpressionNotPlusMinus  */
+#line 2697 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
 
 }
-#line 5542 "cmDependsJavaParser.cxx"
+#line 5718 "cmDependsJavaParser.cxx"
     break;
 
-  case 298:
-#line 2706 "cmDependsJavaParser.y"
-    {
+  case 298: /* MultiplicativeExpression: UnaryExpression  */
+#line 2704 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5554 "cmDependsJavaParser.cxx"
+#line 5730 "cmDependsJavaParser.cxx"
     break;
 
-  case 299:
-#line 2715 "cmDependsJavaParser.y"
-    {
+  case 299: /* MultiplicativeExpression: MultiplicativeExpression jp_TIMES UnaryExpression  */
+#line 2713 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5566 "cmDependsJavaParser.cxx"
+#line 5742 "cmDependsJavaParser.cxx"
     break;
 
-  case 300:
-#line 2724 "cmDependsJavaParser.y"
-    {
+  case 300: /* MultiplicativeExpression: MultiplicativeExpression jp_DIVIDE UnaryExpression  */
+#line 2722 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5578 "cmDependsJavaParser.cxx"
+#line 5754 "cmDependsJavaParser.cxx"
     break;
 
-  case 301:
-#line 2733 "cmDependsJavaParser.y"
-    {
+  case 301: /* MultiplicativeExpression: MultiplicativeExpression jp_PERCENT UnaryExpression  */
+#line 2731 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5590 "cmDependsJavaParser.cxx"
+#line 5766 "cmDependsJavaParser.cxx"
     break;
 
-  case 302:
-#line 2743 "cmDependsJavaParser.y"
-    {
+  case 302: /* AdditiveExpression: MultiplicativeExpression  */
+#line 2741 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5602 "cmDependsJavaParser.cxx"
+#line 5778 "cmDependsJavaParser.cxx"
     break;
 
-  case 303:
-#line 2752 "cmDependsJavaParser.y"
-    {
+  case 303: /* AdditiveExpression: AdditiveExpression jp_PLUS MultiplicativeExpression  */
+#line 2750 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5614 "cmDependsJavaParser.cxx"
+#line 5790 "cmDependsJavaParser.cxx"
     break;
 
-  case 304:
-#line 2761 "cmDependsJavaParser.y"
-    {
+  case 304: /* AdditiveExpression: AdditiveExpression jp_MINUS MultiplicativeExpression  */
+#line 2759 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5626 "cmDependsJavaParser.cxx"
+#line 5802 "cmDependsJavaParser.cxx"
     break;
 
-  case 305:
-#line 2771 "cmDependsJavaParser.y"
-    {
+  case 305: /* ShiftExpression: AdditiveExpression  */
+#line 2769 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5638 "cmDependsJavaParser.cxx"
+#line 5814 "cmDependsJavaParser.cxx"
     break;
 
-  case 306:
-#line 2780 "cmDependsJavaParser.y"
-    {
+  case 306: /* ShiftExpression: ShiftExpression jp_LTLT AdditiveExpression  */
+#line 2778 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5650 "cmDependsJavaParser.cxx"
+#line 5826 "cmDependsJavaParser.cxx"
     break;
 
-  case 307:
-#line 2789 "cmDependsJavaParser.y"
-    {
+  case 307: /* ShiftExpression: ShiftExpression jp_GTGT AdditiveExpression  */
+#line 2787 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5662 "cmDependsJavaParser.cxx"
+#line 5838 "cmDependsJavaParser.cxx"
     break;
 
-  case 308:
-#line 2798 "cmDependsJavaParser.y"
-    {
+  case 308: /* ShiftExpression: ShiftExpression jp_GTGTGT AdditiveExpression  */
+#line 2796 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5674 "cmDependsJavaParser.cxx"
+#line 5850 "cmDependsJavaParser.cxx"
     break;
 
-  case 309:
-#line 2808 "cmDependsJavaParser.y"
-    {
+  case 309: /* RelationalExpression: ShiftExpression  */
+#line 2806 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5686 "cmDependsJavaParser.cxx"
+#line 5862 "cmDependsJavaParser.cxx"
     break;
 
-  case 310:
-#line 2817 "cmDependsJavaParser.y"
-    {
+  case 310: /* RelationalExpression: RelationalExpression jp_LESSTHAN ShiftExpression  */
+#line 2815 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5698 "cmDependsJavaParser.cxx"
+#line 5874 "cmDependsJavaParser.cxx"
     break;
 
-  case 311:
-#line 2826 "cmDependsJavaParser.y"
-    {
+  case 311: /* RelationalExpression: RelationalExpression jp_GREATER ShiftExpression  */
+#line 2824 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5710 "cmDependsJavaParser.cxx"
+#line 5886 "cmDependsJavaParser.cxx"
     break;
 
-  case 312:
-#line 2835 "cmDependsJavaParser.y"
-    {
+  case 312: /* RelationalExpression: RelationalExpression jp_LTEQUALS ShiftExpression  */
+#line 2833 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5722 "cmDependsJavaParser.cxx"
+#line 5898 "cmDependsJavaParser.cxx"
     break;
 
-  case 313:
-#line 2844 "cmDependsJavaParser.y"
-    {
+  case 313: /* RelationalExpression: RelationalExpression jp_GTEQUALS ShiftExpression  */
+#line 2842 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5734 "cmDependsJavaParser.cxx"
+#line 5910 "cmDependsJavaParser.cxx"
     break;
 
-  case 314:
-#line 2853 "cmDependsJavaParser.y"
-    {
+  case 314: /* RelationalExpression: RelationalExpression jp_INSTANCEOF ReferenceType  */
+#line 2851 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5746 "cmDependsJavaParser.cxx"
+#line 5922 "cmDependsJavaParser.cxx"
     break;
 
-  case 315:
-#line 2863 "cmDependsJavaParser.y"
-    {
+  case 315: /* EqualityExpression: RelationalExpression  */
+#line 2861 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5758 "cmDependsJavaParser.cxx"
+#line 5934 "cmDependsJavaParser.cxx"
     break;
 
-  case 316:
-#line 2872 "cmDependsJavaParser.y"
-    {
+  case 316: /* EqualityExpression: EqualityExpression jp_EQUALSEQUALS RelationalExpression  */
+#line 2870 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5770 "cmDependsJavaParser.cxx"
+#line 5946 "cmDependsJavaParser.cxx"
     break;
 
-  case 317:
-#line 2881 "cmDependsJavaParser.y"
-    {
+  case 317: /* EqualityExpression: EqualityExpression jp_EXCLAMATIONEQUALS RelationalExpression  */
+#line 2879 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5782 "cmDependsJavaParser.cxx"
+#line 5958 "cmDependsJavaParser.cxx"
     break;
 
-  case 318:
-#line 2891 "cmDependsJavaParser.y"
-    {
+  case 318: /* AndExpression: EqualityExpression  */
+#line 2889 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5794 "cmDependsJavaParser.cxx"
+#line 5970 "cmDependsJavaParser.cxx"
     break;
 
-  case 319:
-#line 2900 "cmDependsJavaParser.y"
-    {
+  case 319: /* AndExpression: AndExpression jp_AND EqualityExpression  */
+#line 2898 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5806 "cmDependsJavaParser.cxx"
+#line 5982 "cmDependsJavaParser.cxx"
     break;
 
-  case 320:
-#line 2910 "cmDependsJavaParser.y"
-    {
+  case 320: /* ExclusiveOrExpression: AndExpression  */
+#line 2908 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5818 "cmDependsJavaParser.cxx"
+#line 5994 "cmDependsJavaParser.cxx"
     break;
 
-  case 321:
-#line 2919 "cmDependsJavaParser.y"
-    {
+  case 321: /* ExclusiveOrExpression: ExclusiveOrExpression jp_CARROT AndExpression  */
+#line 2917 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5830 "cmDependsJavaParser.cxx"
+#line 6006 "cmDependsJavaParser.cxx"
     break;
 
-  case 322:
-#line 2929 "cmDependsJavaParser.y"
-    {
+  case 322: /* InclusiveOrExpression: ExclusiveOrExpression  */
+#line 2927 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5842 "cmDependsJavaParser.cxx"
+#line 6018 "cmDependsJavaParser.cxx"
     break;
 
-  case 323:
-#line 2938 "cmDependsJavaParser.y"
-    {
+  case 323: /* InclusiveOrExpression: InclusiveOrExpression jp_PIPE ExclusiveOrExpression  */
+#line 2936 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5854 "cmDependsJavaParser.cxx"
+#line 6030 "cmDependsJavaParser.cxx"
     break;
 
-  case 324:
-#line 2948 "cmDependsJavaParser.y"
-    {
+  case 324: /* ConditionalAndExpression: InclusiveOrExpression  */
+#line 2946 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5866 "cmDependsJavaParser.cxx"
+#line 6042 "cmDependsJavaParser.cxx"
     break;
 
-  case 325:
-#line 2957 "cmDependsJavaParser.y"
-    {
+  case 325: /* ConditionalAndExpression: ConditionalAndExpression jp_ANDAND InclusiveOrExpression  */
+#line 2955 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5878 "cmDependsJavaParser.cxx"
+#line 6054 "cmDependsJavaParser.cxx"
     break;
 
-  case 326:
-#line 2967 "cmDependsJavaParser.y"
-    {
+  case 326: /* ConditionalOrExpression: ConditionalAndExpression  */
+#line 2965 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5890 "cmDependsJavaParser.cxx"
+#line 6066 "cmDependsJavaParser.cxx"
     break;
 
-  case 327:
-#line 2976 "cmDependsJavaParser.y"
-    {
+  case 327: /* ConditionalOrExpression: ConditionalOrExpression jp_PIPEPIPE ConditionalAndExpression  */
+#line 2974 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5902 "cmDependsJavaParser.cxx"
+#line 6078 "cmDependsJavaParser.cxx"
     break;
 
-  case 328:
-#line 2986 "cmDependsJavaParser.y"
-    {
+  case 328: /* ConditionalExpression: ConditionalOrExpression  */
+#line 2984 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5914 "cmDependsJavaParser.cxx"
+#line 6090 "cmDependsJavaParser.cxx"
     break;
 
-  case 329:
-#line 2995 "cmDependsJavaParser.y"
-    {
+  case 329: /* ConditionalExpression: ConditionalOrExpression jp_QUESTION Expression jp_COLON ConditionalExpression  */
+#line 2993 "cmDependsJavaParser.y"
+{
   jpElementStart(5);
   jpCheckEmpty(5);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5926 "cmDependsJavaParser.cxx"
+#line 6102 "cmDependsJavaParser.cxx"
     break;
 
-  case 330:
-#line 3005 "cmDependsJavaParser.y"
-    {
+  case 330: /* AssignmentExpression: ConditionalExpression  */
+#line 3003 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5938 "cmDependsJavaParser.cxx"
+#line 6114 "cmDependsJavaParser.cxx"
     break;
 
-  case 331:
-#line 3014 "cmDependsJavaParser.y"
-    {
+  case 331: /* AssignmentExpression: Assignment  */
+#line 3012 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5950 "cmDependsJavaParser.cxx"
+#line 6126 "cmDependsJavaParser.cxx"
     break;
 
-  case 332:
-#line 3024 "cmDependsJavaParser.y"
-    {
+  case 332: /* Assignment: LeftHandSide AssignmentOperator AssignmentExpression  */
+#line 3022 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5962 "cmDependsJavaParser.cxx"
+#line 6138 "cmDependsJavaParser.cxx"
     break;
 
-  case 333:
-#line 3034 "cmDependsJavaParser.y"
-    {
+  case 333: /* LeftHandSide: Name  */
+#line 3032 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(1);
@@ -5971,216 +6147,216 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5975 "cmDependsJavaParser.cxx"
+#line 6151 "cmDependsJavaParser.cxx"
     break;
 
-  case 334:
-#line 3044 "cmDependsJavaParser.y"
-    {
+  case 334: /* LeftHandSide: FieldAccess  */
+#line 3042 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5987 "cmDependsJavaParser.cxx"
+#line 6163 "cmDependsJavaParser.cxx"
     break;
 
-  case 335:
-#line 3053 "cmDependsJavaParser.y"
-    {
+  case 335: /* LeftHandSide: ArrayAccess  */
+#line 3051 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5999 "cmDependsJavaParser.cxx"
+#line 6175 "cmDependsJavaParser.cxx"
     break;
 
-  case 336:
-#line 3063 "cmDependsJavaParser.y"
-    {
+  case 336: /* AssignmentOperator: jp_EQUALS  */
+#line 3061 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6011 "cmDependsJavaParser.cxx"
+#line 6187 "cmDependsJavaParser.cxx"
     break;
 
-  case 337:
-#line 3072 "cmDependsJavaParser.y"
-    {
+  case 337: /* AssignmentOperator: jp_TIMESEQUALS  */
+#line 3070 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6023 "cmDependsJavaParser.cxx"
+#line 6199 "cmDependsJavaParser.cxx"
     break;
 
-  case 338:
-#line 3081 "cmDependsJavaParser.y"
-    {
+  case 338: /* AssignmentOperator: jp_DIVIDEEQUALS  */
+#line 3079 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6035 "cmDependsJavaParser.cxx"
+#line 6211 "cmDependsJavaParser.cxx"
     break;
 
-  case 339:
-#line 3090 "cmDependsJavaParser.y"
-    {
+  case 339: /* AssignmentOperator: jp_PERCENTEQUALS  */
+#line 3088 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6047 "cmDependsJavaParser.cxx"
+#line 6223 "cmDependsJavaParser.cxx"
     break;
 
-  case 340:
-#line 3099 "cmDependsJavaParser.y"
-    {
+  case 340: /* AssignmentOperator: jp_PLUSEQUALS  */
+#line 3097 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6059 "cmDependsJavaParser.cxx"
+#line 6235 "cmDependsJavaParser.cxx"
     break;
 
-  case 341:
-#line 3108 "cmDependsJavaParser.y"
-    {
+  case 341: /* AssignmentOperator: jp_MINUSEQUALS  */
+#line 3106 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6071 "cmDependsJavaParser.cxx"
+#line 6247 "cmDependsJavaParser.cxx"
     break;
 
-  case 342:
-#line 3117 "cmDependsJavaParser.y"
-    {
+  case 342: /* AssignmentOperator: jp_LESLESEQUALS  */
+#line 3115 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6083 "cmDependsJavaParser.cxx"
+#line 6259 "cmDependsJavaParser.cxx"
     break;
 
-  case 343:
-#line 3126 "cmDependsJavaParser.y"
-    {
+  case 343: /* AssignmentOperator: jp_GTGTEQUALS  */
+#line 3124 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6095 "cmDependsJavaParser.cxx"
+#line 6271 "cmDependsJavaParser.cxx"
     break;
 
-  case 344:
-#line 3135 "cmDependsJavaParser.y"
-    {
+  case 344: /* AssignmentOperator: jp_GTGTGTEQUALS  */
+#line 3133 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6107 "cmDependsJavaParser.cxx"
+#line 6283 "cmDependsJavaParser.cxx"
     break;
 
-  case 345:
-#line 3144 "cmDependsJavaParser.y"
-    {
+  case 345: /* AssignmentOperator: jp_ANDEQUALS  */
+#line 3142 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6119 "cmDependsJavaParser.cxx"
+#line 6295 "cmDependsJavaParser.cxx"
     break;
 
-  case 346:
-#line 3153 "cmDependsJavaParser.y"
-    {
+  case 346: /* AssignmentOperator: jp_CARROTEQUALS  */
+#line 3151 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6131 "cmDependsJavaParser.cxx"
+#line 6307 "cmDependsJavaParser.cxx"
     break;
 
-  case 347:
-#line 3162 "cmDependsJavaParser.y"
-    {
+  case 347: /* AssignmentOperator: jp_PIPEEQUALS  */
+#line 3160 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6143 "cmDependsJavaParser.cxx"
+#line 6319 "cmDependsJavaParser.cxx"
     break;
 
-  case 348:
-#line 3172 "cmDependsJavaParser.y"
-    {
+  case 348: /* Expression: AssignmentExpression  */
+#line 3170 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6155 "cmDependsJavaParser.cxx"
+#line 6331 "cmDependsJavaParser.cxx"
     break;
 
-  case 349:
-#line 3182 "cmDependsJavaParser.y"
-    {
+  case 349: /* ConstantExpression: Expression  */
+#line 3180 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6167 "cmDependsJavaParser.cxx"
+#line 6343 "cmDependsJavaParser.cxx"
     break;
 
-  case 350:
-#line 3192 "cmDependsJavaParser.y"
-    {
+  case 350: /* New: jp_NEW  */
+#line 3190 "cmDependsJavaParser.y"
+{
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6179 "cmDependsJavaParser.cxx"
+#line 6355 "cmDependsJavaParser.cxx"
     break;
 
-  case 351:
-#line 3201 "cmDependsJavaParser.y"
-    {
+  case 351: /* New: Name jp_DOT jp_NEW  */
+#line 3199 "cmDependsJavaParser.y"
+{
   jpElementStart(3);
   jpStoreClass((yyvsp[-2].str));
   jpCheckEmpty(3);
@@ -6188,11 +6364,11 @@ yyreduce:
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6192 "cmDependsJavaParser.cxx"
+#line 6368 "cmDependsJavaParser.cxx"
     break;
 
 
-#line 6196 "cmDependsJavaParser.cxx"
+#line 6372 "cmDependsJavaParser.cxx"
 
       default: break;
     }
@@ -6207,11 +6383,10 @@ yyreduce:
      case of YYERROR or YYBACKUP, subsequent parser actions might lead
      to an incorrect destructor call or verbose syntax error message
      before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
   yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
 
   *++yyvsp = yyval;
 
@@ -6235,50 +6410,44 @@ yyreduce:
 yyerrlab:
   /* Make sure we have latest lookahead translation.  See comments at
      user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
+  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
       ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (yyscanner, YY_("syntax error"));
-#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
-                                        yyssp, yytoken)
       {
+        yypcontext_t yyctx
+          = {yyssp, yytoken};
         char const *yymsgp = YY_("syntax error");
         int yysyntax_error_status;
-        yysyntax_error_status = YYSYNTAX_ERROR;
+        yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
-        else if (yysyntax_error_status == 1)
+        else if (yysyntax_error_status == -1)
           {
             if (yymsg != yymsgbuf)
               YYSTACK_FREE (yymsg);
-            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
-            if (!yymsg)
+            yymsg = YY_CAST (char *,
+                             YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+            if (yymsg)
               {
-                yymsg = yymsgbuf;
-                yymsg_alloc = sizeof yymsgbuf;
-                yysyntax_error_status = 2;
+                yysyntax_error_status
+                  = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+                yymsgp = yymsg;
               }
             else
               {
-                yysyntax_error_status = YYSYNTAX_ERROR;
-                yymsgp = yymsg;
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = YYENOMEM;
               }
           }
         yyerror (yyscanner, yymsgp);
-        if (yysyntax_error_status == 2)
+        if (yysyntax_error_status == YYENOMEM)
           goto yyexhaustedlab;
       }
-# undef YYSYNTAX_ERROR
-#endif
     }
 
-
-
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
@@ -6298,7 +6467,6 @@ yyerrlab:
         }
     }
 
-#if 0
   /* Else will try to reuse lookahead token after shifting the error
      token.  */
   goto yyerrlab1;
@@ -6326,16 +6494,16 @@ yyerrorlab:
 | yyerrlab1 -- common code for both syntax error and YYERROR.  |
 `-------------------------------------------------------------*/
 yyerrlab1:
-#endif
   yyerrstatus = 3;      /* Each real token shifted decrements this.  */
 
+  /* Pop stack until we find a state that shifts the error token.  */
   for (;;)
     {
       yyn = yypact[yystate];
       if (!yypact_value_is_default (yyn))
         {
-          yyn += YYTERROR;
-          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+          yyn += YYSYMBOL_YYerror;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
             {
               yyn = yytable[yyn];
               if (0 < yyn)
@@ -6349,7 +6517,7 @@ yyerrlab1:
 
 
       yydestruct ("Error: popping",
-                  yystos[yystate], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -6361,7 +6529,7 @@ yyerrlab1:
 
 
   /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
 
   yystate = yyn;
   goto yynewstate;
@@ -6383,20 +6551,20 @@ yyabortlab:
   goto yyreturn;
 
 
-#if !defined yyoverflow || YYERROR_VERBOSE
+#if 1
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
   yyerror (yyscanner, YY_("memory exhausted"));
   yyresult = 2;
-  /* Fall through.  */
+  goto yyreturn;
 #endif
 
 
-/*-----------------------------------------------------.
-| yyreturn -- parsing is finished, return the result.  |
-`-----------------------------------------------------*/
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return.  |
+`-------------------------------------------------------*/
 yyreturn:
   if (yychar != YYEMPTY)
     {
@@ -6413,20 +6581,19 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                  yystos[*yyssp], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
   if (yyss != yyssa)
     YYSTACK_FREE (yyss);
 #endif
-#if YYERROR_VERBOSE
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
-#endif
   return yyresult;
 }
-#line 3210 "cmDependsJavaParser.y"
+
+#line 3208 "cmDependsJavaParser.y"
 
 /* End of grammar */
 
index d15cffc..a76ec50 100644 (file)
@@ -7,15 +7,13 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmDependsJava_yy --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx cmDependsJavaParser.y
-
-Modify cmDependsJavaParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+  bison --name-prefix=cmDependsJava_yy --defines=cmDependsJavaParserTokens.h -ocmDependsJavaParser.cxx cmDependsJavaParser.y
 
 */
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string>
@@ -25,7 +23,6 @@ Modify cmDependsJavaParser.cxx:
 /*-------------------------------------------------------------------------*/
 #include "cmDependsJavaParserHelper.h" /* Interface to parser object.  */
 #include "cmDependsJavaLexer.h"  /* Interface to lexer object.  */
-#include "cmDependsJavaParserTokens.h" /* Need YYSTYPE for YY_DECL.  */
 
 /* Forward declare the lexer entry point.  */
 YY_DECL;
@@ -46,6 +43,7 @@ static void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message);
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
 #endif
 %}
 
index e0dfa01..4ae55fa 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -31,8 +31,9 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
 
 #ifndef YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
 # define YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
 extern int cmDependsJava_yydebug;
 #endif
 
-/* Token type.  */
+/* Token kinds.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
   enum yytokentype
   {
-    jp_ABSTRACT = 258,
-    jp_ASSERT = 259,
-    jp_BOOLEAN_TYPE = 260,
-    jp_BREAK = 261,
-    jp_BYTE_TYPE = 262,
-    jp_CASE = 263,
-    jp_CATCH = 264,
-    jp_CHAR_TYPE = 265,
-    jp_CLASS = 266,
-    jp_CONTINUE = 267,
-    jp_DEFAULT = 268,
-    jp_DO = 269,
-    jp_DOUBLE_TYPE = 270,
-    jp_ELSE = 271,
-    jp_EXTENDS = 272,
-    jp_FINAL = 273,
-    jp_FINALLY = 274,
-    jp_FLOAT_TYPE = 275,
-    jp_FOR = 276,
-    jp_IF = 277,
-    jp_IMPLEMENTS = 278,
-    jp_IMPORT = 279,
-    jp_INSTANCEOF = 280,
-    jp_INT_TYPE = 281,
-    jp_INTERFACE = 282,
-    jp_LONG_TYPE = 283,
-    jp_NATIVE = 284,
-    jp_NEW = 285,
-    jp_PACKAGE = 286,
-    jp_PRIVATE = 287,
-    jp_PROTECTED = 288,
-    jp_PUBLIC = 289,
-    jp_RETURN = 290,
-    jp_SHORT_TYPE = 291,
-    jp_STATIC = 292,
-    jp_STRICTFP = 293,
-    jp_SUPER = 294,
-    jp_SWITCH = 295,
-    jp_SYNCHRONIZED = 296,
-    jp_THIS = 297,
-    jp_THROW = 298,
-    jp_THROWS = 299,
-    jp_TRANSIENT = 300,
-    jp_TRY = 301,
-    jp_VOID = 302,
-    jp_VOLATILE = 303,
-    jp_WHILE = 304,
-    jp_BOOLEANLITERAL = 305,
-    jp_CHARACTERLITERAL = 306,
-    jp_DECIMALINTEGERLITERAL = 307,
-    jp_FLOATINGPOINTLITERAL = 308,
-    jp_HEXINTEGERLITERAL = 309,
-    jp_NULLLITERAL = 310,
-    jp_STRINGLITERAL = 311,
-    jp_NAME = 312,
-    jp_AND = 313,
-    jp_ANDAND = 314,
-    jp_ANDEQUALS = 315,
-    jp_BRACKETEND = 316,
-    jp_BRACKETSTART = 317,
-    jp_CARROT = 318,
-    jp_CARROTEQUALS = 319,
-    jp_COLON = 320,
-    jp_COMMA = 321,
-    jp_CURLYEND = 322,
-    jp_CURLYSTART = 323,
-    jp_DIVIDE = 324,
-    jp_DIVIDEEQUALS = 325,
-    jp_DOLLAR = 326,
-    jp_DOT = 327,
-    jp_EQUALS = 328,
-    jp_EQUALSEQUALS = 329,
-    jp_EXCLAMATION = 330,
-    jp_EXCLAMATIONEQUALS = 331,
-    jp_GREATER = 332,
-    jp_GTEQUALS = 333,
-    jp_GTGT = 334,
-    jp_GTGTEQUALS = 335,
-    jp_GTGTGT = 336,
-    jp_GTGTGTEQUALS = 337,
-    jp_LESLESEQUALS = 338,
-    jp_LESSTHAN = 339,
-    jp_LTEQUALS = 340,
-    jp_LTLT = 341,
-    jp_MINUS = 342,
-    jp_MINUSEQUALS = 343,
-    jp_MINUSMINUS = 344,
-    jp_PAREEND = 345,
-    jp_PARESTART = 346,
-    jp_PERCENT = 347,
-    jp_PERCENTEQUALS = 348,
-    jp_PIPE = 349,
-    jp_PIPEEQUALS = 350,
-    jp_PIPEPIPE = 351,
-    jp_PLUS = 352,
-    jp_PLUSEQUALS = 353,
-    jp_PLUSPLUS = 354,
-    jp_QUESTION = 355,
-    jp_SEMICOL = 356,
-    jp_TILDE = 357,
-    jp_TIMES = 358,
-    jp_TIMESEQUALS = 359,
-    jp_ERROR = 360
+    YYEMPTY = -2,
+    YYEOF = 0,                     /* "end of file"  */
+    YYerror = 256,                 /* error  */
+    YYUNDEF = 257,                 /* "invalid token"  */
+    jp_ABSTRACT = 258,             /* jp_ABSTRACT  */
+    jp_ASSERT = 259,               /* jp_ASSERT  */
+    jp_BOOLEAN_TYPE = 260,         /* jp_BOOLEAN_TYPE  */
+    jp_BREAK = 261,                /* jp_BREAK  */
+    jp_BYTE_TYPE = 262,            /* jp_BYTE_TYPE  */
+    jp_CASE = 263,                 /* jp_CASE  */
+    jp_CATCH = 264,                /* jp_CATCH  */
+    jp_CHAR_TYPE = 265,            /* jp_CHAR_TYPE  */
+    jp_CLASS = 266,                /* jp_CLASS  */
+    jp_CONTINUE = 267,             /* jp_CONTINUE  */
+    jp_DEFAULT = 268,              /* jp_DEFAULT  */
+    jp_DO = 269,                   /* jp_DO  */
+    jp_DOUBLE_TYPE = 270,          /* jp_DOUBLE_TYPE  */
+    jp_ELSE = 271,                 /* jp_ELSE  */
+    jp_EXTENDS = 272,              /* jp_EXTENDS  */
+    jp_FINAL = 273,                /* jp_FINAL  */
+    jp_FINALLY = 274,              /* jp_FINALLY  */
+    jp_FLOAT_TYPE = 275,           /* jp_FLOAT_TYPE  */
+    jp_FOR = 276,                  /* jp_FOR  */
+    jp_IF = 277,                   /* jp_IF  */
+    jp_IMPLEMENTS = 278,           /* jp_IMPLEMENTS  */
+    jp_IMPORT = 279,               /* jp_IMPORT  */
+    jp_INSTANCEOF = 280,           /* jp_INSTANCEOF  */
+    jp_INT_TYPE = 281,             /* jp_INT_TYPE  */
+    jp_INTERFACE = 282,            /* jp_INTERFACE  */
+    jp_LONG_TYPE = 283,            /* jp_LONG_TYPE  */
+    jp_NATIVE = 284,               /* jp_NATIVE  */
+    jp_NEW = 285,                  /* jp_NEW  */
+    jp_PACKAGE = 286,              /* jp_PACKAGE  */
+    jp_PRIVATE = 287,              /* jp_PRIVATE  */
+    jp_PROTECTED = 288,            /* jp_PROTECTED  */
+    jp_PUBLIC = 289,               /* jp_PUBLIC  */
+    jp_RETURN = 290,               /* jp_RETURN  */
+    jp_SHORT_TYPE = 291,           /* jp_SHORT_TYPE  */
+    jp_STATIC = 292,               /* jp_STATIC  */
+    jp_STRICTFP = 293,             /* jp_STRICTFP  */
+    jp_SUPER = 294,                /* jp_SUPER  */
+    jp_SWITCH = 295,               /* jp_SWITCH  */
+    jp_SYNCHRONIZED = 296,         /* jp_SYNCHRONIZED  */
+    jp_THIS = 297,                 /* jp_THIS  */
+    jp_THROW = 298,                /* jp_THROW  */
+    jp_THROWS = 299,               /* jp_THROWS  */
+    jp_TRANSIENT = 300,            /* jp_TRANSIENT  */
+    jp_TRY = 301,                  /* jp_TRY  */
+    jp_VOID = 302,                 /* jp_VOID  */
+    jp_VOLATILE = 303,             /* jp_VOLATILE  */
+    jp_WHILE = 304,                /* jp_WHILE  */
+    jp_BOOLEANLITERAL = 305,       /* jp_BOOLEANLITERAL  */
+    jp_CHARACTERLITERAL = 306,     /* jp_CHARACTERLITERAL  */
+    jp_DECIMALINTEGERLITERAL = 307, /* jp_DECIMALINTEGERLITERAL  */
+    jp_FLOATINGPOINTLITERAL = 308, /* jp_FLOATINGPOINTLITERAL  */
+    jp_HEXINTEGERLITERAL = 309,    /* jp_HEXINTEGERLITERAL  */
+    jp_NULLLITERAL = 310,          /* jp_NULLLITERAL  */
+    jp_STRINGLITERAL = 311,        /* jp_STRINGLITERAL  */
+    jp_NAME = 312,                 /* jp_NAME  */
+    jp_AND = 313,                  /* jp_AND  */
+    jp_ANDAND = 314,               /* jp_ANDAND  */
+    jp_ANDEQUALS = 315,            /* jp_ANDEQUALS  */
+    jp_BRACKETEND = 316,           /* jp_BRACKETEND  */
+    jp_BRACKETSTART = 317,         /* jp_BRACKETSTART  */
+    jp_CARROT = 318,               /* jp_CARROT  */
+    jp_CARROTEQUALS = 319,         /* jp_CARROTEQUALS  */
+    jp_COLON = 320,                /* jp_COLON  */
+    jp_COMMA = 321,                /* jp_COMMA  */
+    jp_CURLYEND = 322,             /* jp_CURLYEND  */
+    jp_CURLYSTART = 323,           /* jp_CURLYSTART  */
+    jp_DIVIDE = 324,               /* jp_DIVIDE  */
+    jp_DIVIDEEQUALS = 325,         /* jp_DIVIDEEQUALS  */
+    jp_DOLLAR = 326,               /* jp_DOLLAR  */
+    jp_DOT = 327,                  /* jp_DOT  */
+    jp_EQUALS = 328,               /* jp_EQUALS  */
+    jp_EQUALSEQUALS = 329,         /* jp_EQUALSEQUALS  */
+    jp_EXCLAMATION = 330,          /* jp_EXCLAMATION  */
+    jp_EXCLAMATIONEQUALS = 331,    /* jp_EXCLAMATIONEQUALS  */
+    jp_GREATER = 332,              /* jp_GREATER  */
+    jp_GTEQUALS = 333,             /* jp_GTEQUALS  */
+    jp_GTGT = 334,                 /* jp_GTGT  */
+    jp_GTGTEQUALS = 335,           /* jp_GTGTEQUALS  */
+    jp_GTGTGT = 336,               /* jp_GTGTGT  */
+    jp_GTGTGTEQUALS = 337,         /* jp_GTGTGTEQUALS  */
+    jp_LESLESEQUALS = 338,         /* jp_LESLESEQUALS  */
+    jp_LESSTHAN = 339,             /* jp_LESSTHAN  */
+    jp_LTEQUALS = 340,             /* jp_LTEQUALS  */
+    jp_LTLT = 341,                 /* jp_LTLT  */
+    jp_MINUS = 342,                /* jp_MINUS  */
+    jp_MINUSEQUALS = 343,          /* jp_MINUSEQUALS  */
+    jp_MINUSMINUS = 344,           /* jp_MINUSMINUS  */
+    jp_PAREEND = 345,              /* jp_PAREEND  */
+    jp_PARESTART = 346,            /* jp_PARESTART  */
+    jp_PERCENT = 347,              /* jp_PERCENT  */
+    jp_PERCENTEQUALS = 348,        /* jp_PERCENTEQUALS  */
+    jp_PIPE = 349,                 /* jp_PIPE  */
+    jp_PIPEEQUALS = 350,           /* jp_PIPEEQUALS  */
+    jp_PIPEPIPE = 351,             /* jp_PIPEPIPE  */
+    jp_PLUS = 352,                 /* jp_PLUS  */
+    jp_PLUSEQUALS = 353,           /* jp_PLUSEQUALS  */
+    jp_PLUSPLUS = 354,             /* jp_PLUSPLUS  */
+    jp_QUESTION = 355,             /* jp_QUESTION  */
+    jp_SEMICOL = 356,              /* jp_SEMICOL  */
+    jp_TILDE = 357,                /* jp_TILDE  */
+    jp_TIMES = 358,                /* jp_TIMES  */
+    jp_TIMESEQUALS = 359,          /* jp_TIMESEQUALS  */
+    jp_ERROR = 360                 /* jp_ERROR  */
   };
+  typedef enum yytokentype yytoken_kind_t;
 #endif
-/* Tokens.  */
-#define jp_ABSTRACT 258
-#define jp_ASSERT 259
-#define jp_BOOLEAN_TYPE 260
-#define jp_BREAK 261
-#define jp_BYTE_TYPE 262
-#define jp_CASE 263
-#define jp_CATCH 264
-#define jp_CHAR_TYPE 265
-#define jp_CLASS 266
-#define jp_CONTINUE 267
-#define jp_DEFAULT 268
-#define jp_DO 269
-#define jp_DOUBLE_TYPE 270
-#define jp_ELSE 271
-#define jp_EXTENDS 272
-#define jp_FINAL 273
-#define jp_FINALLY 274
-#define jp_FLOAT_TYPE 275
-#define jp_FOR 276
-#define jp_IF 277
-#define jp_IMPLEMENTS 278
-#define jp_IMPORT 279
-#define jp_INSTANCEOF 280
-#define jp_INT_TYPE 281
-#define jp_INTERFACE 282
-#define jp_LONG_TYPE 283
-#define jp_NATIVE 284
-#define jp_NEW 285
-#define jp_PACKAGE 286
-#define jp_PRIVATE 287
-#define jp_PROTECTED 288
-#define jp_PUBLIC 289
-#define jp_RETURN 290
-#define jp_SHORT_TYPE 291
-#define jp_STATIC 292
-#define jp_STRICTFP 293
-#define jp_SUPER 294
-#define jp_SWITCH 295
-#define jp_SYNCHRONIZED 296
-#define jp_THIS 297
-#define jp_THROW 298
-#define jp_THROWS 299
-#define jp_TRANSIENT 300
-#define jp_TRY 301
-#define jp_VOID 302
-#define jp_VOLATILE 303
-#define jp_WHILE 304
-#define jp_BOOLEANLITERAL 305
-#define jp_CHARACTERLITERAL 306
-#define jp_DECIMALINTEGERLITERAL 307
-#define jp_FLOATINGPOINTLITERAL 308
-#define jp_HEXINTEGERLITERAL 309
-#define jp_NULLLITERAL 310
-#define jp_STRINGLITERAL 311
-#define jp_NAME 312
-#define jp_AND 313
-#define jp_ANDAND 314
-#define jp_ANDEQUALS 315
-#define jp_BRACKETEND 316
-#define jp_BRACKETSTART 317
-#define jp_CARROT 318
-#define jp_CARROTEQUALS 319
-#define jp_COLON 320
-#define jp_COMMA 321
-#define jp_CURLYEND 322
-#define jp_CURLYSTART 323
-#define jp_DIVIDE 324
-#define jp_DIVIDEEQUALS 325
-#define jp_DOLLAR 326
-#define jp_DOT 327
-#define jp_EQUALS 328
-#define jp_EQUALSEQUALS 329
-#define jp_EXCLAMATION 330
-#define jp_EXCLAMATIONEQUALS 331
-#define jp_GREATER 332
-#define jp_GTEQUALS 333
-#define jp_GTGT 334
-#define jp_GTGTEQUALS 335
-#define jp_GTGTGT 336
-#define jp_GTGTGTEQUALS 337
-#define jp_LESLESEQUALS 338
-#define jp_LESSTHAN 339
-#define jp_LTEQUALS 340
-#define jp_LTLT 341
-#define jp_MINUS 342
-#define jp_MINUSEQUALS 343
-#define jp_MINUSMINUS 344
-#define jp_PAREEND 345
-#define jp_PARESTART 346
-#define jp_PERCENT 347
-#define jp_PERCENTEQUALS 348
-#define jp_PIPE 349
-#define jp_PIPEEQUALS 350
-#define jp_PIPEPIPE 351
-#define jp_PLUS 352
-#define jp_PLUSEQUALS 353
-#define jp_PLUSPLUS 354
-#define jp_QUESTION 355
-#define jp_SEMICOL 356
-#define jp_TILDE 357
-#define jp_TIMES 358
-#define jp_TIMESEQUALS 359
-#define jp_ERROR 360
 
 /* Value type.  */
 
index 562b35b..b747d8b 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
 /* C LALR(1) parser skeleton written by Richard Stallman, by
    simplifying the original so-called "semantic" parser.  */
 
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
 /* All symbols defined below should begin with yy or YY, to avoid
    infringing on user name space.  This should be done even for local
    variables, as they might otherwise be expanded by user macros.
    define necessary library symbols; they are noted "INFRINGES ON
    USER NAME SPACE" below.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
+/* Identify Bison output, and Bison version.  */
+#define YYBISON 30704
 
-/* Bison version.  */
-#define YYBISON_VERSION "3.4.2"
+/* Bison version string.  */
+#define YYBISON_VERSION "3.7.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -70,7 +71,6 @@
 #define yydebug         cmExpr_yydebug
 #define yynerrs         cmExpr_yynerrs
 
-
 /* First part of user prologue.  */
 #line 1 "cmExprParser.y"
 
@@ -82,15 +82,13 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h -ocmExprParser.cxx cmExprParser.y
-
-Modify cmExprParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+  bison --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h -ocmExprParser.cxx cmExprParser.y
 
 */
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdexcept>
@@ -114,10 +112,25 @@ static void cmExpr_yyerror(yyscan_t yyscanner, const char* message);
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wused-but-marked-unused")
+#  pragma clang diagnostic ignored "-Wused-but-marked-unused"
+# endif
 #endif
 
-#line 120 "cmExprParser.cxx"
+#line 124 "cmExprParser.cxx"
 
+# ifndef YY_CAST
+#  ifdef __cplusplus
+#   define YY_CAST(Type, Val) static_cast<Type> (Val)
+#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+#  else
+#   define YY_CAST(Type, Val) ((Type) (Val))
+#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+#  endif
+# endif
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -130,99 +143,117 @@ static void cmExpr_yyerror(yyscan_t yyscanner, const char* message);
 #  endif
 # endif
 
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Use api.header.include to #include this header
-   instead of duplicating it here.  */
-#ifndef YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
-# define YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
-/* Debug traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int cmExpr_yydebug;
-#endif
-
-/* Token type.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-  enum yytokentype
-  {
-    exp_PLUS = 258,
-    exp_MINUS = 259,
-    exp_TIMES = 260,
-    exp_DIVIDE = 261,
-    exp_MOD = 262,
-    exp_SHIFTLEFT = 263,
-    exp_SHIFTRIGHT = 264,
-    exp_OPENPARENT = 265,
-    exp_CLOSEPARENT = 266,
-    exp_OR = 267,
-    exp_AND = 268,
-    exp_XOR = 269,
-    exp_NOT = 270,
-    exp_NUMBER = 271
-  };
-#endif
-/* Tokens.  */
-#define exp_PLUS 258
-#define exp_MINUS 259
-#define exp_TIMES 260
-#define exp_DIVIDE 261
-#define exp_MOD 262
-#define exp_SHIFTLEFT 263
-#define exp_SHIFTRIGHT 264
-#define exp_OPENPARENT 265
-#define exp_CLOSEPARENT 266
-#define exp_OR 267
-#define exp_AND 268
-#define exp_XOR 269
-#define exp_NOT 270
-#define exp_NUMBER 271
+#include "cmExprParserTokens.h"
+/* Symbol kind.  */
+enum yysymbol_kind_t
+{
+  YYSYMBOL_YYEMPTY = -2,
+  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
+  YYSYMBOL_YYerror = 1,                    /* error  */
+  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
+  YYSYMBOL_exp_PLUS = 3,                   /* exp_PLUS  */
+  YYSYMBOL_exp_MINUS = 4,                  /* exp_MINUS  */
+  YYSYMBOL_exp_TIMES = 5,                  /* exp_TIMES  */
+  YYSYMBOL_exp_DIVIDE = 6,                 /* exp_DIVIDE  */
+  YYSYMBOL_exp_MOD = 7,                    /* exp_MOD  */
+  YYSYMBOL_exp_SHIFTLEFT = 8,              /* exp_SHIFTLEFT  */
+  YYSYMBOL_exp_SHIFTRIGHT = 9,             /* exp_SHIFTRIGHT  */
+  YYSYMBOL_exp_OPENPARENT = 10,            /* exp_OPENPARENT  */
+  YYSYMBOL_exp_CLOSEPARENT = 11,           /* exp_CLOSEPARENT  */
+  YYSYMBOL_exp_OR = 12,                    /* exp_OR  */
+  YYSYMBOL_exp_AND = 13,                   /* exp_AND  */
+  YYSYMBOL_exp_XOR = 14,                   /* exp_XOR  */
+  YYSYMBOL_exp_NOT = 15,                   /* exp_NOT  */
+  YYSYMBOL_exp_NUMBER = 16,                /* exp_NUMBER  */
+  YYSYMBOL_YYACCEPT = 17,                  /* $accept  */
+  YYSYMBOL_start = 18,                     /* start  */
+  YYSYMBOL_exp = 19,                       /* exp  */
+  YYSYMBOL_bitwiseor = 20,                 /* bitwiseor  */
+  YYSYMBOL_bitwisexor = 21,                /* bitwisexor  */
+  YYSYMBOL_bitwiseand = 22,                /* bitwiseand  */
+  YYSYMBOL_shift = 23,                     /* shift  */
+  YYSYMBOL_term = 24,                      /* term  */
+  YYSYMBOL_unary = 25,                     /* unary  */
+  YYSYMBOL_factor = 26                     /* factor  */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
 
-/* Value type.  */
 
 
 
-int cmExpr_yyparse (yyscan_t yyscanner);
+#ifdef short
+# undef short
+#endif
 
-#endif /* !YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED  */
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+   <limits.h> and (if available) <stdint.h> are included
+   so that the code can choose integer types of a good width.  */
 
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+#  define YY_STDINT_H
+# endif
+#endif
 
+/* Narrow types that promote to a signed type and that can represent a
+   signed or unsigned integer of at least N bits.  In tables they can
+   save space and decrease cache pressure.  Promoting to a signed type
+   helps avoid bugs in integer arithmetic.  */
 
-#ifdef short
-# undef short
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
 #endif
 
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
 #else
-typedef unsigned char yytype_uint8;
+typedef short yytype_int16;
 #endif
 
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
 #else
-typedef signed char yytype_int8;
+typedef short yytype_uint8;
 #endif
 
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
 typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
 #endif
 
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short yytype_int16;
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+#  define YYPTRDIFF_T __PTRDIFF_TYPE__
+#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+#  ifndef ptrdiff_t
+#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  endif
+#  define YYPTRDIFF_T ptrdiff_t
+#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+#  define YYPTRDIFF_T long
+#  define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
 #endif
 
 #ifndef YYSIZE_T
@@ -230,7 +261,7 @@ typedef short yytype_int16;
 #  define YYSIZE_T __SIZE_TYPE__
 # elif defined size_t
 #  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
 #  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
 #  define YYSIZE_T size_t
 # else
@@ -238,7 +269,20 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+#define YYSIZE_MAXIMUM                                  \
+  YY_CAST (YYPTRDIFF_T,                                 \
+           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
+            ? YYPTRDIFF_MAXIMUM                         \
+            : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int8 yy_state_t;
+
+/* State numbers in computations.  */
+typedef int yy_state_fast_t;
 
 #ifndef YY_
 # if defined YYENABLE_NLS && YYENABLE_NLS
@@ -252,22 +296,21 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#ifndef YY_ATTRIBUTE
-# if (defined __GNUC__                                               \
-      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
-     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
-#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
-# else
-#  define YY_ATTRIBUTE(Spec) /* empty */
-# endif
-#endif
 
 #ifndef YY_ATTRIBUTE_PURE
-# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define YY_ATTRIBUTE_PURE
+# endif
 #endif
 
 #ifndef YY_ATTRIBUTE_UNUSED
-# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+#  define YY_ATTRIBUTE_UNUSED
+# endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
@@ -279,11 +322,11 @@ typedef short yytype_int16;
 
 #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
 /* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
-    _Pragma ("GCC diagnostic push") \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                            \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
     _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
     _Pragma ("GCC diagnostic pop")
 #else
 # define YY_INITIAL_VALUE(Value) Value
@@ -296,10 +339,22 @@ typedef short yytype_int16;
 # define YY_INITIAL_VALUE(Value) /* Nothing. */
 #endif
 
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN                          \
+    _Pragma ("GCC diagnostic push")                            \
+    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END            \
+    _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
 
 #define YY_ASSERT(E) ((void) (0 && (E)))
 
-#if ! defined yyoverflow || YYERROR_VERBOSE
+#if 1
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
@@ -364,8 +419,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 # endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
+#endif /* 1 */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus \
@@ -374,17 +428,17 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  yytype_int16 yyss_alloc;
+  yy_state_t yyss_alloc;
   YYSTYPE yyvs_alloc;
 };
 
 /* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
 
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
       + YYSTACK_GAP_MAXIMUM)
 
 # define YYCOPY_NEEDED 1
@@ -397,11 +451,11 @@ union yyalloc
 # define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
     do                                                                  \
       {                                                                 \
-        YYSIZE_T yynewbytes;                                            \
+        YYPTRDIFF_T yynewbytes;                                         \
         YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
         Stack = &yyptr->Stack_alloc;                                    \
-        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-        yyptr += yynewbytes / sizeof (*yyptr);                          \
+        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
       }                                                                 \
     while (0)
 
@@ -413,12 +467,12 @@ union yyalloc
 # ifndef YYCOPY
 #  if defined __GNUC__ && 1 < __GNUC__
 #   define YYCOPY(Dst, Src, Count) \
-      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
 #  else
 #   define YYCOPY(Dst, Src, Count)              \
       do                                        \
         {                                       \
-          YYSIZE_T yyi;                         \
+          YYPTRDIFF_T yyi;                      \
           for (yyi = 0; yyi < (Count); yyi++)   \
             (Dst)[yyi] = (Src)[yyi];            \
         }                                       \
@@ -441,17 +495,20 @@ union yyalloc
 /* YYNSTATES -- Number of states.  */
 #define YYNSTATES  41
 
-#define YYUNDEFTOK  2
+/* YYMAXUTOK -- Last valid token kind.  */
 #define YYMAXUTOK   271
 
+
 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex, with out-of-bounds checking.  */
-#define YYTRANSLATE(YYX)                                                \
-  ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+#define YYTRANSLATE(YYX)                                \
+  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
+   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
+   : YYSYMBOL_YYUNDEF)
 
 /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex.  */
-static const yytype_uint8 yytranslate[] =
+static const yytype_int8 yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -487,43 +544,57 @@ static const yytype_uint8 yytranslate[] =
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    77,    77,    82,    85,    90,    93,    98,   101,   106,
-     109,   112,   117,   120,   123,   128,   131,   134,   140,   145,
-     148,   151,   154,   159,   162
+       0,    81,    81,    86,    89,    94,    97,   102,   105,   110,
+     113,   116,   121,   124,   127,   132,   135,   138,   144,   149,
+     152,   155,   158,   163,   166
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || 1
+/** Accessing symbol of state STATE.  */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+   YYSYMBOL.  No bounds checking.  */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "exp_PLUS", "exp_MINUS", "exp_TIMES",
-  "exp_DIVIDE", "exp_MOD", "exp_SHIFTLEFT", "exp_SHIFTRIGHT",
-  "exp_OPENPARENT", "exp_CLOSEPARENT", "exp_OR", "exp_AND", "exp_XOR",
-  "exp_NOT", "exp_NUMBER", "$accept", "start", "exp", "bitwiseor",
-  "bitwisexor", "bitwiseand", "shift", "term", "unary", "factor", YY_NULLPTR
+  "\"end of file\"", "error", "\"invalid token\"", "exp_PLUS",
+  "exp_MINUS", "exp_TIMES", "exp_DIVIDE", "exp_MOD", "exp_SHIFTLEFT",
+  "exp_SHIFTRIGHT", "exp_OPENPARENT", "exp_CLOSEPARENT", "exp_OR",
+  "exp_AND", "exp_XOR", "exp_NOT", "exp_NUMBER", "$accept", "start", "exp",
+  "bitwiseor", "bitwisexor", "bitwiseand", "shift", "term", "unary",
+  "factor", YY_NULLPTR
 };
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+  return yytname[yysymbol];
+}
 #endif
 
-# ifdef YYPRINT
+#ifdef YYPRINT
 /* YYTOKNUM[NUM] -- (External) token number corresponding to the
    (internal) symbol number NUM (which must be that of a token).  */
-static const yytype_uint16 yytoknum[] =
+static const yytype_int16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271
 };
-# endif
+#endif
 
-#define YYPACT_NINF -11
+#define YYPACT_NINF (-11)
 
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-11)))
+#define yypact_value_is_default(Yyn) \
+  ((Yyn) == YYPACT_NINF)
 
-#define YYTABLE_NINF -1
+#define YYTABLE_NINF (-1)
 
-#define yytable_value_is_error(Yytable_value) \
+#define yytable_value_is_error(Yyn) \
   0
 
   /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
@@ -540,7 +611,7 @@ static const yytype_int8 yypact[] =
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
      Performed when YYTABLE does not specify something else to do.  Zero
      means the default is an error.  */
-static const yytype_uint8 yydefact[] =
+static const yytype_int8 yydefact[] =
 {
        0,     0,     0,     0,     0,    23,     0,     2,     3,     5,
        7,     9,    12,    15,    19,    20,    21,     0,    22,     1,
@@ -564,7 +635,7 @@ static const yytype_int8 yydefgoto[] =
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
      positive, shift that token.  If negative, reduce the rule whose
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
-static const yytype_uint8 yytable[] =
+static const yytype_int8 yytable[] =
 {
       15,    16,    20,    18,     1,     2,    19,    27,    28,    29,
       21,     3,    23,    24,    25,    26,     4,     5,    30,    20,
@@ -582,7 +653,7 @@ static const yytype_int8 yycheck[] =
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
+static const yytype_int8 yystos[] =
 {
        0,     3,     4,    10,    15,    16,    18,    19,    20,    21,
       22,    23,    24,    25,    26,    25,    25,    19,    25,     0,
@@ -592,7 +663,7 @@ static const yytype_uint8 yystos[] =
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
+static const yytype_int8 yyr1[] =
 {
        0,    17,    18,    19,    19,    20,    20,    21,    21,    22,
       22,    22,    23,    23,    23,    24,    24,    24,    24,    25,
@@ -600,7 +671,7 @@ static const yytype_uint8 yyr1[] =
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
+static const yytype_int8 yyr2[] =
 {
        0,     2,     1,     1,     3,     1,     3,     1,     3,     1,
        3,     3,     1,     3,     3,     1,     3,     3,     3,     1,
@@ -608,10 +679,10 @@ static const yytype_uint8 yyr2[] =
 };
 
 
+enum { YYENOMEM = -2 };
+
 #define yyerrok         (yyerrstatus = 0)
 #define yyclearin       (yychar = YYEMPTY)
-#define YYEMPTY         (-2)
-#define YYEOF           0
 
 #define YYACCEPT        goto yyacceptlab
 #define YYABORT         goto yyabortlab
@@ -637,10 +708,9 @@ static const yytype_uint8 yyr2[] =
       }                                                           \
   while (0)
 
-/* Error token number */
-#define YYTERROR        1
-#define YYERRCODE       256
-
+/* Backward compatibility with an undocumented macro.
+   Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
 
 
 /* Enable debugging if requested.  */
@@ -658,18 +728,18 @@ do {                                            \
 } while (0)
 
 /* This macro is provided for backward compatibility. */
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
+# ifndef YY_LOCATION_PRINT
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
 
 
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
 do {                                                                      \
   if (yydebug)                                                            \
     {                                                                     \
       YYFPRINTF (stderr, "%s ", Title);                                   \
       yy_symbol_print (stderr,                                            \
-                  Type, Value, yyscanner); \
+                  Kind, Value, yyscanner); \
       YYFPRINTF (stderr, "\n");                                           \
     }                                                                     \
 } while (0)
@@ -680,7 +750,8 @@ do {                                                                      \
 `-----------------------------------*/
 
 static void
-yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_value_print (FILE *yyo,
+                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   FILE *yyoutput = yyo;
   YYUSE (yyoutput);
@@ -688,11 +759,11 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
   if (!yyvaluep)
     return;
 # ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
+  if (yykind < YYNTOKENS)
+    YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
 # endif
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
@@ -702,12 +773,13 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
 `---------------------------*/
 
 static void
-yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_print (FILE *yyo,
+                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   YYFPRINTF (yyo, "%s %s (",
-             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
 
-  yy_symbol_value_print (yyo, yytype, yyvaluep, yyscanner);
+  yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
   YYFPRINTF (yyo, ")");
 }
 
@@ -717,7 +789,7 @@ yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t
 `------------------------------------------------------------------*/
 
 static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
 {
   YYFPRINTF (stderr, "Stack now");
   for (; yybottom <= yytop; yybottom++)
@@ -740,21 +812,21 @@ do {                                                            \
 `------------------------------------------------*/
 
 static void
-yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, yyscan_t yyscanner)
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+                 int yyrule, yyscan_t yyscanner)
 {
-  unsigned long yylno = yyrline[yyrule];
+  int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
   int yyi;
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
              yyrule - 1, yylno);
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr,
-                       yystos[yyssp[yyi + 1 - yynrhs]],
-                       &yyvsp[(yyi + 1) - (yynrhs)]
-                                              , yyscanner);
+                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+                       &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -769,8 +841,8 @@ do {                                    \
    multiple parsers can coexist.  */
 int yydebug;
 #else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
 # define YY_STACK_PRINT(Bottom, Top)
 # define YY_REDUCE_PRINT(Rule)
 #endif /* !YYDEBUG */
@@ -793,28 +865,76 @@ int yydebug;
 #endif
 
 
-#if YYERROR_VERBOSE
+/* Context of a parse error.  */
+typedef struct
+{
+  yy_state_t *yyssp;
+  yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+   current YYCTX, and return the number of tokens stored in YYARG.  If
+   YYARG is null, return the number of expected tokens (guaranteed to
+   be less than YYNTOKENS).  Return YYENOMEM on memory exhaustion.
+   Return 0 if there are more than YYARGN expected tokens, yet fill
+   YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+                            yysymbol_kind_t yyarg[], int yyargn)
+{
+  /* Actual size of YYARG. */
+  int yycount = 0;
+  int yyn = yypact[+*yyctx->yyssp];
+  if (!yypact_value_is_default (yyn))
+    {
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+         YYCHECK.  In other words, skip the first -YYN actions for
+         this state because they are default actions.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yyx;
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+        if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+            && !yytable_value_is_error (yytable[yyx + yyn]))
+          {
+            if (!yyarg)
+              ++yycount;
+            else if (yycount == yyargn)
+              return 0;
+            else
+              yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+          }
+    }
+  if (yyarg && yycount == 0 && 0 < yyargn)
+    yyarg[0] = YYSYMBOL_YYEMPTY;
+  return yycount;
+}
 
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+#  define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
 /* Return the length of YYSTR.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yystrlen (const char *yystr)
 {
-  YYSIZE_T yylen;
+  YYPTRDIFF_T yylen;
   for (yylen = 0; yystr[yylen]; yylen++)
     continue;
   return yylen;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#  define yystpcpy stpcpy
+# else
 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    YYDEST.  */
 static char *
@@ -828,10 +948,10 @@ yystpcpy (char *yydest, const char *yysrc)
 
   return yyd - 1;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yytnamerr
+#ifndef yytnamerr
 /* Copy to YYRES the contents of YYSTR after stripping away unnecessary
    quotes and backslashes, so that it's suitable for yyerror.  The
    heuristic is that double-quoting is unnecessary unless the string
@@ -839,14 +959,13 @@ yystpcpy (char *yydest, const char *yysrc)
    backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
    null, do not copy; instead, return the length of what the result
    would have been.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yytnamerr (char *yyres, const char *yystr)
 {
   if (*yystr == '"')
     {
-      YYSIZE_T yyn = 0;
+      YYPTRDIFF_T yyn = 0;
       char const *yyp = yystr;
-
       for (;;)
         switch (*++yyp)
           {
@@ -875,36 +994,20 @@ yytnamerr (char *yyres, const char *yystr)
     do_not_strip_quotes: ;
     }
 
-  if (! yyres)
+  if (yyres)
+    return yystpcpy (yyres, yystr) - yyres;
+  else
     return yystrlen (yystr);
-
-  return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres);
 }
-# endif
+#endif
 
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN for the state stack whose top is
-   YYSSP.
 
-   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
-   not large enough to hold the message.  In that case, also set
-   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
-   required number of bytes is too large to store.  */
 static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                yytype_int16 *yyssp, int yytoken)
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+                           yysymbol_kind_t yyarg[], int yyargn)
 {
-  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
-  YYSIZE_T yysize = yysize0;
-  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-  /* Internationalized format string. */
-  const char *yyformat = YY_NULLPTR;
-  /* Arguments of yyformat. */
-  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-  /* Number of reported tokens (one for the "unexpected", one per
-     "expected"). */
+  /* Actual size of YYARG. */
   int yycount = 0;
-
   /* There are many possibilities here to consider:
      - If this state is a consistent state with a default action, then
        the only way this function was invoked is if the default action
@@ -928,49 +1031,54 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
        one exception: it will still contain any token that will not be
        accepted due to an error action in a later state.
   */
-  if (yytoken != YYEMPTY)
+  if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
     {
-      int yyn = yypact[*yyssp];
-      yyarg[yycount++] = yytname[yytoken];
-      if (!yypact_value_is_default (yyn))
-        {
-          /* Start YYX at -YYN if negative to avoid negative indexes in
-             YYCHECK.  In other words, skip the first -YYN actions for
-             this state because they are default actions.  */
-          int yyxbegin = yyn < 0 ? -yyn : 0;
-          /* Stay within bounds of both yycheck and yytname.  */
-          int yychecklim = YYLAST - yyn + 1;
-          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-          int yyx;
-
-          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
-                && !yytable_value_is_error (yytable[yyx + yyn]))
-              {
-                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-                  {
-                    yycount = 1;
-                    yysize = yysize0;
-                    break;
-                  }
-                yyarg[yycount++] = yytname[yyx];
-                {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
-                  if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-                    yysize = yysize1;
-                  else
-                    return 2;
-                }
-              }
-        }
+      int yyn;
+      if (yyarg)
+        yyarg[yycount] = yyctx->yytoken;
+      ++yycount;
+      yyn = yypcontext_expected_tokens (yyctx,
+                                        yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+      if (yyn == YYENOMEM)
+        return YYENOMEM;
+      else
+        yycount += yyn;
     }
+  return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return -1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return YYENOMEM if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+                const yypcontext_t *yyctx)
+{
+  enum { YYARGS_MAX = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat: reported tokens (one for the "unexpected",
+     one per "expected"). */
+  yysymbol_kind_t yyarg[YYARGS_MAX];
+  /* Cumulated lengths of YYARG.  */
+  YYPTRDIFF_T yysize = 0;
+
+  /* Actual size of YYARG. */
+  int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+  if (yycount == YYENOMEM)
+    return YYENOMEM;
 
   switch (yycount)
     {
-# define YYCASE_(N, S)                      \
+#define YYCASE_(N, S)                       \
       case N:                               \
         yyformat = S;                       \
-      break
+        break
     default: /* Avoid compiler warnings. */
       YYCASE_(0, YY_("syntax error"));
       YYCASE_(1, YY_("syntax error, unexpected %s"));
@@ -978,15 +1086,23 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
+#undef YYCASE_
     }
 
+  /* Compute error message size.  Don't count the "%s"s, but reserve
+     room for the terminator.  */
+  yysize = yystrlen (yyformat) - 2 * yycount + 1;
   {
-    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
-    if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-      yysize = yysize1;
-    else
-      return 2;
+    int yyi;
+    for (yyi = 0; yyi < yycount; ++yyi)
+      {
+        YYPTRDIFF_T yysize1
+          = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+        if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+          yysize = yysize1;
+        else
+          return YYENOMEM;
+      }
   }
 
   if (*yymsg_alloc < yysize)
@@ -995,7 +1111,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       if (! (yysize <= *yymsg_alloc
              && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
         *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
-      return 1;
+      return -1;
     }
 
   /* Avoid sprintf, as that infringes on the user's name space.
@@ -1007,40 +1123,43 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
     while ((*yyp = *yyformat) != '\0')
       if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
         {
-          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
           yyformat += 2;
         }
       else
         {
-          yyp++;
-          yyformat++;
+          ++yyp;
+          ++yyformat;
         }
   }
   return 0;
 }
-#endif /* YYERROR_VERBOSE */
+
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
 `-----------------------------------------------*/
 
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+yydestruct (const char *yymsg,
+            yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
 {
   YYUSE (yyvaluep);
   YYUSE (yyscanner);
   if (!yymsg)
     yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
 
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
 
 
+
+
 /*----------.
 | yyparse.  |
 `----------*/
@@ -1048,7 +1167,7 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner
 int
 yyparse (yyscan_t yyscanner)
 {
-/* The lookahead symbol.  */
+/* Lookahead token kind.  */
 int yychar;
 
 
@@ -1059,45 +1178,41 @@ YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
 YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
 
     /* Number of syntax errors so far.  */
-    int yynerrs;
+    int yynerrs = 0;
 
-    int yystate;
+    yy_state_fast_t yystate = 0;
     /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus;
-
-    /* The stacks and their tools:
-       'yyss': related to states.
-       'yyvs': related to semantic values.
+    int yyerrstatus = 0;
 
-       Refer to the stacks through separate pointers, to allow yyoverflow
+    /* Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
 
-    /* The state stack.  */
-    yytype_int16 yyssa[YYINITDEPTH];
-    yytype_int16 *yyss;
-    yytype_int16 *yyssp;
+    /* Their size.  */
+    YYPTRDIFF_T yystacksize = YYINITDEPTH;
 
-    /* The semantic value stack.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs;
-    YYSTYPE *yyvsp;
+    /* The state stack: array, bottom, top.  */
+    yy_state_t yyssa[YYINITDEPTH];
+    yy_state_t *yyss = yyssa;
+    yy_state_t *yyssp = yyss;
 
-    YYSIZE_T yystacksize;
+    /* The semantic value stack: array, bottom, top.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs = yyvsa;
+    YYSTYPE *yyvsp = yyvs;
 
   int yyn;
+  /* The return value of yyparse.  */
   int yyresult;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken = 0;
+  /* Lookahead symbol kind.  */
+  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
 
-#if YYERROR_VERBOSE
   /* Buffer for error messages, and its allocated size.  */
   char yymsgbuf[128];
   char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
+  YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
 
 #define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
 
@@ -1105,15 +1220,8 @@ YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
 
-  yyssp = yyss = yyssa;
-  yyvsp = yyvs = yyvsa;
-  yystacksize = YYINITDEPTH;
-
   YYDPRINTF ((stderr, "Starting parse\n"));
 
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
   yychar = YYEMPTY; /* Cause a token to be read.  */
   goto yysetstate;
 
@@ -1128,12 +1236,15 @@ yynewstate:
 
 
 /*--------------------------------------------------------------------.
-| yynewstate -- set current state (the top of the stack) to yystate.  |
+| yysetstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
   YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
-  *yyssp = (yytype_int16) yystate;
+  YY_IGNORE_USELESS_CAST_BEGIN
+  *yyssp = YY_CAST (yy_state_t, yystate);
+  YY_IGNORE_USELESS_CAST_END
+  YY_STACK_PRINT (yyss, yyssp);
 
   if (yyss + yystacksize - 1 <= yyssp)
 #if !defined yyoverflow && !defined YYSTACK_RELOCATE
@@ -1141,23 +1252,23 @@ yysetstate:
 #else
     {
       /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1);
+      YYPTRDIFF_T yysize = yyssp - yyss + 1;
 
 # if defined yyoverflow
       {
         /* Give user a chance to reallocate the stack.  Use copies of
            these so that the &'s don't force the real ones into
            memory.  */
+        yy_state_t *yyss1 = yyss;
         YYSTYPE *yyvs1 = yyvs;
-        yytype_int16 *yyss1 = yyss;
 
         /* Each stack pointer address is followed by the size of the
            data in use in that stack, in bytes.  This used to be a
            conditional around just the two extra args, but that might
            be undefined if yyoverflow is a macro.  */
         yyoverflow (YY_("memory exhausted"),
-                    &yyss1, yysize * sizeof (*yyssp),
-                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yyss1, yysize * YYSIZEOF (*yyssp),
+                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
                     &yystacksize);
         yyss = yyss1;
         yyvs = yyvs1;
@@ -1171,14 +1282,15 @@ yysetstate:
         yystacksize = YYMAXDEPTH;
 
       {
-        yytype_int16 *yyss1 = yyss;
+        yy_state_t *yyss1 = yyss;
         union yyalloc *yyptr =
-          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+          YY_CAST (union yyalloc *,
+                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
         if (! yyptr)
           goto yyexhaustedlab;
         YYSTACK_RELOCATE (yyss_alloc, yyss);
         YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-# undef YYSTACK_RELOCATE
+#  undef YYSTACK_RELOCATE
         if (yyss1 != yyssa)
           YYSTACK_FREE (yyss1);
       }
@@ -1187,8 +1299,10 @@ yysetstate:
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
 
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                  (unsigned long) yystacksize));
+      YY_IGNORE_USELESS_CAST_BEGIN
+      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+                  YY_CAST (long, yystacksize)));
+      YY_IGNORE_USELESS_CAST_END
 
       if (yyss + yystacksize - 1 <= yyssp)
         YYABORT;
@@ -1215,18 +1329,29 @@ yybackup:
 
   /* Not known => get a lookahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
   if (yychar == YYEMPTY)
     {
-      YYDPRINTF ((stderr, "Reading a token"));
+      YYDPRINTF ((stderr, "Reading a token\n"));
       yychar = yylex (&yylval, yyscanner);
     }
 
   if (yychar <= YYEOF)
     {
-      yychar = yytoken = YYEOF;
+      yychar = YYEOF;
+      yytoken = YYSYMBOL_YYEOF;
       YYDPRINTF ((stderr, "Now at end of input.\n"));
     }
+  else if (yychar == YYerror)
+    {
+      /* The scanner already issued an error message, process directly
+         to error recovery.  But do not keep the error token as
+         lookahead, it is too special and may lead us to an endless
+         loop in error recovery. */
+      yychar = YYUNDEF;
+      yytoken = YYSYMBOL_YYerror;
+      goto yyerrlab1;
+    }
   else
     {
       yytoken = YYTRANSLATE (yychar);
@@ -1254,14 +1379,13 @@ yybackup:
 
   /* Shift the lookahead token.  */
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-
   yystate = yyn;
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
   goto yynewstate;
 
 
@@ -1296,195 +1420,195 @@ yyreduce:
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-  case 2:
-#line 77 "cmExprParser.y"
-    {
+  case 2: /* start: exp  */
+#line 81 "cmExprParser.y"
+      {
     cmExpr_yyget_extra(yyscanner)->SetResult((yyvsp[0].Number));
   }
-#line 1305 "cmExprParser.cxx"
+#line 1429 "cmExprParser.cxx"
     break;
 
-  case 3:
-#line 82 "cmExprParser.y"
-    {
+  case 3: /* exp: bitwiseor  */
+#line 86 "cmExprParser.y"
+            {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1313 "cmExprParser.cxx"
+#line 1437 "cmExprParser.cxx"
     break;
 
-  case 4:
-#line 85 "cmExprParser.y"
-    {
+  case 4: /* exp: exp exp_OR bitwiseor  */
+#line 89 "cmExprParser.y"
+                       {
     (yyval.Number) = (yyvsp[-2].Number) | (yyvsp[0].Number);
   }
-#line 1321 "cmExprParser.cxx"
+#line 1445 "cmExprParser.cxx"
     break;
 
-  case 5:
-#line 90 "cmExprParser.y"
-    {
+  case 5: /* bitwiseor: bitwisexor  */
+#line 94 "cmExprParser.y"
+             {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1329 "cmExprParser.cxx"
+#line 1453 "cmExprParser.cxx"
     break;
 
-  case 6:
-#line 93 "cmExprParser.y"
-    {
+  case 6: /* bitwiseor: bitwiseor exp_XOR bitwisexor  */
+#line 97 "cmExprParser.y"
+                               {
     (yyval.Number) = (yyvsp[-2].Number) ^ (yyvsp[0].Number);
   }
-#line 1337 "cmExprParser.cxx"
+#line 1461 "cmExprParser.cxx"
     break;
 
-  case 7:
-#line 98 "cmExprParser.y"
-    {
+  case 7: /* bitwisexor: bitwiseand  */
+#line 102 "cmExprParser.y"
+             {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1345 "cmExprParser.cxx"
+#line 1469 "cmExprParser.cxx"
     break;
 
-  case 8:
-#line 101 "cmExprParser.y"
-    {
+  case 8: /* bitwisexor: bitwisexor exp_AND bitwiseand  */
+#line 105 "cmExprParser.y"
+                                {
     (yyval.Number) = (yyvsp[-2].Number) & (yyvsp[0].Number);
   }
-#line 1353 "cmExprParser.cxx"
+#line 1477 "cmExprParser.cxx"
     break;
 
-  case 9:
-#line 106 "cmExprParser.y"
-    {
+  case 9: /* bitwiseand: shift  */
+#line 110 "cmExprParser.y"
+        {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1361 "cmExprParser.cxx"
+#line 1485 "cmExprParser.cxx"
     break;
 
-  case 10:
-#line 109 "cmExprParser.y"
-    {
+  case 10: /* bitwiseand: bitwiseand exp_SHIFTLEFT shift  */
+#line 113 "cmExprParser.y"
+                                 {
     (yyval.Number) = (yyvsp[-2].Number) << (yyvsp[0].Number);
   }
-#line 1369 "cmExprParser.cxx"
+#line 1493 "cmExprParser.cxx"
     break;
 
-  case 11:
-#line 112 "cmExprParser.y"
-    {
+  case 11: /* bitwiseand: bitwiseand exp_SHIFTRIGHT shift  */
+#line 116 "cmExprParser.y"
+                                  {
     (yyval.Number) = (yyvsp[-2].Number) >> (yyvsp[0].Number);
   }
-#line 1377 "cmExprParser.cxx"
+#line 1501 "cmExprParser.cxx"
     break;
 
-  case 12:
-#line 117 "cmExprParser.y"
-    {
+  case 12: /* shift: term  */
+#line 121 "cmExprParser.y"
+       {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1385 "cmExprParser.cxx"
+#line 1509 "cmExprParser.cxx"
     break;
 
-  case 13:
-#line 120 "cmExprParser.y"
-    {
+  case 13: /* shift: shift exp_PLUS term  */
+#line 124 "cmExprParser.y"
+                      {
     (yyval.Number) = (yyvsp[-2].Number) + (yyvsp[0].Number);
   }
-#line 1393 "cmExprParser.cxx"
+#line 1517 "cmExprParser.cxx"
     break;
 
-  case 14:
-#line 123 "cmExprParser.y"
-    {
+  case 14: /* shift: shift exp_MINUS term  */
+#line 127 "cmExprParser.y"
+                       {
     (yyval.Number) = (yyvsp[-2].Number) - (yyvsp[0].Number);
   }
-#line 1401 "cmExprParser.cxx"
+#line 1525 "cmExprParser.cxx"
     break;
 
-  case 15:
-#line 128 "cmExprParser.y"
-    {
+  case 15: /* term: unary  */
+#line 132 "cmExprParser.y"
+        {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1409 "cmExprParser.cxx"
+#line 1533 "cmExprParser.cxx"
     break;
 
-  case 16:
-#line 131 "cmExprParser.y"
-    {
+  case 16: /* term: term exp_TIMES unary  */
+#line 135 "cmExprParser.y"
+                       {
     (yyval.Number) = (yyvsp[-2].Number) * (yyvsp[0].Number);
   }
-#line 1417 "cmExprParser.cxx"
+#line 1541 "cmExprParser.cxx"
     break;
 
-  case 17:
-#line 134 "cmExprParser.y"
-    {
+  case 17: /* term: term exp_DIVIDE unary  */
+#line 138 "cmExprParser.y"
+                        {
     if (yyvsp[0].Number == 0) {
       throw std::overflow_error("divide by zero");
     }
     (yyval.Number) = (yyvsp[-2].Number) / (yyvsp[0].Number);
   }
-#line 1428 "cmExprParser.cxx"
+#line 1552 "cmExprParser.cxx"
     break;
 
-  case 18:
-#line 140 "cmExprParser.y"
-    {
+  case 18: /* term: term exp_MOD unary  */
+#line 144 "cmExprParser.y"
+                     {
     (yyval.Number) = (yyvsp[-2].Number) % (yyvsp[0].Number);
   }
-#line 1436 "cmExprParser.cxx"
+#line 1560 "cmExprParser.cxx"
     break;
 
-  case 19:
-#line 145 "cmExprParser.y"
-    {
+  case 19: /* unary: factor  */
+#line 149 "cmExprParser.y"
+         {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1444 "cmExprParser.cxx"
+#line 1568 "cmExprParser.cxx"
     break;
 
-  case 20:
-#line 148 "cmExprParser.y"
-    {
+  case 20: /* unary: exp_PLUS unary  */
+#line 152 "cmExprParser.y"
+                 {
     (yyval.Number) = + (yyvsp[0].Number);
   }
-#line 1452 "cmExprParser.cxx"
+#line 1576 "cmExprParser.cxx"
     break;
 
-  case 21:
-#line 151 "cmExprParser.y"
-    {
+  case 21: /* unary: exp_MINUS unary  */
+#line 155 "cmExprParser.y"
+                  {
     (yyval.Number) = - (yyvsp[0].Number);
   }
-#line 1460 "cmExprParser.cxx"
+#line 1584 "cmExprParser.cxx"
     break;
 
-  case 22:
-#line 154 "cmExprParser.y"
-    {
+  case 22: /* unary: exp_NOT unary  */
+#line 158 "cmExprParser.y"
+                {
     (yyval.Number) = ~ (yyvsp[0].Number);
   }
-#line 1468 "cmExprParser.cxx"
+#line 1592 "cmExprParser.cxx"
     break;
 
-  case 23:
-#line 159 "cmExprParser.y"
-    {
+  case 23: /* factor: exp_NUMBER  */
+#line 163 "cmExprParser.y"
+             {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1476 "cmExprParser.cxx"
+#line 1600 "cmExprParser.cxx"
     break;
 
-  case 24:
-#line 162 "cmExprParser.y"
-    {
+  case 24: /* factor: exp_OPENPARENT exp exp_CLOSEPARENT  */
+#line 166 "cmExprParser.y"
+                                     {
     (yyval.Number) = (yyvsp[-1].Number);
   }
-#line 1484 "cmExprParser.cxx"
+#line 1608 "cmExprParser.cxx"
     break;
 
 
-#line 1488 "cmExprParser.cxx"
+#line 1612 "cmExprParser.cxx"
 
       default: break;
     }
@@ -1499,11 +1623,10 @@ yyreduce:
      case of YYERROR or YYBACKUP, subsequent parser actions might lead
      to an incorrect destructor call or verbose syntax error message
      before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
   yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
 
   *++yyvsp = yyval;
 
@@ -1527,50 +1650,44 @@ yyreduce:
 yyerrlab:
   /* Make sure we have latest lookahead translation.  See comments at
      user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
+  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
       ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (yyscanner, YY_("syntax error"));
-#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
-                                        yyssp, yytoken)
       {
+        yypcontext_t yyctx
+          = {yyssp, yytoken};
         char const *yymsgp = YY_("syntax error");
         int yysyntax_error_status;
-        yysyntax_error_status = YYSYNTAX_ERROR;
+        yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
-        else if (yysyntax_error_status == 1)
+        else if (yysyntax_error_status == -1)
           {
             if (yymsg != yymsgbuf)
               YYSTACK_FREE (yymsg);
-            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
-            if (!yymsg)
+            yymsg = YY_CAST (char *,
+                             YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+            if (yymsg)
               {
-                yymsg = yymsgbuf;
-                yymsg_alloc = sizeof yymsgbuf;
-                yysyntax_error_status = 2;
+                yysyntax_error_status
+                  = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+                yymsgp = yymsg;
               }
             else
               {
-                yysyntax_error_status = YYSYNTAX_ERROR;
-                yymsgp = yymsg;
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = YYENOMEM;
               }
           }
         yyerror (yyscanner, yymsgp);
-        if (yysyntax_error_status == 2)
+        if (yysyntax_error_status == YYENOMEM)
           goto yyexhaustedlab;
       }
-# undef YYSYNTAX_ERROR
-#endif
     }
 
-
-
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
@@ -1590,7 +1707,6 @@ yyerrlab:
         }
     }
 
-#if 0
   /* Else will try to reuse lookahead token after shifting the error
      token.  */
   goto yyerrlab1;
@@ -1618,16 +1734,16 @@ yyerrorlab:
 | yyerrlab1 -- common code for both syntax error and YYERROR.  |
 `-------------------------------------------------------------*/
 yyerrlab1:
-#endif
   yyerrstatus = 3;      /* Each real token shifted decrements this.  */
 
+  /* Pop stack until we find a state that shifts the error token.  */
   for (;;)
     {
       yyn = yypact[yystate];
       if (!yypact_value_is_default (yyn))
         {
-          yyn += YYTERROR;
-          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+          yyn += YYSYMBOL_YYerror;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
             {
               yyn = yytable[yyn];
               if (0 < yyn)
@@ -1641,7 +1757,7 @@ yyerrlab1:
 
 
       yydestruct ("Error: popping",
-                  yystos[yystate], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -1653,7 +1769,7 @@ yyerrlab1:
 
 
   /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
 
   yystate = yyn;
   goto yynewstate;
@@ -1675,20 +1791,20 @@ yyabortlab:
   goto yyreturn;
 
 
-#if !defined yyoverflow || YYERROR_VERBOSE
+#if 1
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
   yyerror (yyscanner, YY_("memory exhausted"));
   yyresult = 2;
-  /* Fall through.  */
+  goto yyreturn;
 #endif
 
 
-/*-----------------------------------------------------.
-| yyreturn -- parsing is finished, return the result.  |
-`-----------------------------------------------------*/
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return.  |
+`-------------------------------------------------------*/
 yyreturn:
   if (yychar != YYEMPTY)
     {
@@ -1705,20 +1821,19 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                  yystos[*yyssp], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
   if (yyss != yyssa)
     YYSTACK_FREE (yyss);
 #endif
-#if YYERROR_VERBOSE
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
-#endif
   return yyresult;
 }
-#line 167 "cmExprParser.y"
+
+#line 171 "cmExprParser.y"
 
 /* End of grammar */
 
index 7ae2118..b49f482 100644 (file)
@@ -7,15 +7,13 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h -ocmExprParser.cxx cmExprParser.y
-
-Modify cmExprParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
+  bison --name-prefix=cmExpr_yy --defines=cmExprParserTokens.h -ocmExprParser.cxx cmExprParser.y
 
 */
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdexcept>
@@ -39,6 +37,12 @@ static void cmExpr_yyerror(yyscan_t yyscanner, const char* message);
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+#endif
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wused-but-marked-unused")
+#  pragma clang diagnostic ignored "-Wused-but-marked-unused"
+# endif
 #endif
 %}
 
index e30a832..2eb1fe9 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -31,8 +31,9 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
 
 #ifndef YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
 # define YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
 extern int cmExpr_yydebug;
 #endif
 
-/* Token type.  */
+/* Token kinds.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
   enum yytokentype
   {
-    exp_PLUS = 258,
-    exp_MINUS = 259,
-    exp_TIMES = 260,
-    exp_DIVIDE = 261,
-    exp_MOD = 262,
-    exp_SHIFTLEFT = 263,
-    exp_SHIFTRIGHT = 264,
-    exp_OPENPARENT = 265,
-    exp_CLOSEPARENT = 266,
-    exp_OR = 267,
-    exp_AND = 268,
-    exp_XOR = 269,
-    exp_NOT = 270,
-    exp_NUMBER = 271
+    YYEMPTY = -2,
+    YYEOF = 0,                     /* "end of file"  */
+    YYerror = 256,                 /* error  */
+    YYUNDEF = 257,                 /* "invalid token"  */
+    exp_PLUS = 258,                /* exp_PLUS  */
+    exp_MINUS = 259,               /* exp_MINUS  */
+    exp_TIMES = 260,               /* exp_TIMES  */
+    exp_DIVIDE = 261,              /* exp_DIVIDE  */
+    exp_MOD = 262,                 /* exp_MOD  */
+    exp_SHIFTLEFT = 263,           /* exp_SHIFTLEFT  */
+    exp_SHIFTRIGHT = 264,          /* exp_SHIFTRIGHT  */
+    exp_OPENPARENT = 265,          /* exp_OPENPARENT  */
+    exp_CLOSEPARENT = 266,         /* exp_CLOSEPARENT  */
+    exp_OR = 267,                  /* exp_OR  */
+    exp_AND = 268,                 /* exp_AND  */
+    exp_XOR = 269,                 /* exp_XOR  */
+    exp_NOT = 270,                 /* exp_NOT  */
+    exp_NUMBER = 271               /* exp_NUMBER  */
   };
+  typedef enum yytokentype yytoken_kind_t;
 #endif
-/* Tokens.  */
-#define exp_PLUS 258
-#define exp_MINUS 259
-#define exp_TIMES 260
-#define exp_DIVIDE 261
-#define exp_MOD 262
-#define exp_SHIFTLEFT 263
-#define exp_SHIFTRIGHT 264
-#define exp_OPENPARENT 265
-#define exp_CLOSEPARENT 266
-#define exp_OR 267
-#define exp_AND 268
-#define exp_XOR 269
-#define exp_NOT 270
-#define exp_NUMBER 271
 
 /* Value type.  */
 
index 2494aad..dba2cac 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
 /* C LALR(1) parser skeleton written by Richard Stallman, by
    simplifying the original so-called "semantic" parser.  */
 
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
+
 /* All symbols defined below should begin with yy or YY, to avoid
    infringing on user name space.  This should be done even for local
    variables, as they might otherwise be expanded by user macros.
    define necessary library symbols; they are noted "INFRINGES ON
    USER NAME SPACE" below.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
+/* Identify Bison output, and Bison version.  */
+#define YYBISON 30704
 
-/* Bison version.  */
-#define YYBISON_VERSION "3.4.2"
+/* Bison version string.  */
+#define YYBISON_VERSION "3.7.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -70,7 +71,6 @@
 #define yydebug         cmFortran_yydebug
 #define yynerrs         cmFortran_yynerrs
 
-
 /* First part of user prologue.  */
 #line 1 "cmFortranParser.y"
 
@@ -92,13 +92,11 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmFortran_yy
+  bison --name-prefix=cmFortran_yy
         --defines=cmFortranParserTokens.h
          -ocmFortranParser.cxx
           cmFortranParser.y
 
-Modify cmFortranParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
 */
 
 #include "cmConfigure.h" // IWYU pragma: keep
@@ -110,7 +108,6 @@ Modify cmFortranParser.cxx:
 /*-------------------------------------------------------------------------*/
 #define cmFortranParser_cxx
 #include "cmFortranParser.h" /* Interface to parser object.  */
-#include "cmFortranParserTokens.h" /* Need YYSTYPE for YY_DECL.  */
 
 /* Forward declare the lexer entry point.  */
 YY_DECL;
@@ -133,10 +130,20 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message)
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
 #endif
 
-#line 139 "cmFortranParser.cxx"
+#line 137 "cmFortranParser.cxx"
 
+# ifndef YY_CAST
+#  ifdef __cplusplus
+#   define YY_CAST(Type, Val) static_cast<Type> (Val)
+#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+#  else
+#   define YY_CAST(Type, Val) ((Type) (Val))
+#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+#  endif
+# endif
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -149,132 +156,69 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message)
 #  endif
 # endif
 
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Use api.header.include to #include this header
-   instead of duplicating it here.  */
-#ifndef YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
-# define YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
-/* Debug traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int cmFortran_yydebug;
-#endif
-
-/* Token type.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-  enum yytokentype
-  {
-    EOSTMT = 258,
-    ASSIGNMENT_OP = 259,
-    GARBAGE = 260,
-    CPP_LINE_DIRECTIVE = 261,
-    CPP_INCLUDE = 262,
-    F90PPR_INCLUDE = 263,
-    COCO_INCLUDE = 264,
-    F90PPR_DEFINE = 265,
-    CPP_DEFINE = 266,
-    F90PPR_UNDEF = 267,
-    CPP_UNDEF = 268,
-    CPP_IFDEF = 269,
-    CPP_IFNDEF = 270,
-    CPP_IF = 271,
-    CPP_ELSE = 272,
-    CPP_ELIF = 273,
-    CPP_ENDIF = 274,
-    F90PPR_IFDEF = 275,
-    F90PPR_IFNDEF = 276,
-    F90PPR_IF = 277,
-    F90PPR_ELSE = 278,
-    F90PPR_ELIF = 279,
-    F90PPR_ENDIF = 280,
-    COMMA = 281,
-    COLON = 282,
-    DCOLON = 283,
-    LPAREN = 284,
-    RPAREN = 285,
-    UNTERMINATED_STRING = 286,
-    STRING = 287,
-    WORD = 288,
-    CPP_INCLUDE_ANGLE = 289,
-    END = 290,
-    INCLUDE = 291,
-    INTERFACE = 292,
-    MODULE = 293,
-    SUBMODULE = 294,
-    USE = 295
-  };
-#endif
-/* Tokens.  */
-#define EOSTMT 258
-#define ASSIGNMENT_OP 259
-#define GARBAGE 260
-#define CPP_LINE_DIRECTIVE 261
-#define CPP_INCLUDE 262
-#define F90PPR_INCLUDE 263
-#define COCO_INCLUDE 264
-#define F90PPR_DEFINE 265
-#define CPP_DEFINE 266
-#define F90PPR_UNDEF 267
-#define CPP_UNDEF 268
-#define CPP_IFDEF 269
-#define CPP_IFNDEF 270
-#define CPP_IF 271
-#define CPP_ELSE 272
-#define CPP_ELIF 273
-#define CPP_ENDIF 274
-#define F90PPR_IFDEF 275
-#define F90PPR_IFNDEF 276
-#define F90PPR_IF 277
-#define F90PPR_ELSE 278
-#define F90PPR_ELIF 279
-#define F90PPR_ENDIF 280
-#define COMMA 281
-#define COLON 282
-#define DCOLON 283
-#define LPAREN 284
-#define RPAREN 285
-#define UNTERMINATED_STRING 286
-#define STRING 287
-#define WORD 288
-#define CPP_INCLUDE_ANGLE 289
-#define END 290
-#define INCLUDE 291
-#define INTERFACE 292
-#define MODULE 293
-#define SUBMODULE 294
-#define USE 295
-
-/* Value type.  */
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-union YYSTYPE
+#include "cmFortranParserTokens.h"
+/* Symbol kind.  */
+enum yysymbol_kind_t
 {
-#line 73 "cmFortranParser.y"
-
-  char* string;
-
-#line 266 "cmFortranParser.cxx"
-
+  YYSYMBOL_YYEMPTY = -2,
+  YYSYMBOL_YYEOF = 0,                      /* "end of file"  */
+  YYSYMBOL_YYerror = 1,                    /* error  */
+  YYSYMBOL_YYUNDEF = 2,                    /* "invalid token"  */
+  YYSYMBOL_EOSTMT = 3,                     /* EOSTMT  */
+  YYSYMBOL_ASSIGNMENT_OP = 4,              /* ASSIGNMENT_OP  */
+  YYSYMBOL_GARBAGE = 5,                    /* GARBAGE  */
+  YYSYMBOL_CPP_LINE_DIRECTIVE = 6,         /* CPP_LINE_DIRECTIVE  */
+  YYSYMBOL_CPP_INCLUDE = 7,                /* CPP_INCLUDE  */
+  YYSYMBOL_F90PPR_INCLUDE = 8,             /* F90PPR_INCLUDE  */
+  YYSYMBOL_COCO_INCLUDE = 9,               /* COCO_INCLUDE  */
+  YYSYMBOL_F90PPR_DEFINE = 10,             /* F90PPR_DEFINE  */
+  YYSYMBOL_CPP_DEFINE = 11,                /* CPP_DEFINE  */
+  YYSYMBOL_F90PPR_UNDEF = 12,              /* F90PPR_UNDEF  */
+  YYSYMBOL_CPP_UNDEF = 13,                 /* CPP_UNDEF  */
+  YYSYMBOL_CPP_IFDEF = 14,                 /* CPP_IFDEF  */
+  YYSYMBOL_CPP_IFNDEF = 15,                /* CPP_IFNDEF  */
+  YYSYMBOL_CPP_IF = 16,                    /* CPP_IF  */
+  YYSYMBOL_CPP_ELSE = 17,                  /* CPP_ELSE  */
+  YYSYMBOL_CPP_ELIF = 18,                  /* CPP_ELIF  */
+  YYSYMBOL_CPP_ENDIF = 19,                 /* CPP_ENDIF  */
+  YYSYMBOL_F90PPR_IFDEF = 20,              /* F90PPR_IFDEF  */
+  YYSYMBOL_F90PPR_IFNDEF = 21,             /* F90PPR_IFNDEF  */
+  YYSYMBOL_F90PPR_IF = 22,                 /* F90PPR_IF  */
+  YYSYMBOL_F90PPR_ELSE = 23,               /* F90PPR_ELSE  */
+  YYSYMBOL_F90PPR_ELIF = 24,               /* F90PPR_ELIF  */
+  YYSYMBOL_F90PPR_ENDIF = 25,              /* F90PPR_ENDIF  */
+  YYSYMBOL_COMMA = 26,                     /* COMMA  */
+  YYSYMBOL_COLON = 27,                     /* COLON  */
+  YYSYMBOL_DCOLON = 28,                    /* DCOLON  */
+  YYSYMBOL_LPAREN = 29,                    /* LPAREN  */
+  YYSYMBOL_RPAREN = 30,                    /* RPAREN  */
+  YYSYMBOL_UNTERMINATED_STRING = 31,       /* UNTERMINATED_STRING  */
+  YYSYMBOL_STRING = 32,                    /* STRING  */
+  YYSYMBOL_WORD = 33,                      /* WORD  */
+  YYSYMBOL_CPP_INCLUDE_ANGLE = 34,         /* CPP_INCLUDE_ANGLE  */
+  YYSYMBOL_END = 35,                       /* END  */
+  YYSYMBOL_INCLUDE = 36,                   /* INCLUDE  */
+  YYSYMBOL_INTERFACE = 37,                 /* INTERFACE  */
+  YYSYMBOL_MODULE = 38,                    /* MODULE  */
+  YYSYMBOL_SUBMODULE = 39,                 /* SUBMODULE  */
+  YYSYMBOL_USE = 40,                       /* USE  */
+  YYSYMBOL_YYACCEPT = 41,                  /* $accept  */
+  YYSYMBOL_code = 42,                      /* code  */
+  YYSYMBOL_stmt = 43,                      /* stmt  */
+  YYSYMBOL_include = 44,                   /* include  */
+  YYSYMBOL_define = 45,                    /* define  */
+  YYSYMBOL_undef = 46,                     /* undef  */
+  YYSYMBOL_ifdef = 47,                     /* ifdef  */
+  YYSYMBOL_ifndef = 48,                    /* ifndef  */
+  YYSYMBOL_if = 49,                        /* if  */
+  YYSYMBOL_elif = 50,                      /* elif  */
+  YYSYMBOL_else = 51,                      /* else  */
+  YYSYMBOL_endif = 52,                     /* endif  */
+  YYSYMBOL_other = 53,                     /* other  */
+  YYSYMBOL_misc_code = 54                  /* misc_code  */
 };
-typedef union YYSTYPE YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-
+typedef enum yysymbol_kind_t yysymbol_kind_t;
 
-int cmFortran_yyparse (yyscan_t yyscanner);
-
-#endif /* !YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED  */
 
 
 
@@ -282,28 +226,75 @@ int cmFortran_yyparse (yyscan_t yyscanner);
 # undef short
 #endif
 
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+   <limits.h> and (if available) <stdint.h> are included
+   so that the code can choose integer types of a good width.  */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+#  include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+#  define YY_STDINT_H
+# endif
 #endif
 
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
+/* Narrow types that promote to a signed type and that can represent a
+   signed or unsigned integer of at least N bits.  In tables they can
+   save space and decrease cache pressure.  Promoting to a signed type
+   helps avoid bugs in integer arithmetic.  */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
 #else
 typedef signed char yytype_int8;
 #endif
 
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
 #else
-typedef unsigned short yytype_uint16;
+typedef short yytype_int16;
 #endif
 
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
 #else
-typedef short yytype_int16;
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+       && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+#  define YYPTRDIFF_T __PTRDIFF_TYPE__
+#  define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+#  ifndef ptrdiff_t
+#   include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  endif
+#  define YYPTRDIFF_T ptrdiff_t
+#  define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+#  define YYPTRDIFF_T long
+#  define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
 #endif
 
 #ifndef YYSIZE_T
@@ -311,7 +302,7 @@ typedef short yytype_int16;
 #  define YYSIZE_T __SIZE_TYPE__
 # elif defined size_t
 #  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
 #  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
 #  define YYSIZE_T size_t
 # else
@@ -319,7 +310,20 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+#define YYSIZE_MAXIMUM                                  \
+  YY_CAST (YYPTRDIFF_T,                                 \
+           (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1)  \
+            ? YYPTRDIFF_MAXIMUM                         \
+            : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int8 yy_state_t;
+
+/* State numbers in computations.  */
+typedef int yy_state_fast_t;
 
 #ifndef YY_
 # if defined YYENABLE_NLS && YYENABLE_NLS
@@ -333,22 +337,21 @@ typedef short yytype_int16;
 # endif
 #endif
 
-#ifndef YY_ATTRIBUTE
-# if (defined __GNUC__                                               \
-      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
-     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
-#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
-# else
-#  define YY_ATTRIBUTE(Spec) /* empty */
-# endif
-#endif
 
 #ifndef YY_ATTRIBUTE_PURE
-# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define YY_ATTRIBUTE_PURE
+# endif
 #endif
 
 #ifndef YY_ATTRIBUTE_UNUSED
-# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+#  define YY_ATTRIBUTE_UNUSED
+# endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
@@ -360,11 +363,11 @@ typedef short yytype_int16;
 
 #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
 /* Suppress an incorrect diagnostic about yylval being uninitialized.  */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
-    _Pragma ("GCC diagnostic push") \
-    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                            \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
     _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
     _Pragma ("GCC diagnostic pop")
 #else
 # define YY_INITIAL_VALUE(Value) Value
@@ -377,10 +380,22 @@ typedef short yytype_int16;
 # define YY_INITIAL_VALUE(Value) /* Nothing. */
 #endif
 
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN                          \
+    _Pragma ("GCC diagnostic push")                            \
+    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END            \
+    _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
 
 #define YY_ASSERT(E) ((void) (0 && (E)))
 
-#if ! defined yyoverflow || YYERROR_VERBOSE
+#if 1
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
@@ -445,8 +460,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 # endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
+#endif /* 1 */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus \
@@ -455,17 +469,17 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  yytype_int16 yyss_alloc;
+  yy_state_t yyss_alloc;
   YYSTYPE yyvs_alloc;
 };
 
 /* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
 
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+     ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \
       + YYSTACK_GAP_MAXIMUM)
 
 # define YYCOPY_NEEDED 1
@@ -478,11 +492,11 @@ union yyalloc
 # define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
     do                                                                  \
       {                                                                 \
-        YYSIZE_T yynewbytes;                                            \
+        YYPTRDIFF_T yynewbytes;                                         \
         YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
         Stack = &yyptr->Stack_alloc;                                    \
-        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-        yyptr += yynewbytes / sizeof (*yyptr);                          \
+        yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / YYSIZEOF (*yyptr);                        \
       }                                                                 \
     while (0)
 
@@ -494,12 +508,12 @@ union yyalloc
 # ifndef YYCOPY
 #  if defined __GNUC__ && 1 < __GNUC__
 #   define YYCOPY(Dst, Src, Count) \
-      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+      __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
 #  else
 #   define YYCOPY(Dst, Src, Count)              \
       do                                        \
         {                                       \
-          YYSIZE_T yyi;                         \
+          YYPTRDIFF_T yyi;                      \
           for (yyi = 0; yyi < (Count); yyi++)   \
             (Dst)[yyi] = (Src)[yyi];            \
         }                                       \
@@ -522,17 +536,20 @@ union yyalloc
 /* YYNSTATES -- Number of states.  */
 #define YYNSTATES  127
 
-#define YYUNDEFTOK  2
+/* YYMAXUTOK -- Last valid token kind.  */
 #define YYMAXUTOK   295
 
+
 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex, with out-of-bounds checking.  */
-#define YYTRANSLATE(YYX)                                                \
-  ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+#define YYTRANSLATE(YYX)                                \
+  (0 <= (YYX) && (YYX) <= YYMAXUTOK                     \
+   ? YY_CAST (yysymbol_kind_t, yytranslate[YYX])        \
+   : YYSYMBOL_YYUNDEF)
 
 /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
    as returned by yylex.  */
-static const yytype_uint8 yytranslate[] =
+static const yytype_int8 yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -570,38 +587,52 @@ static const yytype_uint8 yytranslate[] =
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,   101,   101,   101,   104,   108,   113,   122,   128,   135,
-     140,   144,   149,   157,   162,   167,   172,   177,   182,   187,
-     192,   197,   201,   205,   209,   213,   214,   219,   219,   219,
-     220,   220,   221,   221,   222,   222,   223,   223,   224,   224,
-     225,   225,   226,   226,   227,   227,   228,   228,   231,   232,
-     233,   234,   235,   236,   237,   238,   239,   240,   241,   242,
-     243,   244,   245,   246,   247
+       0,    99,    99,    99,   102,   106,   111,   120,   126,   133,
+     138,   142,   147,   155,   160,   165,   170,   175,   180,   185,
+     190,   195,   199,   203,   207,   211,   212,   217,   217,   217,
+     218,   218,   219,   219,   220,   220,   221,   221,   222,   222,
+     223,   223,   224,   224,   225,   225,   226,   226,   229,   230,
+     231,   232,   233,   234,   235,   236,   237,   238,   239,   240,
+     241,   242,   243,   244,   245
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || 1
+/** Accessing symbol of state STATE.  */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+   YYSYMBOL.  No bounds checking.  */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "EOSTMT", "ASSIGNMENT_OP", "GARBAGE",
-  "CPP_LINE_DIRECTIVE", "CPP_INCLUDE", "F90PPR_INCLUDE", "COCO_INCLUDE",
-  "F90PPR_DEFINE", "CPP_DEFINE", "F90PPR_UNDEF", "CPP_UNDEF", "CPP_IFDEF",
-  "CPP_IFNDEF", "CPP_IF", "CPP_ELSE", "CPP_ELIF", "CPP_ENDIF",
-  "F90PPR_IFDEF", "F90PPR_IFNDEF", "F90PPR_IF", "F90PPR_ELSE",
-  "F90PPR_ELIF", "F90PPR_ENDIF", "COMMA", "COLON", "DCOLON", "LPAREN",
-  "RPAREN", "UNTERMINATED_STRING", "STRING", "WORD", "CPP_INCLUDE_ANGLE",
-  "END", "INCLUDE", "INTERFACE", "MODULE", "SUBMODULE", "USE", "$accept",
-  "code", "stmt", "include", "define", "undef", "ifdef", "ifndef", "if",
-  "elif", "else", "endif", "other", "misc_code", YY_NULLPTR
+  "\"end of file\"", "error", "\"invalid token\"", "EOSTMT",
+  "ASSIGNMENT_OP", "GARBAGE", "CPP_LINE_DIRECTIVE", "CPP_INCLUDE",
+  "F90PPR_INCLUDE", "COCO_INCLUDE", "F90PPR_DEFINE", "CPP_DEFINE",
+  "F90PPR_UNDEF", "CPP_UNDEF", "CPP_IFDEF", "CPP_IFNDEF", "CPP_IF",
+  "CPP_ELSE", "CPP_ELIF", "CPP_ENDIF", "F90PPR_IFDEF", "F90PPR_IFNDEF",
+  "F90PPR_IF", "F90PPR_ELSE", "F90PPR_ELIF", "F90PPR_ENDIF", "COMMA",
+  "COLON", "DCOLON", "LPAREN", "RPAREN", "UNTERMINATED_STRING", "STRING",
+  "WORD", "CPP_INCLUDE_ANGLE", "END", "INCLUDE", "INTERFACE", "MODULE",
+  "SUBMODULE", "USE", "$accept", "code", "stmt", "include", "define",
+  "undef", "ifdef", "ifndef", "if", "elif", "else", "endif", "other",
+  "misc_code", YY_NULLPTR
 };
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+  return yytname[yysymbol];
+}
 #endif
 
-# ifdef YYPRINT
+#ifdef YYPRINT
 /* YYTOKNUM[NUM] -- (External) token number corresponding to the
    (internal) symbol number NUM (which must be that of a token).  */
-static const yytype_uint16 yytoknum[] =
+static const yytype_int16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
@@ -609,16 +640,16 @@ static const yytype_uint16 yytoknum[] =
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
      295
 };
-# endif
+#endif
 
-#define YYPACT_NINF -39
+#define YYPACT_NINF (-39)
 
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-39)))
+#define yypact_value_is_default(Yyn) \
+  ((Yyn) == YYPACT_NINF)
 
-#define YYTABLE_NINF -1
+#define YYTABLE_NINF (-1)
 
-#define yytable_value_is_error(Yytable_value) \
+#define yytable_value_is_error(Yyn) \
   0
 
   /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
@@ -643,7 +674,7 @@ static const yytype_int16 yypact[] =
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
      Performed when YYTABLE does not specify something else to do.  Zero
      means the default is an error.  */
-static const yytype_uint8 yydefact[] =
+static const yytype_int8 yydefact[] =
 {
        2,     0,     1,     0,    25,     0,    27,    28,    29,    31,
       30,    33,    32,    34,    36,    38,    42,    40,    44,    35,
@@ -677,7 +708,7 @@ static const yytype_int8 yydefgoto[] =
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
      positive, shift that token.  If negative, reduce the rule whose
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
-static const yytype_uint8 yytable[] =
+static const yytype_int8 yytable[] =
 {
       59,    60,    61,    62,    42,    63,   105,    83,    84,   106,
       85,    86,    43,    45,    46,    90,    91,    92,    93,    94,
@@ -807,7 +838,7 @@ static const yytype_int8 yycheck[] =
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
+static const yytype_int8 yystos[] =
 {
        0,    42,     0,     1,     3,     6,     7,     8,     9,    10,
       11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
@@ -825,7 +856,7 @@ static const yytype_uint8 yystos[] =
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
+static const yytype_int8 yyr1[] =
 {
        0,    41,    42,    42,    43,    43,    43,    43,    43,    43,
       43,    43,    43,    43,    43,    43,    43,    43,    43,    43,
@@ -837,7 +868,7 @@ static const yytype_uint8 yyr1[] =
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
+static const yytype_int8 yyr2[] =
 {
        0,     2,     0,     2,     2,     4,     4,     7,     9,     4,
        4,     5,     7,     4,     4,     3,     4,     4,     4,     4,
@@ -849,10 +880,10 @@ static const yytype_uint8 yyr2[] =
 };
 
 
+enum { YYENOMEM = -2 };
+
 #define yyerrok         (yyerrstatus = 0)
 #define yyclearin       (yychar = YYEMPTY)
-#define YYEMPTY         (-2)
-#define YYEOF           0
 
 #define YYACCEPT        goto yyacceptlab
 #define YYABORT         goto yyabortlab
@@ -878,10 +909,9 @@ static const yytype_uint8 yyr2[] =
       }                                                           \
   while (0)
 
-/* Error token number */
-#define YYTERROR        1
-#define YYERRCODE       256
-
+/* Backward compatibility with an undocumented macro.
+   Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
 
 
 /* Enable debugging if requested.  */
@@ -899,18 +929,18 @@ do {                                            \
 } while (0)
 
 /* This macro is provided for backward compatibility. */
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
+# ifndef YY_LOCATION_PRINT
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
 
 
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)                    \
 do {                                                                      \
   if (yydebug)                                                            \
     {                                                                     \
       YYFPRINTF (stderr, "%s ", Title);                                   \
       yy_symbol_print (stderr,                                            \
-                  Type, Value, yyscanner); \
+                  Kind, Value, yyscanner); \
       YYFPRINTF (stderr, "\n");                                           \
     }                                                                     \
 } while (0)
@@ -921,7 +951,8 @@ do {                                                                      \
 `-----------------------------------*/
 
 static void
-yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_value_print (FILE *yyo,
+                       yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   FILE *yyoutput = yyo;
   YYUSE (yyoutput);
@@ -929,11 +960,11 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
   if (!yyvaluep)
     return;
 # ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
+  if (yykind < YYNTOKENS)
+    YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
 # endif
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
@@ -943,12 +974,13 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy
 `---------------------------*/
 
 static void
-yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
+yy_symbol_print (FILE *yyo,
+                 yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, yyscan_t yyscanner)
 {
   YYFPRINTF (yyo, "%s %s (",
-             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+             yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
 
-  yy_symbol_value_print (yyo, yytype, yyvaluep, yyscanner);
+  yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner);
   YYFPRINTF (yyo, ")");
 }
 
@@ -958,7 +990,7 @@ yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yyscan_t
 `------------------------------------------------------------------*/
 
 static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
 {
   YYFPRINTF (stderr, "Stack now");
   for (; yybottom <= yytop; yybottom++)
@@ -981,21 +1013,21 @@ do {                                                            \
 `------------------------------------------------*/
 
 static void
-yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, yyscan_t yyscanner)
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp,
+                 int yyrule, yyscan_t yyscanner)
 {
-  unsigned long yylno = yyrline[yyrule];
+  int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
   int yyi;
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
              yyrule - 1, yylno);
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr,
-                       yystos[yyssp[yyi + 1 - yynrhs]],
-                       &yyvsp[(yyi + 1) - (yynrhs)]
-                                              , yyscanner);
+                       YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+                       &yyvsp[(yyi + 1) - (yynrhs)], yyscanner);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -1010,8 +1042,8 @@ do {                                    \
    multiple parsers can coexist.  */
 int yydebug;
 #else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
 # define YY_STACK_PRINT(Bottom, Top)
 # define YY_REDUCE_PRINT(Rule)
 #endif /* !YYDEBUG */
@@ -1034,28 +1066,76 @@ int yydebug;
 #endif
 
 
-#if YYERROR_VERBOSE
+/* Context of a parse error.  */
+typedef struct
+{
+  yy_state_t *yyssp;
+  yysymbol_kind_t yytoken;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+   current YYCTX, and return the number of tokens stored in YYARG.  If
+   YYARG is null, return the number of expected tokens (guaranteed to
+   be less than YYNTOKENS).  Return YYENOMEM on memory exhaustion.
+   Return 0 if there are more than YYARGN expected tokens, yet fill
+   YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+                            yysymbol_kind_t yyarg[], int yyargn)
+{
+  /* Actual size of YYARG. */
+  int yycount = 0;
+  int yyn = yypact[+*yyctx->yyssp];
+  if (!yypact_value_is_default (yyn))
+    {
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+         YYCHECK.  In other words, skip the first -YYN actions for
+         this state because they are default actions.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yyx;
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+        if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+            && !yytable_value_is_error (yytable[yyx + yyn]))
+          {
+            if (!yyarg)
+              ++yycount;
+            else if (yycount == yyargn)
+              return 0;
+            else
+              yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+          }
+    }
+  if (yyarg && yycount == 0 && 0 < yyargn)
+    yyarg[0] = YYSYMBOL_YYEMPTY;
+  return yycount;
+}
 
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+#  define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
 /* Return the length of YYSTR.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yystrlen (const char *yystr)
 {
-  YYSIZE_T yylen;
+  YYPTRDIFF_T yylen;
   for (yylen = 0; yystr[yylen]; yylen++)
     continue;
   return yylen;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#  define yystpcpy stpcpy
+# else
 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    YYDEST.  */
 static char *
@@ -1069,10 +1149,10 @@ yystpcpy (char *yydest, const char *yysrc)
 
   return yyd - 1;
 }
-#  endif
 # endif
+#endif
 
-# ifndef yytnamerr
+#ifndef yytnamerr
 /* Copy to YYRES the contents of YYSTR after stripping away unnecessary
    quotes and backslashes, so that it's suitable for yyerror.  The
    heuristic is that double-quoting is unnecessary unless the string
@@ -1080,14 +1160,13 @@ yystpcpy (char *yydest, const char *yysrc)
    backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
    null, do not copy; instead, return the length of what the result
    would have been.  */
-static YYSIZE_T
+static YYPTRDIFF_T
 yytnamerr (char *yyres, const char *yystr)
 {
   if (*yystr == '"')
     {
-      YYSIZE_T yyn = 0;
+      YYPTRDIFF_T yyn = 0;
       char const *yyp = yystr;
-
       for (;;)
         switch (*++yyp)
           {
@@ -1116,36 +1195,20 @@ yytnamerr (char *yyres, const char *yystr)
     do_not_strip_quotes: ;
     }
 
-  if (! yyres)
+  if (yyres)
+    return yystpcpy (yyres, yystr) - yyres;
+  else
     return yystrlen (yystr);
-
-  return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres);
 }
-# endif
+#endif
 
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN for the state stack whose top is
-   YYSSP.
 
-   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
-   not large enough to hold the message.  In that case, also set
-   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
-   required number of bytes is too large to store.  */
 static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                yytype_int16 *yyssp, int yytoken)
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+                           yysymbol_kind_t yyarg[], int yyargn)
 {
-  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
-  YYSIZE_T yysize = yysize0;
-  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-  /* Internationalized format string. */
-  const char *yyformat = YY_NULLPTR;
-  /* Arguments of yyformat. */
-  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-  /* Number of reported tokens (one for the "unexpected", one per
-     "expected"). */
+  /* Actual size of YYARG. */
   int yycount = 0;
-
   /* There are many possibilities here to consider:
      - If this state is a consistent state with a default action, then
        the only way this function was invoked is if the default action
@@ -1169,49 +1232,54 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
        one exception: it will still contain any token that will not be
        accepted due to an error action in a later state.
   */
-  if (yytoken != YYEMPTY)
+  if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
     {
-      int yyn = yypact[*yyssp];
-      yyarg[yycount++] = yytname[yytoken];
-      if (!yypact_value_is_default (yyn))
-        {
-          /* Start YYX at -YYN if negative to avoid negative indexes in
-             YYCHECK.  In other words, skip the first -YYN actions for
-             this state because they are default actions.  */
-          int yyxbegin = yyn < 0 ? -yyn : 0;
-          /* Stay within bounds of both yycheck and yytname.  */
-          int yychecklim = YYLAST - yyn + 1;
-          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-          int yyx;
-
-          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
-                && !yytable_value_is_error (yytable[yyx + yyn]))
-              {
-                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-                  {
-                    yycount = 1;
-                    yysize = yysize0;
-                    break;
-                  }
-                yyarg[yycount++] = yytname[yyx];
-                {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
-                  if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-                    yysize = yysize1;
-                  else
-                    return 2;
-                }
-              }
-        }
+      int yyn;
+      if (yyarg)
+        yyarg[yycount] = yyctx->yytoken;
+      ++yycount;
+      yyn = yypcontext_expected_tokens (yyctx,
+                                        yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+      if (yyn == YYENOMEM)
+        return YYENOMEM;
+      else
+        yycount += yyn;
     }
+  return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return -1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return YYENOMEM if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+                const yypcontext_t *yyctx)
+{
+  enum { YYARGS_MAX = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat: reported tokens (one for the "unexpected",
+     one per "expected"). */
+  yysymbol_kind_t yyarg[YYARGS_MAX];
+  /* Cumulated lengths of YYARG.  */
+  YYPTRDIFF_T yysize = 0;
+
+  /* Actual size of YYARG. */
+  int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+  if (yycount == YYENOMEM)
+    return YYENOMEM;
 
   switch (yycount)
     {
-# define YYCASE_(N, S)                      \
+#define YYCASE_(N, S)                       \
       case N:                               \
         yyformat = S;                       \
-      break
+        break
     default: /* Avoid compiler warnings. */
       YYCASE_(0, YY_("syntax error"));
       YYCASE_(1, YY_("syntax error, unexpected %s"));
@@ -1219,15 +1287,23 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
+#undef YYCASE_
     }
 
+  /* Compute error message size.  Don't count the "%s"s, but reserve
+     room for the terminator.  */
+  yysize = yystrlen (yyformat) - 2 * yycount + 1;
   {
-    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
-    if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
-      yysize = yysize1;
-    else
-      return 2;
+    int yyi;
+    for (yyi = 0; yyi < yycount; ++yyi)
+      {
+        YYPTRDIFF_T yysize1
+          = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+        if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+          yysize = yysize1;
+        else
+          return YYENOMEM;
+      }
   }
 
   if (*yymsg_alloc < yysize)
@@ -1236,7 +1312,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       if (! (yysize <= *yymsg_alloc
              && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
         *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
-      return 1;
+      return -1;
     }
 
   /* Avoid sprintf, as that infringes on the user's name space.
@@ -1248,40 +1324,43 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
     while ((*yyp = *yyformat) != '\0')
       if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
         {
-          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
           yyformat += 2;
         }
       else
         {
-          yyp++;
-          yyformat++;
+          ++yyp;
+          ++yyformat;
         }
   }
   return 0;
 }
-#endif /* YYERROR_VERBOSE */
+
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
 `-----------------------------------------------*/
 
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner)
+yydestruct (const char *yymsg,
+            yysymbol_kind_t yykind, YYSTYPE *yyvaluep, yyscan_t yyscanner)
 {
   YYUSE (yyvaluep);
   YYUSE (yyscanner);
   if (!yymsg)
     yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+  YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
 
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  YYUSE (yytype);
+  YYUSE (yykind);
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
 
 
+
+
 /*----------.
 | yyparse.  |
 `----------*/
@@ -1289,7 +1368,7 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t yyscanner
 int
 yyparse (yyscan_t yyscanner)
 {
-/* The lookahead symbol.  */
+/* Lookahead token kind.  */
 int yychar;
 
 
@@ -1300,45 +1379,41 @@ YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
 YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
 
     /* Number of syntax errors so far.  */
-    int yynerrs;
+    int yynerrs = 0;
 
-    int yystate;
+    yy_state_fast_t yystate = 0;
     /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus;
-
-    /* The stacks and their tools:
-       'yyss': related to states.
-       'yyvs': related to semantic values.
+    int yyerrstatus = 0;
 
-       Refer to the stacks through separate pointers, to allow yyoverflow
+    /* Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
 
-    /* The state stack.  */
-    yytype_int16 yyssa[YYINITDEPTH];
-    yytype_int16 *yyss;
-    yytype_int16 *yyssp;
+    /* Their size.  */
+    YYPTRDIFF_T yystacksize = YYINITDEPTH;
 
-    /* The semantic value stack.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs;
-    YYSTYPE *yyvsp;
+    /* The state stack: array, bottom, top.  */
+    yy_state_t yyssa[YYINITDEPTH];
+    yy_state_t *yyss = yyssa;
+    yy_state_t *yyssp = yyss;
 
-    YYSIZE_T yystacksize;
+    /* The semantic value stack: array, bottom, top.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs = yyvsa;
+    YYSTYPE *yyvsp = yyvs;
 
   int yyn;
+  /* The return value of yyparse.  */
   int yyresult;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken = 0;
+  /* Lookahead symbol kind.  */
+  yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
 
-#if YYERROR_VERBOSE
   /* Buffer for error messages, and its allocated size.  */
   char yymsgbuf[128];
   char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
+  YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
 
 #define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
 
@@ -1346,15 +1421,8 @@ YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
 
-  yyssp = yyss = yyssa;
-  yyvsp = yyvs = yyvsa;
-  yystacksize = YYINITDEPTH;
-
   YYDPRINTF ((stderr, "Starting parse\n"));
 
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
   yychar = YYEMPTY; /* Cause a token to be read.  */
   goto yysetstate;
 
@@ -1369,12 +1437,15 @@ yynewstate:
 
 
 /*--------------------------------------------------------------------.
-| yynewstate -- set current state (the top of the stack) to yystate.  |
+| yysetstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
   YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
-  *yyssp = (yytype_int16) yystate;
+  YY_IGNORE_USELESS_CAST_BEGIN
+  *yyssp = YY_CAST (yy_state_t, yystate);
+  YY_IGNORE_USELESS_CAST_END
+  YY_STACK_PRINT (yyss, yyssp);
 
   if (yyss + yystacksize - 1 <= yyssp)
 #if !defined yyoverflow && !defined YYSTACK_RELOCATE
@@ -1382,23 +1453,23 @@ yysetstate:
 #else
     {
       /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1);
+      YYPTRDIFF_T yysize = yyssp - yyss + 1;
 
 # if defined yyoverflow
       {
         /* Give user a chance to reallocate the stack.  Use copies of
            these so that the &'s don't force the real ones into
            memory.  */
+        yy_state_t *yyss1 = yyss;
         YYSTYPE *yyvs1 = yyvs;
-        yytype_int16 *yyss1 = yyss;
 
         /* Each stack pointer address is followed by the size of the
            data in use in that stack, in bytes.  This used to be a
            conditional around just the two extra args, but that might
            be undefined if yyoverflow is a macro.  */
         yyoverflow (YY_("memory exhausted"),
-                    &yyss1, yysize * sizeof (*yyssp),
-                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yyss1, yysize * YYSIZEOF (*yyssp),
+                    &yyvs1, yysize * YYSIZEOF (*yyvsp),
                     &yystacksize);
         yyss = yyss1;
         yyvs = yyvs1;
@@ -1412,14 +1483,15 @@ yysetstate:
         yystacksize = YYMAXDEPTH;
 
       {
-        yytype_int16 *yyss1 = yyss;
+        yy_state_t *yyss1 = yyss;
         union yyalloc *yyptr =
-          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+          YY_CAST (union yyalloc *,
+                   YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
         if (! yyptr)
           goto yyexhaustedlab;
         YYSTACK_RELOCATE (yyss_alloc, yyss);
         YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-# undef YYSTACK_RELOCATE
+#  undef YYSTACK_RELOCATE
         if (yyss1 != yyssa)
           YYSTACK_FREE (yyss1);
       }
@@ -1428,8 +1500,10 @@ yysetstate:
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
 
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                  (unsigned long) yystacksize));
+      YY_IGNORE_USELESS_CAST_BEGIN
+      YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+                  YY_CAST (long, yystacksize)));
+      YY_IGNORE_USELESS_CAST_END
 
       if (yyss + yystacksize - 1 <= yyssp)
         YYABORT;
@@ -1456,18 +1530,29 @@ yybackup:
 
   /* Not known => get a lookahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  /* YYCHAR is either empty, or end-of-input, or a valid lookahead.  */
   if (yychar == YYEMPTY)
     {
-      YYDPRINTF ((stderr, "Reading a token"));
+      YYDPRINTF ((stderr, "Reading a token\n"));
       yychar = yylex (&yylval, yyscanner);
     }
 
   if (yychar <= YYEOF)
     {
-      yychar = yytoken = YYEOF;
+      yychar = YYEOF;
+      yytoken = YYSYMBOL_YYEOF;
       YYDPRINTF ((stderr, "Now at end of input.\n"));
     }
+  else if (yychar == YYerror)
+    {
+      /* The scanner already issued an error message, process directly
+         to error recovery.  But do not keep the error token as
+         lookahead, it is too special and may lead us to an endless
+         loop in error recovery. */
+      yychar = YYUNDEF;
+      yytoken = YYSYMBOL_YYerror;
+      goto yyerrlab1;
+    }
   else
     {
       yytoken = YYTRANSLATE (yychar);
@@ -1495,14 +1580,13 @@ yybackup:
 
   /* Shift the lookahead token.  */
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-
   yystate = yyn;
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
   goto yynewstate;
 
 
@@ -1537,28 +1621,28 @@ yyreduce:
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-  case 4:
-#line 104 "cmFortranParser.y"
-    {
+  case 4: /* stmt: INTERFACE EOSTMT  */
+#line 102 "cmFortranParser.y"
+                   {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_SetInInterface(parser, true);
   }
-#line 1547 "cmFortranParser.cxx"
+#line 1631 "cmFortranParser.cxx"
     break;
 
-  case 5:
-#line 108 "cmFortranParser.y"
-    {
+  case 5: /* stmt: USE WORD other EOSTMT  */
+#line 106 "cmFortranParser.y"
+                        {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1557 "cmFortranParser.cxx"
+#line 1641 "cmFortranParser.cxx"
     break;
 
-  case 6:
-#line 113 "cmFortranParser.y"
-    {
+  case 6: /* stmt: MODULE WORD other EOSTMT  */
+#line 111 "cmFortranParser.y"
+                           {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 &&
         cmsysString_strcasecmp((yyvsp[-2].string), "procedure") != 0 &&
@@ -1567,64 +1651,64 @@ yyreduce:
     }
     free((yyvsp[-2].string));
   }
-#line 1571 "cmFortranParser.cxx"
+#line 1655 "cmFortranParser.cxx"
     break;
 
-  case 7:
-#line 122 "cmFortranParser.y"
-    {
+  case 7: /* stmt: SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT  */
+#line 120 "cmFortranParser.y"
+                                                 {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string));
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1582 "cmFortranParser.cxx"
+#line 1666 "cmFortranParser.cxx"
     break;
 
-  case 8:
-#line 128 "cmFortranParser.y"
-    {
+  case 8: /* stmt: SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT  */
+#line 126 "cmFortranParser.y"
+                                                            {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string));
     free((yyvsp[-6].string));
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1594 "cmFortranParser.cxx"
+#line 1678 "cmFortranParser.cxx"
     break;
 
-  case 9:
-#line 135 "cmFortranParser.y"
-    {
+  case 9: /* stmt: INTERFACE WORD other EOSTMT  */
+#line 133 "cmFortranParser.y"
+                              {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_SetInInterface(parser, true);
     free((yyvsp[-2].string));
   }
-#line 1604 "cmFortranParser.cxx"
+#line 1688 "cmFortranParser.cxx"
     break;
 
-  case 10:
-#line 140 "cmFortranParser.y"
-    {
+  case 10: /* stmt: END INTERFACE other EOSTMT  */
+#line 138 "cmFortranParser.y"
+                             {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_SetInInterface(parser, false);
   }
-#line 1613 "cmFortranParser.cxx"
+#line 1697 "cmFortranParser.cxx"
     break;
 
-  case 11:
-#line 144 "cmFortranParser.y"
-    {
+  case 11: /* stmt: USE DCOLON WORD other EOSTMT  */
+#line 142 "cmFortranParser.y"
+                               {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1623 "cmFortranParser.cxx"
+#line 1707 "cmFortranParser.cxx"
     break;
 
-  case 12:
-#line 149 "cmFortranParser.y"
-    {
+  case 12: /* stmt: USE COMMA WORD DCOLON WORD other EOSTMT  */
+#line 147 "cmFortranParser.y"
+                                          {
     if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) {
       cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
       cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
@@ -1632,139 +1716,139 @@ yyreduce:
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1636 "cmFortranParser.cxx"
+#line 1720 "cmFortranParser.cxx"
     break;
 
-  case 13:
-#line 157 "cmFortranParser.y"
-    {
+  case 13: /* stmt: INCLUDE STRING other EOSTMT  */
+#line 155 "cmFortranParser.y"
+                              {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1646 "cmFortranParser.cxx"
+#line 1730 "cmFortranParser.cxx"
     break;
 
-  case 14:
-#line 162 "cmFortranParser.y"
-    {
+  case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT  */
+#line 160 "cmFortranParser.y"
+                                         {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1656 "cmFortranParser.cxx"
+#line 1740 "cmFortranParser.cxx"
     break;
 
-  case 15:
-#line 167 "cmFortranParser.y"
-    {
+  case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT  */
+#line 165 "cmFortranParser.y"
+                                 {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1666 "cmFortranParser.cxx"
+#line 1750 "cmFortranParser.cxx"
     break;
 
-  case 16:
-#line 172 "cmFortranParser.y"
-    {
+  case 16: /* stmt: include STRING other EOSTMT  */
+#line 170 "cmFortranParser.y"
+                              {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1676 "cmFortranParser.cxx"
+#line 1760 "cmFortranParser.cxx"
     break;
 
-  case 17:
-#line 177 "cmFortranParser.y"
-    {
+  case 17: /* stmt: define WORD other EOSTMT  */
+#line 175 "cmFortranParser.y"
+                           {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1686 "cmFortranParser.cxx"
+#line 1770 "cmFortranParser.cxx"
     break;
 
-  case 18:
-#line 182 "cmFortranParser.y"
-    {
+  case 18: /* stmt: undef WORD other EOSTMT  */
+#line 180 "cmFortranParser.y"
+                          {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1696 "cmFortranParser.cxx"
+#line 1780 "cmFortranParser.cxx"
     break;
 
-  case 19:
-#line 187 "cmFortranParser.y"
-    {
+  case 19: /* stmt: ifdef WORD other EOSTMT  */
+#line 185 "cmFortranParser.y"
+                          {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1706 "cmFortranParser.cxx"
+#line 1790 "cmFortranParser.cxx"
     break;
 
-  case 20:
-#line 192 "cmFortranParser.y"
-    {
+  case 20: /* stmt: ifndef WORD other EOSTMT  */
+#line 190 "cmFortranParser.y"
+                           {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1716 "cmFortranParser.cxx"
+#line 1800 "cmFortranParser.cxx"
     break;
 
-  case 21:
-#line 197 "cmFortranParser.y"
-    {
+  case 21: /* stmt: if other EOSTMT  */
+#line 195 "cmFortranParser.y"
+                  {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIf(parser);
   }
-#line 1725 "cmFortranParser.cxx"
+#line 1809 "cmFortranParser.cxx"
     break;
 
-  case 22:
-#line 201 "cmFortranParser.y"
-    {
+  case 22: /* stmt: elif other EOSTMT  */
+#line 199 "cmFortranParser.y"
+                    {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElif(parser);
   }
-#line 1734 "cmFortranParser.cxx"
+#line 1818 "cmFortranParser.cxx"
     break;
 
-  case 23:
-#line 205 "cmFortranParser.y"
-    {
+  case 23: /* stmt: else other EOSTMT  */
+#line 203 "cmFortranParser.y"
+                    {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElse(parser);
   }
-#line 1743 "cmFortranParser.cxx"
+#line 1827 "cmFortranParser.cxx"
     break;
 
-  case 24:
-#line 209 "cmFortranParser.y"
-    {
+  case 24: /* stmt: endif other EOSTMT  */
+#line 207 "cmFortranParser.y"
+                     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleEndif(parser);
   }
-#line 1752 "cmFortranParser.cxx"
+#line 1836 "cmFortranParser.cxx"
     break;
 
-  case 48:
-#line 231 "cmFortranParser.y"
-    { free ((yyvsp[0].string)); }
-#line 1758 "cmFortranParser.cxx"
+  case 48: /* misc_code: WORD  */
+#line 229 "cmFortranParser.y"
+                      { free ((yyvsp[0].string)); }
+#line 1842 "cmFortranParser.cxx"
     break;
 
-  case 55:
-#line 238 "cmFortranParser.y"
-    { free ((yyvsp[0].string)); }
-#line 1764 "cmFortranParser.cxx"
+  case 55: /* misc_code: STRING  */
+#line 236 "cmFortranParser.y"
+                      { free ((yyvsp[0].string)); }
+#line 1848 "cmFortranParser.cxx"
     break;
 
 
-#line 1768 "cmFortranParser.cxx"
+#line 1852 "cmFortranParser.cxx"
 
       default: break;
     }
@@ -1779,11 +1863,10 @@ yyreduce:
      case of YYERROR or YYBACKUP, subsequent parser actions might lead
      to an incorrect destructor call or verbose syntax error message
      before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+  YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
   yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
 
   *++yyvsp = yyval;
 
@@ -1807,50 +1890,44 @@ yyreduce:
 yyerrlab:
   /* Make sure we have latest lookahead translation.  See comments at
      user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
+  yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
       ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (yyscanner, YY_("syntax error"));
-#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
-                                        yyssp, yytoken)
       {
+        yypcontext_t yyctx
+          = {yyssp, yytoken};
         char const *yymsgp = YY_("syntax error");
         int yysyntax_error_status;
-        yysyntax_error_status = YYSYNTAX_ERROR;
+        yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
-        else if (yysyntax_error_status == 1)
+        else if (yysyntax_error_status == -1)
           {
             if (yymsg != yymsgbuf)
               YYSTACK_FREE (yymsg);
-            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
-            if (!yymsg)
+            yymsg = YY_CAST (char *,
+                             YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+            if (yymsg)
               {
-                yymsg = yymsgbuf;
-                yymsg_alloc = sizeof yymsgbuf;
-                yysyntax_error_status = 2;
+                yysyntax_error_status
+                  = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+                yymsgp = yymsg;
               }
             else
               {
-                yysyntax_error_status = YYSYNTAX_ERROR;
-                yymsgp = yymsg;
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = YYENOMEM;
               }
           }
         yyerror (yyscanner, yymsgp);
-        if (yysyntax_error_status == 2)
+        if (yysyntax_error_status == YYENOMEM)
           goto yyexhaustedlab;
       }
-# undef YYSYNTAX_ERROR
-#endif
     }
 
-
-
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
@@ -1870,7 +1947,6 @@ yyerrlab:
         }
     }
 
-#if 0
   /* Else will try to reuse lookahead token after shifting the error
      token.  */
   goto yyerrlab1;
@@ -1898,16 +1974,16 @@ yyerrorlab:
 | yyerrlab1 -- common code for both syntax error and YYERROR.  |
 `-------------------------------------------------------------*/
 yyerrlab1:
-#endif
   yyerrstatus = 3;      /* Each real token shifted decrements this.  */
 
+  /* Pop stack until we find a state that shifts the error token.  */
   for (;;)
     {
       yyn = yypact[yystate];
       if (!yypact_value_is_default (yyn))
         {
-          yyn += YYTERROR;
-          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+          yyn += YYSYMBOL_YYerror;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
             {
               yyn = yytable[yyn];
               if (0 < yyn)
@@ -1921,7 +1997,7 @@ yyerrlab1:
 
 
       yydestruct ("Error: popping",
-                  yystos[yystate], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -1933,7 +2009,7 @@ yyerrlab1:
 
 
   /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+  YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
 
   yystate = yyn;
   goto yynewstate;
@@ -1955,20 +2031,20 @@ yyabortlab:
   goto yyreturn;
 
 
-#if !defined yyoverflow || YYERROR_VERBOSE
+#if 1
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
   yyerror (yyscanner, YY_("memory exhausted"));
   yyresult = 2;
-  /* Fall through.  */
+  goto yyreturn;
 #endif
 
 
-/*-----------------------------------------------------.
-| yyreturn -- parsing is finished, return the result.  |
-`-----------------------------------------------------*/
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return.  |
+`-------------------------------------------------------*/
 yyreturn:
   if (yychar != YYEMPTY)
     {
@@ -1985,19 +2061,18 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                  yystos[*yyssp], yyvsp, yyscanner);
+                  YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
   if (yyss != yyssa)
     YYSTACK_FREE (yyss);
 #endif
-#if YYERROR_VERBOSE
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
-#endif
   return yyresult;
 }
-#line 250 "cmFortranParser.y"
+
+#line 248 "cmFortranParser.y"
 
 /* End of grammar */
index 1b54dd9..e461160 100644 (file)
@@ -17,13 +17,11 @@ This file must be translated to C and modified to build everywhere.
 
 Run bison like this:
 
-  bison --yacc --name-prefix=cmFortran_yy
+  bison --name-prefix=cmFortran_yy
         --defines=cmFortranParserTokens.h
          -ocmFortranParser.cxx
           cmFortranParser.y
 
-Modify cmFortranParser.cxx:
-  - "#if 0" out yyerrorlab block in range ["goto yyerrlab1", "yyerrlab1:"]
 */
 
 #include "cmConfigure.h" // IWYU pragma: keep
@@ -35,7 +33,6 @@ Modify cmFortranParser.cxx:
 /*-------------------------------------------------------------------------*/
 #define cmFortranParser_cxx
 #include "cmFortranParser.h" /* Interface to parser object.  */
-#include "cmFortranParserTokens.h" /* Need YYSTYPE for YY_DECL.  */
 
 /* Forward declare the lexer entry point.  */
 YY_DECL;
@@ -58,6 +55,7 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message)
 #endif
 #if defined(__GNUC__) && __GNUC__ >= 8
 # pragma GCC diagnostic ignored "-Wconversion"
+# pragma GCC diagnostic ignored "-Wfree-nonheap-object"
 #endif
 %}
 
index f66a15c..e250110 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.4.2.  */
+/* A Bison parser, made by GNU Bison 3.7.4.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -31,8 +31,9 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
-/* Undocumented macros, especially those whose name start with YY_,
-   are private implementation details.  Do not rely on them.  */
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+   especially those whose name start with YY_ or yy_.  They are
+   private implementation details that can be changed or removed.  */
 
 #ifndef YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
 # define YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
 extern int cmFortran_yydebug;
 #endif
 
-/* Token type.  */
+/* Token kinds.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
   enum yytokentype
   {
-    EOSTMT = 258,
-    ASSIGNMENT_OP = 259,
-    GARBAGE = 260,
-    CPP_LINE_DIRECTIVE = 261,
-    CPP_INCLUDE = 262,
-    F90PPR_INCLUDE = 263,
-    COCO_INCLUDE = 264,
-    F90PPR_DEFINE = 265,
-    CPP_DEFINE = 266,
-    F90PPR_UNDEF = 267,
-    CPP_UNDEF = 268,
-    CPP_IFDEF = 269,
-    CPP_IFNDEF = 270,
-    CPP_IF = 271,
-    CPP_ELSE = 272,
-    CPP_ELIF = 273,
-    CPP_ENDIF = 274,
-    F90PPR_IFDEF = 275,
-    F90PPR_IFNDEF = 276,
-    F90PPR_IF = 277,
-    F90PPR_ELSE = 278,
-    F90PPR_ELIF = 279,
-    F90PPR_ENDIF = 280,
-    COMMA = 281,
-    COLON = 282,
-    DCOLON = 283,
-    LPAREN = 284,
-    RPAREN = 285,
-    UNTERMINATED_STRING = 286,
-    STRING = 287,
-    WORD = 288,
-    CPP_INCLUDE_ANGLE = 289,
-    END = 290,
-    INCLUDE = 291,
-    INTERFACE = 292,
-    MODULE = 293,
-    SUBMODULE = 294,
-    USE = 295
+    YYEMPTY = -2,
+    YYEOF = 0,                     /* "end of file"  */
+    YYerror = 256,                 /* error  */
+    YYUNDEF = 257,                 /* "invalid token"  */
+    EOSTMT = 258,                  /* EOSTMT  */
+    ASSIGNMENT_OP = 259,           /* ASSIGNMENT_OP  */
+    GARBAGE = 260,                 /* GARBAGE  */
+    CPP_LINE_DIRECTIVE = 261,      /* CPP_LINE_DIRECTIVE  */
+    CPP_INCLUDE = 262,             /* CPP_INCLUDE  */
+    F90PPR_INCLUDE = 263,          /* F90PPR_INCLUDE  */
+    COCO_INCLUDE = 264,            /* COCO_INCLUDE  */
+    F90PPR_DEFINE = 265,           /* F90PPR_DEFINE  */
+    CPP_DEFINE = 266,              /* CPP_DEFINE  */
+    F90PPR_UNDEF = 267,            /* F90PPR_UNDEF  */
+    CPP_UNDEF = 268,               /* CPP_UNDEF  */
+    CPP_IFDEF = 269,               /* CPP_IFDEF  */
+    CPP_IFNDEF = 270,              /* CPP_IFNDEF  */
+    CPP_IF = 271,                  /* CPP_IF  */
+    CPP_ELSE = 272,                /* CPP_ELSE  */
+    CPP_ELIF = 273,                /* CPP_ELIF  */
+    CPP_ENDIF = 274,               /* CPP_ENDIF  */
+    F90PPR_IFDEF = 275,            /* F90PPR_IFDEF  */
+    F90PPR_IFNDEF = 276,           /* F90PPR_IFNDEF  */
+    F90PPR_IF = 277,               /* F90PPR_IF  */
+    F90PPR_ELSE = 278,             /* F90PPR_ELSE  */
+    F90PPR_ELIF = 279,             /* F90PPR_ELIF  */
+    F90PPR_ENDIF = 280,            /* F90PPR_ENDIF  */
+    COMMA = 281,                   /* COMMA  */
+    COLON = 282,                   /* COLON  */
+    DCOLON = 283,                  /* DCOLON  */
+    LPAREN = 284,                  /* LPAREN  */
+    RPAREN = 285,                  /* RPAREN  */
+    UNTERMINATED_STRING = 286,     /* UNTERMINATED_STRING  */
+    STRING = 287,                  /* STRING  */
+    WORD = 288,                    /* WORD  */
+    CPP_INCLUDE_ANGLE = 289,       /* CPP_INCLUDE_ANGLE  */
+    END = 290,                     /* END  */
+    INCLUDE = 291,                 /* INCLUDE  */
+    INTERFACE = 292,               /* INTERFACE  */
+    MODULE = 293,                  /* MODULE  */
+    SUBMODULE = 294,               /* SUBMODULE  */
+    USE = 295                      /* USE  */
   };
+  typedef enum yytokentype yytoken_kind_t;
 #endif
-/* Tokens.  */
-#define EOSTMT 258
-#define ASSIGNMENT_OP 259
-#define GARBAGE 260
-#define CPP_LINE_DIRECTIVE 261
-#define CPP_INCLUDE 262
-#define F90PPR_INCLUDE 263
-#define COCO_INCLUDE 264
-#define F90PPR_DEFINE 265
-#define CPP_DEFINE 266
-#define F90PPR_UNDEF 267
-#define CPP_UNDEF 268
-#define CPP_IFDEF 269
-#define CPP_IFNDEF 270
-#define CPP_IF 271
-#define CPP_ELSE 272
-#define CPP_ELIF 273
-#define CPP_ENDIF 274
-#define F90PPR_IFDEF 275
-#define F90PPR_IFNDEF 276
-#define F90PPR_IF 277
-#define F90PPR_ELSE 278
-#define F90PPR_ELIF 279
-#define F90PPR_ENDIF 280
-#define COMMA 281
-#define COLON 282
-#define DCOLON 283
-#define LPAREN 284
-#define RPAREN 285
-#define UNTERMINATED_STRING 286
-#define STRING 287
-#define WORD 288
-#define CPP_INCLUDE_ANGLE 289
-#define END 290
-#define INCLUDE 291
-#define INTERFACE 292
-#define MODULE 293
-#define SUBMODULE 294
-#define USE 295
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 union YYSTYPE
 {
-#line 73 "cmFortranParser.y"
+#line 71 "cmFortranParser.y"
 
   char* string;
 
-#line 141 "cmFortranParserTokens.h"
+#line 108 "cmFortranParserTokens.h"
 
 };
 typedef union YYSTYPE YYSTYPE;
index a98969d..3630f4e 100644 (file)
@@ -994,7 +994,7 @@ case 5:
 YY_RULE_SETUP
 {
                          // A line continuation ends the current file name.
-                         yyextra->newDependency();
+                         yyextra->newRuleOrDependency();
                        }
        YY_BREAK
 case 6:
index 08f8577..c83cb75 100644 (file)
@@ -42,7 +42,7 @@ NEWLINE \r?\n
                        }
 {WSPACE}*\\{NEWLINE}   {
                          // A line continuation ends the current file name.
-                         yyextra->newDependency();
+                         yyextra->newRuleOrDependency();
                        }
 {NEWLINE}              {
                          // A newline ends the current file name and the current rule.
index 0f0c39a..0c263bb 100644 (file)
@@ -3,20 +3,52 @@
 
 project(QtDialog)
 CMake_OPTIONAL_COMPONENT(cmake-gui)
-find_package(Qt5Widgets REQUIRED)
+set (QT_COMPONENTS
+  Core
+  Widgets
+  Gui
+)
+
+set(CMake_QT_MAJOR_VERSION "A" CACHE
+  STRING "Expected Qt major version. Valid values are A (auto-select), 5, 6.")
+set(SUPPORTED_QT_VERSIONS "A" 5 6)
+set_property(CACHE CMake_QT_MAJOR_VERSION PROPERTY STRINGS ${SUPPORTED_QT_VERSIONS})
+if(NOT CMake_QT_MAJOR_VERSION STREQUAL "A")
+  if(NOT CMake_QT_MAJOR_VERSION IN_LIST SUPPORTED_QT_VERSIONS)
+    message(FATAL_ERROR "Supported Qt versions are \"${SUPPORTED_QT_VERSIONS}\"."
+            " But CMake_QT_MAJOR_VERSION is set to ${CMake_QT_MAJOR_VERSION}.")
+  endif()
+  set(INSTALLED_QT_VERSION ${CMake_QT_MAJOR_VERSION})
+else()
+  find_package(Qt6Widgets QUIET)
+  set(INSTALLED_QT_VERSION 6)
+  if(NOT Qt6Widgets_FOUND)
+    find_package(Qt5Widgets QUIET)
+    if(NOT Qt5Widgets_FOUND)
+      message(FATAL_ERROR "Could not find a valid Qt installation.")
+    endif()
+    set(INSTALLED_QT_VERSION 5)
+  endif()
+endif()
+
+find_package(Qt${INSTALLED_QT_VERSION}
+    COMPONENTS ${QT_COMPONENTS}
+    REQUIRED QUIET
+)
 
 set(CMake_QT_EXTRA_LIBRARIES)
 
 # Try to find the package WinExtras for the task bar progress
 if(WIN32)
-  find_package(Qt5WinExtras QUIET)
-  if (Qt5WinExtras_FOUND)
+  find_package(Qt${INSTALLED_QT_VERSION}WinExtras QUIET)
+  if (Qt${INSTALLED_QT_VERSION}WinExtras_FOUND)
     add_definitions(-DQT_WINEXTRAS)
-    list(APPEND CMake_QT_EXTRA_LIBRARIES Qt5::WinExtras)
+    list(APPEND CMake_QT_EXTRA_LIBRARIES Qt${INSTALLED_QT_VERSION}::WinExtras)
+    list(APPEND QT_COMPONENTS WinExtras)
   endif()
 endif()
 
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt${INSTALLED_QT_VERSION}Widgets_EXECUTABLE_COMPILE_FLAGS}")
 
 if(CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES)
   list(APPEND CMake_QT_EXTRA_LIBRARIES ${CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES})
@@ -31,11 +63,25 @@ if(CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES)
 endif()
 
 # We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows.
-# FIXME: This should be part of Qt5 CMake scripts, but unfortunately
-# Qt5 support is missing there.
 if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
-  macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var)
-    get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION)
+  function(_qt_get_plugin_name_with_version target out_var)
+      string(REGEX REPLACE "^Qt::(.+)" "Qt${INSTALLED_QT_VERSION}::\\1"
+             qt_plugin_with_version "${target}")
+      if(TARGET "${qt_plugin_with_version}")
+          set("${out_var}" "${qt_plugin_with_version}" PARENT_SCOPE)
+      else()
+          set("${out_var}" "" PARENT_SCOPE)
+      endif()
+  endfunction()
+  macro(install_qt_plugin _qt_plugin_name _qt_plugins_var)
+    if(TARGET "${_qt_plugin_name}")
+      get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION)
+    else()
+      _qt_get_plugin_name_with_version("Qt::${_qt_plugin_name}" _qt_plugin_with_version_name)
+      if(TARGET "${_qt_plugin_with_version_name}")
+        get_target_property(_qt_plugin_path "${_qt_plugin_with_version_name}" LOCATION)
+      endif()
+    endif()
     if(EXISTS "${_qt_plugin_path}")
       get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME)
       get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH)
@@ -51,14 +97,34 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
         ${COMPONENT})
       set(${_qt_plugins_var}
         "${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}")
-    else()
-      message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found")
     endif()
   endmacro()
+  macro(install_qt_plugins _comps _plugins_var)
+    foreach(_qt_comp ${${_comps}})
+      if (INSTALLED_QT_VERSION VERSION_LESS 6)
+        set(_qt_module_plugins ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_PLUGINS})
+      else()
+        get_target_property(_qt_module_plugins Qt${INSTALLED_QT_VERSION}::${_qt_comp} QT_PLUGINS)
+      endif()
+      foreach(_qt_plugin ${_qt_module_plugins})
+        if (INSTALLED_QT_VERSION VERSION_GREATER_EQUAL 6)
+          # Qt6 provides the plugins as individual packages that need to be found.
+          find_package(Qt${INSTALLED_QT_VERSION}${_qt_plugin} QUIET
+            PATHS ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_DIR})
+        endif()
+        install_qt_plugin("${_qt_plugin}" "${_plugins_var}")
+      endforeach()
+    endforeach()
+  endmacro()
   if(APPLE)
-    install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS)
-    if(TARGET Qt5::QMacStylePlugin)
-      install_qt5_plugin("Qt5::QMacStylePlugin" QT_PLUGINS)
+    if (INSTALLED_QT_VERSION VERSION_EQUAL 5)
+      install_qt_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS)
+      if(TARGET Qt5::QMacStylePlugin)
+        install_qt_plugin("Qt5::QMacStylePlugin" QT_PLUGINS)
+      endif()
+    else()
+      # FIXME: Minimize plugins for Qt6.
+      install_qt_plugins(QT_COMPONENTS QT_PLUGINS)
     endif()
     file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
       "[Paths]\nPlugins = ${_qt_plugin_dir}\n")
@@ -66,7 +132,12 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
       DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources"
       ${COMPONENT})
   elseif(WIN32 AND NOT CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES)
-    install_qt5_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS)
+    if (INSTALLED_QT_VERSION VERSION_EQUAL 5)
+      install_qt_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS)
+    else()
+      # FIXME: Minimize plugins for Qt6.
+      install_qt_plugins(QT_COMPONENTS QT_PLUGINS)
+    endif()
     file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
       "[Paths]\nPlugins = ../${_qt_plugin_dir}\n")
     install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
@@ -75,8 +146,8 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
   endif()
 endif()
 
-get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION)
-get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH)
+get_property(_Qt_Core_LOCATION TARGET Qt${INSTALLED_QT_VERSION}::Core PROPERTY LOCATION)
+get_filename_component(Qt_BIN_DIR "${_Qt_Core_LOCATION}" PATH)
 if(APPLE)
   get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH)
 endif()
@@ -108,7 +179,7 @@ set(SRCS
   WarningMessagesDialog.cxx
   WarningMessagesDialog.h
   )
-qt5_wrap_ui(UI_SRCS
+set(UI_SRCS
   CMakeSetupDialog.ui
   Compilers.ui
   CrossCompiler.ui
@@ -117,7 +188,7 @@ qt5_wrap_ui(UI_SRCS
   RegexExplorer.ui
   WarningMessagesDialog.ui
   )
-qt5_wrap_cpp(MOC_SRCS
+set(MOC_SRCS
   AddCacheEntry.h
   Compilers.h
   CMakeSetupDialog.h
@@ -131,8 +202,18 @@ qt5_wrap_cpp(MOC_SRCS
   RegexExplorer.h
   WarningMessagesDialog.h
   )
-qt5_add_resources(RC_SRCS CMakeSetup.qrc)
-add_library(CMakeGUIQRCLib OBJECT ${RC_SRCS})
+set(QRC_SRCS CMakeSetup.qrc)
+
+if (INSTALLED_QT_VERSION VERSION_LESS 6)
+  qt5_wrap_ui(UI_BUILT_SRCS ${UI_SRCS})
+  qt5_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS})
+  qt5_add_resources(QRC_BUILT_SRCS ${QRC_SRCS})
+else()
+  qt_wrap_ui(UI_BUILT_SRCS ${UI_SRCS})
+  qt_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS})
+  qt_add_resources(QRC_BUILT_SRCS ${QRC_SRCS})
+endif()
+add_library(CMakeGUIQRCLib OBJECT ${QRC_BUILT_SRCS})
 
 if (FALSE) # CMake's bootstrap binary does not support automoc
   set(CMAKE_AUTOMOC 1)
@@ -140,8 +221,8 @@ if (FALSE) # CMake's bootstrap binary does not support automoc
   set(CMAKE_AUTOUIC 1)
 else ()
   list(APPEND SRCS
-    ${UI_SRCS}
-    ${MOC_SRCS})
+    ${UI_BUILT_SRCS}
+    ${MOC_BUILT_SRCS})
 endif ()
 
 if(USE_LGPL)
@@ -156,13 +237,14 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
 add_library(CMakeGUILib STATIC ${SRCS})
 # CMake_QT_EXTRA_LIBRARIES have to come before the main libraries on the link line
-target_link_libraries(CMakeGUILib PUBLIC CMakeLib ${CMake_QT_EXTRA_LIBRARIES} Qt5::Core Qt5::Widgets)
+target_link_libraries(CMakeGUILib PUBLIC CMakeLib ${CMake_QT_EXTRA_LIBRARIES}
+  Qt${INSTALLED_QT_VERSION}::Core Qt${INSTALLED_QT_VERSION}::Widgets)
 
 add_library(CMakeGUIMainLib STATIC CMakeSetup.cxx)
 target_link_libraries(CMakeGUIMainLib PUBLIC CMakeGUILib)
 
 add_executable(cmake-gui WIN32 MACOSX_BUNDLE CMakeGUIExec.cxx ${MANIFEST_FILE})
-target_link_libraries(cmake-gui CMakeGUIMainLib Qt5::Core)
+target_link_libraries(cmake-gui CMakeGUIMainLib Qt${INSTALLED_QT_VERSION}::Core)
 
 target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeGUIQRCLib>)
 if(WIN32)
index c1555a2..5debdb8 100644 (file)
@@ -7,7 +7,6 @@
 #include <QDir>
 #include <QLocale>
 #include <QString>
-#include <QTextCodec>
 #include <QTranslator>
 #include <QtPlugin>
 
@@ -122,9 +121,6 @@ int main(int argc, char** argv)
 
   setlocale(LC_NUMERIC, "C");
 
-  QTextCodec* utf8_codec = QTextCodec::codecForName("UTF-8");
-  QTextCodec::setCodecForLocale(utf8_codec);
-
   // tell the cmake library where cmake is
   QDir cmExecDir(QApplication::applicationDirPath());
 #if defined(Q_OS_MAC)
@@ -146,7 +142,7 @@ int main(int argc, char** argv)
   QIcon appIcon;
   appIcon.addFile(":/Icons/CMakeSetup32.png");
   appIcon.addFile(":/Icons/CMakeSetup128.png");
-  QApplication::setWindowIcon(appIcon);
+  QApplication::setWindowIcon(QIcon::fromTheme("cmake-gui", appIcon));
 
   CMakeSetupDialog dialog;
   dialog.show();
index 05518a9..0313088 100644 (file)
@@ -22,7 +22,6 @@
 #include <QShortcut>
 #include <QStatusBar>
 #include <QString>
-#include <QToolButton>
 #include <QUrl>
 #include <QVector>
 
@@ -253,7 +252,7 @@ void CMakeSetupDialog::initialize()
                    &QCMake::propertiesChanged, this->CacheValues->cacheModel(),
                    &QCMakeCacheModel::setProperties);
 
-  QObject::connect(this->ConfigureButton, &QPushButton::clicked, this,
+  QObject::connect(this->ConfigureButton, &QAbstractButton::clicked, this,
                    &CMakeSetupDialog::doConfigure);
 
   QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::configureDone,
@@ -261,15 +260,17 @@ void CMakeSetupDialog::initialize()
   QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::generateDone,
                    this, &CMakeSetupDialog::exitLoop);
 
-  QObject::connect(this->GenerateButton, &QPushButton::clicked, this,
+  QObject::connect(this->GenerateButton, &QAbstractButton::clicked, this,
                    &CMakeSetupDialog::doGenerate);
-  QObject::connect(this->OpenProjectButton, &QPushButton::clicked, this,
+  QObject::connect(this->OpenProjectButton, &QAbstractButton::clicked, this,
                    &CMakeSetupDialog::doOpenProject);
 
-  QObject::connect(this->BrowseSourceDirectoryButton, &QPushButton::clicked,
-                   this, &CMakeSetupDialog::doSourceBrowse);
-  QObject::connect(this->BrowseBinaryDirectoryButton, &QPushButton::clicked,
-                   this, &CMakeSetupDialog::doBinaryBrowse);
+  QObject::connect(this->BrowseSourceDirectoryButton,
+                   &QAbstractButton::clicked, this,
+                   &CMakeSetupDialog::doSourceBrowse);
+  QObject::connect(this->BrowseBinaryDirectoryButton,
+                   &QAbstractButton::clicked, this,
+                   &CMakeSetupDialog::doBinaryBrowse);
 
   QObject::connect(this->BinaryDirectory, &QComboBox::editTextChanged, this,
                    &CMakeSetupDialog::onBinaryDirectoryChanged);
@@ -324,12 +325,12 @@ void CMakeSetupDialog::initialize()
   QObject::connect(this->CacheValues->selectionModel(),
                    &QItemSelectionModel::selectionChanged, this,
                    &CMakeSetupDialog::selectionChanged);
-  QObject::connect(this->RemoveEntry, &QToolButton::clicked, this,
+  QObject::connect(this->RemoveEntry, &QAbstractButton::clicked, this,
                    &CMakeSetupDialog::removeSelectedCacheEntries);
-  QObject::connect(this->AddEntry, &QToolButton::clicked, this,
+  QObject::connect(this->AddEntry, &QAbstractButton::clicked, this,
                    &CMakeSetupDialog::addCacheEntry);
 
-  QObject::connect(this->Environment, &QToolButton::clicked, this,
+  QObject::connect(this->Environment, &QAbstractButton::clicked, this,
                    &CMakeSetupDialog::editEnvironment);
 
   QObject::connect(this->WarnUninitializedAction, &QAction::triggered,
index a5c35b1..c17c414 100644 (file)
      <item row="2" column="1">
       <widget class="QComboBox" name="BinaryDirectory">
        <property name="sizePolicy">
-        <sizepolicy hsizetype="Ignored" vsizetype="Fixed">
+        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
-       <property name="styleSheet">
-        <string notr="true">padding-left: 0</string>
-       </property>
        <property name="editable">
         <bool>true</bool>
        </property>
           </widget>
          </item>
          <item>
-          <widget class="QToolButton" name="AddEntry">
+          <widget class="QPushButton" name="AddEntry">
            <property name="toolTip">
             <string>Add New Entry</string>
            </property>
             <string>&amp;Add Entry</string>
            </property>
            <property name="icon">
-            <iconset resource="CMakeSetup.qrc">
+            <iconset theme="list-add" resource="CMakeSetup.qrc">
              <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
            </property>
-           <property name="toolButtonStyle">
-            <enum>Qt::ToolButtonTextBesideIcon</enum>
-           </property>
           </widget>
          </item>
          <item>
-          <widget class="QToolButton" name="RemoveEntry">
+          <widget class="QPushButton" name="RemoveEntry">
            <property name="toolTip">
             <string>Remove Selected Entries</string>
            </property>
             <string>&amp;Remove Entry</string>
            </property>
            <property name="icon">
-            <iconset resource="CMakeSetup.qrc">
+            <iconset theme="list-remove" resource="CMakeSetup.qrc">
              <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
            </property>
-           <property name="toolButtonStyle">
-            <enum>Qt::ToolButtonTextBesideIcon</enum>
-           </property>
           </widget>
          </item>
          <item>
index 846456c..bf89816 100644 (file)
@@ -81,7 +81,11 @@ bool EnvironmentSearchFilter::filterAcceptsRow(int row,
   auto* model = this->sourceModel();
   auto key =
     model->data(model->index(row, 0, parent), Qt::DisplayRole).toString();
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+  return key.contains(this->filterRegularExpression());
+#else
   return key.contains(this->filterRegExp());
+#endif
 }
 
 EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment,
@@ -102,12 +106,18 @@ EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment,
   this->Environment->setSelectionMode(QAbstractItemView::ExtendedSelection);
   this->Environment->setSelectionBehavior(QAbstractItemView::SelectRows);
 
-  QObject::connect(this->AddEntry, &QToolButton::clicked, this,
+  QObject::connect(this->AddEntry, &QAbstractButton::clicked, this,
                    &EnvironmentDialog::addEntry);
-  QObject::connect(this->RemoveEntry, &QToolButton::clicked, this,
+  QObject::connect(this->RemoveEntry, &QAbstractButton::clicked, this,
                    &EnvironmentDialog::removeSelectedEntries);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+  QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter,
+                   QOverload<const QString&>::of(
+                     &EnvironmentSearchFilter::setFilterRegularExpression));
+#else
   QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter,
                    &EnvironmentSearchFilter::setFilterFixedString);
+#endif
   QObject::connect(this->Environment->selectionModel(),
                    &QItemSelectionModel::selectionChanged, this,
                    &EnvironmentDialog::selectionChanged);
index dea7624..ed23c2c 100644 (file)
       </spacer>
      </item>
      <item>
-      <widget class="QToolButton" name="AddEntry">
+      <widget class="QPushButton" name="AddEntry">
        <property name="text">
         <string>&amp;Add Entry</string>
        </property>
        <property name="icon">
-        <iconset resource="CMakeSetup.qrc">
+        <iconset theme="list-add" resource="CMakeSetup.qrc">
          <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset>
        </property>
-       <property name="toolButtonStyle">
-        <enum>Qt::ToolButtonTextBesideIcon</enum>
-       </property>
       </widget>
      </item>
      <item>
-      <widget class="QToolButton" name="RemoveEntry">
+      <widget class="QPushButton" name="RemoveEntry">
        <property name="text">
         <string>&amp;Remove Entry</string>
        </property>
        <property name="icon">
-        <iconset resource="CMakeSetup.qrc">
+        <iconset theme="list-remove" resource="CMakeSetup.qrc">
          <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset>
        </property>
-       <property name="toolButtonStyle">
-        <enum>Qt::ToolButtonTextBesideIcon</enum>
-       </property>
       </widget>
      </item>
     </layout>
index 2f41f70..f593f83 100644 (file)
@@ -68,9 +68,9 @@ QCMake::QCMake(QObject* p)
   connect(&this->LoadPresetsTimer, &QTimer::timeout, this, [this]() {
     this->loadPresets();
     if (!this->PresetName.isEmpty() &&
-        this->CMakePresetsFile.Presets.find(
+        this->CMakePresetsFile.ConfigurePresets.find(
           std::string(this->PresetName.toLocal8Bit())) ==
-          this->CMakePresetsFile.Presets.end()) {
+          this->CMakePresetsFile.ConfigurePresets.end()) {
       this->setPreset(QString{});
     }
   });
@@ -158,7 +158,7 @@ void QCMake::setPreset(const QString& name, bool setBinary)
     if (!name.isNull()) {
       std::string presetName(name.toLocal8Bit());
       auto const& expandedPreset =
-        this->CMakePresetsFile.Presets[presetName].Expanded;
+        this->CMakePresetsFile.ConfigurePresets[presetName].Expanded;
       if (expandedPreset) {
         if (setBinary) {
           QString binaryDir =
@@ -420,7 +420,8 @@ QCMakePropertyList QCMake::properties() const
 
   if (!this->PresetName.isNull()) {
     std::string presetName(this->PresetName.toLocal8Bit());
-    auto const& p = this->CMakePresetsFile.Presets.at(presetName).Expanded;
+    auto const& p =
+      this->CMakePresetsFile.ConfigurePresets.at(presetName).Expanded;
     if (p) {
       for (auto const& v : p->CacheVariables) {
         if (!v.second) {
@@ -535,8 +536,8 @@ void QCMake::loadPresets()
   this->LastLoadPresetsResult = result;
 
   QVector<QCMakePreset> presets;
-  for (auto const& name : this->CMakePresetsFile.PresetOrder) {
-    auto const& it = this->CMakePresetsFile.Presets[name];
+  for (auto const& name : this->CMakePresetsFile.ConfigurePresetOrder) {
+    auto const& it = this->CMakePresetsFile.ConfigurePresets[name];
     auto const& p = it.Unexpanded;
     if (p.Hidden) {
       continue;
index 22f5be1..994df78 100644 (file)
@@ -47,7 +47,11 @@ protected:
 
     // check all strings for a match
     foreach (QString const& str, strs) {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+      if (str.contains(this->filterRegularExpression())) {
+#else
       if (str.contains(this->filterRegExp())) {
+#endif
         return true;
       }
     }
@@ -166,7 +170,11 @@ bool QCMakeCacheView::showAdvanced() const
 
 void QCMakeCacheView::setSearchFilter(const QString& s)
 {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+  this->SearchFilter->setFilterRegularExpression(s);
+#else
   this->SearchFilter->setFilterFixedString(s);
+#endif
 }
 
 QCMakeCacheModel::QCMakeCacheModel(QObject* p)
index e68faba..03d6ed1 100644 (file)
@@ -1,20 +1,23 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
 
-// FIXME: Port to QFileSystemModel from the deprecated QDirModel.
-// Be sure completion works when incrementally editing existing paths.
 #define QT_DEPRECATED_WARNINGS_SINCE QT_VERSION_CHECK(5, 14, 0)
 
 #include "QCMakeWidgets.h"
 
 #include <utility>
 
-#include <QDirModel>
 #include <QFileDialog>
 #include <QFileInfo>
 #include <QResizeEvent>
 #include <QToolButton>
 
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+#  include <QFileSystemModel>
+#else
+#  include <QDirModel>
+#endif
+
 QCMakeFileEditor::QCMakeFileEditor(QWidget* p, QString var)
   : QLineEdit(p)
   , Variable(std::move(var))
@@ -22,7 +25,7 @@ QCMakeFileEditor::QCMakeFileEditor(QWidget* p, QString var)
   this->ToolButton = new QToolButton(this);
   this->ToolButton->setText("...");
   this->ToolButton->setCursor(QCursor(Qt::ArrowCursor));
-  QObject::connect(this->ToolButton, &QToolButton::clicked, this,
+  QObject::connect(this->ToolButton, &QAbstractButton::clicked, this,
                    &QCMakeFileEditor::chooseFile);
 }
 
@@ -93,8 +96,30 @@ void QCMakePathEditor::chooseFile()
   }
 }
 
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+// use same QFileSystemModel for all completers
+static QFileSystemModel* fileDirModel()
+
+{
+  static QFileSystemModel* m = nullptr;
+  if (!m) {
+    m = new QFileSystemModel();
+  }
+  return m;
+}
+static QFileSystemModel* pathDirModel()
+{
+  static QFileSystemModel* m = nullptr;
+  if (!m) {
+    m = new QFileSystemModel();
+    m->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot);
+  }
+  return m;
+}
+#else
 // use same QDirModel for all completers
 static QDirModel* fileDirModel()
+
 {
   static QDirModel* m = nullptr;
   if (!m) {
@@ -111,12 +136,19 @@ static QDirModel* pathDirModel()
   }
   return m;
 }
+#endif
 
 QCMakeFileCompleter::QCMakeFileCompleter(QObject* o, bool dirs)
   : QCompleter(o)
 {
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+  QFileSystemModel* m = dirs ? pathDirModel() : fileDirModel();
+  this->setModel(m);
+  m->setRootPath(QString());
+#else
   QDirModel* m = dirs ? pathDirModel() : fileDirModel();
   this->setModel(m);
+#endif
 }
 
 QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const
index 8435740..0dc954a 100644 (file)
@@ -467,7 +467,7 @@ bool DumpFile(std::string const& nmPath, const char* filename,
 
 bool bindexplib::AddObjectFile(const char* filename)
 {
-  return DumpFile(NmPath, filename, this->Symbols, this->DataSymbols);
+  return DumpFile(this->NmPath, filename, this->Symbols, this->DataSymbols);
 }
 
 bool bindexplib::AddDefinitionFile(const char* filename)
@@ -511,5 +511,5 @@ void bindexplib::WriteFile(FILE* file)
 
 void bindexplib::SetNmPath(std::string const& nm)
 {
-  NmPath = nm;
+  this->NmPath = nm;
 }
index 231a2d6..a7ce3a6 100644 (file)
@@ -5,11 +5,11 @@
 #include <sstream>
 #include <unordered_set>
 
-#include "cmCheckCustomOutputs.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmCustomCommandTypes.h"
 #include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -188,17 +188,10 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
         case doing_output:
         case doing_outputs:
         case doing_byproducts:
-          if (!cmSystemTools::FileIsFullPath(copy)) {
+          if (!cmSystemTools::FileIsFullPath(copy) &&
+              cmGeneratorExpression::Find(copy) != 0) {
             // This is an output to be generated, so it should be
-            // under the build tree.  CMake 2.4 placed this under the
-            // source tree.  However the only case that this change
-            // will break is when someone writes
-            //
-            //   add_custom_command(OUTPUT out.txt ...)
-            //
-            // and later references "${CMAKE_CURRENT_SOURCE_DIR}/out.txt".
-            // This is fairly obscure so we can wait for someone to
-            // complain.
+            // under the build tree.
             filename = cmStrCat(mf.GetCurrentBinaryDirectory(), '/');
           }
           filename += copy;
@@ -215,8 +208,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
       }
 
       if (cmSystemTools::FileIsFullPath(filename)) {
-        filename = cmSystemTools::CollapseFullPath(
-          filename, status.GetMakefile().GetHomeOutputDirectory());
+        filename = cmSystemTools::CollapseFullPath(filename);
       }
       switch (doing) {
         case doing_depfile:
@@ -304,26 +296,18 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
     status.SetError("given APPEND option with no OUTPUT.");
     return false;
   }
-
-  // Make sure the output names and locations are safe.
-  if (!cmCheckCustomOutputs(output, "OUTPUT", status) ||
-      !cmCheckCustomOutputs(outputs, "OUTPUTS", status) ||
-      !cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) {
+  if (!implicit_depends.empty() && !depfile.empty() &&
+      mf.GetGlobalGenerator()->GetName() != "Ninja") {
+    // Makefiles generators does not support both at the same time
+    status.SetError("IMPLICIT_DEPENDS and DEPFILE can not both be specified.");
     return false;
   }
 
   // Check for an append request.
   if (append) {
-    if (mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
-                                       commandLines)) {
-      return true;
-    }
-
-    // No command for this output exists.
-    status.SetError(
-      cmStrCat("given APPEND option with output\n  ", output[0],
-               "\nwhich is not already a custom command output."));
-    return false;
+    mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
+                                   commandLines);
+    return true;
   }
 
   if (uses_terminal && !job_pool.empty()) {
@@ -336,15 +320,16 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
   if (source.empty() && output.empty()) {
     // Source is empty, use the target.
     std::vector<std::string> no_depends;
-    mf.AddCustomCommandToTarget(target, byproducts, no_depends, commandLines,
-                                cctype, comment, working.c_str(),
-                                escapeOldStyle, uses_terminal, depfile,
-                                job_pool, command_expand_lists);
+    mf.AddCustomCommandToTarget(
+      target, byproducts, no_depends, commandLines, cctype, comment,
+      working.c_str(), mf.GetPolicyStatus(cmPolicies::CMP0116), escapeOldStyle,
+      uses_terminal, depfile, job_pool, command_expand_lists);
   } else if (target.empty()) {
     // Target is empty, use the output.
     mf.AddCustomCommandToOutput(
       output, byproducts, depends, main_dependency, implicit_depends,
-      commandLines, comment, working.c_str(), nullptr, false, escapeOldStyle,
+      commandLines, comment, working.c_str(),
+      mf.GetPolicyStatus(cmPolicies::CMP0116), nullptr, false, escapeOldStyle,
       uses_terminal, command_expand_lists, depfile, job_pool);
   } else if (!byproducts.empty()) {
     status.SetError("BYPRODUCTS may not be specified with SOURCE signatures");
@@ -381,7 +366,8 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
 
     // Use the old-style mode for backward compatibility.
     mf.AddCustomCommandOldStyle(target, outputs, depends, source, commandLines,
-                                comment);
+                                comment,
+                                mf.GetPolicyStatus(cmPolicies::CMP0116));
   }
 
   return true;
index aa98d89..2b19aad 100644 (file)
@@ -4,13 +4,13 @@
 
 #include <utility>
 
-#include "cmCheckCustomOutputs.h"
 #include "cmCustomCommandLines.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -120,12 +120,16 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args,
           break;
         case doing_byproducts: {
           std::string filename;
-          if (!cmSystemTools::FileIsFullPath(copy)) {
+          if (!cmSystemTools::FileIsFullPath(copy) &&
+              cmGeneratorExpression::Find(copy) != 0) {
             filename = cmStrCat(mf.GetCurrentBinaryDirectory(), '/');
           }
           filename += copy;
           cmSystemTools::ConvertToUnixSlashes(filename);
-          byproducts.push_back(cmSystemTools::CollapseFullPath(filename));
+          if (cmSystemTools::FileIsFullPath(filename)) {
+            filename = cmSystemTools::CollapseFullPath(filename);
+          }
+          byproducts.push_back(filename);
         } break;
         case doing_depends: {
           std::string dep = copy;
@@ -206,17 +210,12 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  // Make sure the byproduct names and locations are safe.
-  if (!cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) {
-    return false;
-  }
-
   // Add the utility target to the makefile.
   bool escapeOldStyle = !verbatim;
   cmTarget* target = mf.AddUtilityCommand(
     targetName, excludeFromAll, working_directory.c_str(), byproducts, depends,
-    commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
-    job_pool);
+    commandLines, mf.GetPolicyStatus(cmPolicies::CMP0116), escapeOldStyle,
+    comment, uses_terminal, command_expand_lists, job_pool);
 
   // Add additional user-specified source files to the target.
   target->AddSources(sources);
index f262fac..92e04e4 100644 (file)
@@ -238,16 +238,6 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args,
       status.SetError("called with IMPORTED argument but no library type.");
       return false;
     }
-    if (type == cmStateEnums::OBJECT_LIBRARY) {
-      std::string reason;
-      if (!mf.GetGlobalGenerator()->HasKnownObjectFileLocation(&reason)) {
-        mf.IssueMessage(
-          MessageType::FATAL_ERROR,
-          "The OBJECT library type may not be used for IMPORTED libraries" +
-            reason + ".");
-        return true;
-      }
-    }
     if (type == cmStateEnums::INTERFACE_LIBRARY) {
       if (!cmGeneratorExpression::IsValidTargetName(libName)) {
         status.SetError(cmStrCat(
index 87000da..c192e2a 100644 (file)
@@ -47,7 +47,8 @@ struct BinarySearcher
 
   bool operator()(argument_type const& item) const
   {
-    return std::binary_search(m_range.begin(), m_range.end(), item);
+    return std::binary_search(this->m_range.begin(), this->m_range.end(),
+                              item);
   }
 
 private:
index 356089b..b685b73 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmArchiveWrite.h"
 
+#include <cstdio>
 #include <cstring>
 #include <ctime>
 #include <iostream>
@@ -81,7 +82,8 @@ struct cmArchiveWrite::Callback
 };
 
 cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
-                               std::string const& format, int compressionLevel)
+                               std::string const& format, int compressionLevel,
+                               int numThreads)
   : Stream(os)
   , Archive(archive_write_new())
   , Disk(archive_read_disk_new())
@@ -142,6 +144,18 @@ cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c,
                                cm_archive_error_string(this->Archive));
         return;
       }
+      {
+        char sNumThreads[8];
+        snprintf(sNumThreads, sizeof(sNumThreads), "%d", numThreads);
+        sNumThreads[7] = '\0'; // for safety
+        if (archive_write_set_filter_option(this->Archive, "xz", "threads",
+                                            sNumThreads) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_compressor_xz_options: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
+      }
+
       break;
     case CompressZstd:
       if (archive_write_add_filter_zstd(this->Archive) != ARCHIVE_OK) {
index 0d33758..34aafe9 100644 (file)
@@ -26,7 +26,7 @@ public:
   }
   void Clear() { this->IsValueSet = false; }
   bool IsSet() const { return this->IsValueSet; }
-  T Get() const { return Value; }
+  T Get() const { return this->Value; }
 
 private:
   T Value;
@@ -54,7 +54,8 @@ public:
 
   /** Construct with output stream to which to write archive.  */
   cmArchiveWrite(std::ostream& os, Compress c = CompressNone,
-                 std::string const& format = "paxr", int compressionLevel = 0);
+                 std::string const& format = "paxr", int compressionLevel = 0,
+                 int numThreads = 1);
 
   ~cmArchiveWrite();
 
index 15edcc5..35f4c88 100644 (file)
@@ -51,7 +51,7 @@ bool cmAuxSourceDirectoryCommand(std::vector<std::string> const& args,
       if (dotpos != std::string::npos) {
         auto ext = cm::string_view(file).substr(dotpos + 1);
         // Process only source files
-        auto cm = mf.GetCMakeInstance();
+        auto* cm = mf.GetCMakeInstance();
         if (dotpos > 0 && cm->IsACLikeSourceExtension(ext)) {
           std::string fullname = cmStrCat(templateDirectory, '/', file);
           // add the file as a class file so
index 80ada47..a9c15c2 100644 (file)
@@ -36,8 +36,6 @@ void Base32Encode5(const unsigned char src[5], char dst[8])
 
 cmBase32Encoder::cmBase32Encoder() = default;
 
-cmBase32Encoder::~cmBase32Encoder() = default;
-
 std::string cmBase32Encoder::encodeString(const unsigned char* input,
                                           size_t len, bool padding)
 {
index 726f45d..d70a062 100644 (file)
@@ -17,9 +17,8 @@ class cmBase32Encoder
 public:
   static const char paddingChar = '=';
 
-public:
   cmBase32Encoder();
-  ~cmBase32Encoder();
+  ~cmBase32Encoder() = default;
 
   // Encodes the given input byte sequence into a string
   // @arg input Input data pointer
index b8215df..73321c6 100644 (file)
@@ -88,7 +88,8 @@ bool cmCMakePath::IsPrefix(const cmCMakePath& path) const
     ++prefix_it;
     ++path_it;
   }
-  return prefix_it == prefix_end;
+  return (prefix_it == prefix_end) ||
+    (prefix_it->empty() && path_it != path_end);
 }
 
 std::string cmCMakePath::FormatPath(std::string path, format fmt)
index 720f582..962fdcc 100644 (file)
@@ -37,7 +37,7 @@ public:
   template <typename T>
   CMakePathArgumentParser& Bind(cm::static_string_view name, T Result::*member)
   {
-    cmArgumentParser<Result>::Bind(name, member);
+    this->cmArgumentParser<Result>::Bind(name, member);
     return *this;
   }
 
@@ -48,12 +48,12 @@ public:
   {
     this->Inputs.clear();
 
-    return cmArgumentParser<Result>::Parse(cmMakeRange(args).advance(Advance),
-                                           &this->Inputs, keywordsMissingValue,
-                                           parsedKeywords);
+    return this->cmArgumentParser<Result>::Parse(
+      cmMakeRange(args).advance(Advance), &this->Inputs, keywordsMissingValue,
+      parsedKeywords);
   }
 
-  const std::vector<std::string>& GetInputs() const { return Inputs; }
+  const std::vector<std::string>& GetInputs() const { return this->Inputs; }
 
 protected:
   mutable std::vector<std::string> Inputs;
@@ -74,7 +74,7 @@ public:
   ArgumentParserWithOutputVariable& Bind(cm::static_string_view name,
                                          T Result::*member)
   {
-    cmArgumentParser<Result>::Bind(name, member);
+    this->cmArgumentParser<Result>::Bind(name, member);
     return *this;
   }
 
@@ -84,7 +84,7 @@ public:
     this->KeywordsMissingValue.clear();
     this->ParsedKeywords.clear();
 
-    return CMakePathArgumentParser<Result>::template Parse<Advance>(
+    return this->CMakePathArgumentParser<Result>::template Parse<Advance>(
       args, &this->KeywordsMissingValue, &this->ParsedKeywords);
   }
 
@@ -149,7 +149,7 @@ public:
 bool getInputPath(const std::string& arg, cmExecutionStatus& status,
                   std::string& path)
 {
-  auto def = status.GetMakefile().GetDefinition(arg);
+  const auto* def = status.GetMakefile().GetDefinition(arg);
   if (def == nullptr) {
     status.SetError("undefined variable for input path.");
     return false;
@@ -194,7 +194,7 @@ bool HandleGetCommand(std::vector<std::string> const& args,
                  }
                  return path.GetNarrowStem();
                } },
-             { "RELATIVE_PATH"_s,
+             { "RELATIVE_PART"_s,
                [](const cmCMakePath& path, bool) -> cmCMakePath {
                  return path.GetRelativePath();
                } },
@@ -250,9 +250,48 @@ bool HandleGetCommand(std::vector<std::string> const& args,
   return true;
 }
 
+bool HandleSetCommand(std::vector<std::string> const& args,
+                      cmExecutionStatus& status)
+{
+  if (args.size() < 3 || args.size() > 4) {
+    status.SetError("SET must be called with two or three arguments.");
+    return false;
+  }
+
+  if (args[1].empty()) {
+    status.SetError("Invalid name for path variable.");
+    return false;
+  }
+
+  static NormalizeParser const parser;
+
+  const auto arguments = parser.Parse(args);
+
+  if (parser.GetInputs().size() != 1) {
+    status.SetError("SET called with unexpected arguments.");
+    return false;
+  }
+
+  auto path =
+    cmCMakePath(parser.GetInputs().front(), cmCMakePath::native_format);
+
+  if (arguments.Normalize) {
+    path = path.Normal();
+  }
+
+  status.GetMakefile().AddDefinition(args[1], path.GenericString());
+
+  return true;
+}
+
 bool HandleAppendCommand(std::vector<std::string> const& args,
                          cmExecutionStatus& status)
 {
+  if (args[1].empty()) {
+    status.SetError("Invalid name for path variable.");
+    return false;
+  }
+
   static OutputVariableParser const parser{};
 
   const auto arguments = parser.Parse(args);
@@ -272,8 +311,8 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
   return true;
 }
 
-bool HandleConcatCommand(std::vector<std::string> const& args,
-                         cmExecutionStatus& status)
+bool HandleAppendStringCommand(std::vector<std::string> const& args,
+                               cmExecutionStatus& status)
 {
   static OutputVariableParser const parser{};
 
@@ -546,16 +585,6 @@ bool HandleRelativePathCommand(std::vector<std::string> const& args,
     });
 }
 
-bool HandleProximatePathCommand(std::vector<std::string> const& args,
-                                cmExecutionStatus& status)
-{
-  return HandleTransformPathCommand(
-    args, status,
-    [](const cmCMakePath& path, const std::string& base) -> cmCMakePath {
-      return path.Proximate(base);
-    });
-}
-
 bool HandleAbsolutePathCommand(std::vector<std::string> const& args,
                                cmExecutionStatus& status)
 {
@@ -567,40 +596,6 @@ bool HandleAbsolutePathCommand(std::vector<std::string> const& args,
     true);
 }
 
-bool HandleCMakePathCommand(std::vector<std::string> const& args,
-                            cmExecutionStatus& status)
-{
-  if (args.size() < 3 || args.size() > 4) {
-    status.SetError("CMAKE_PATH must be called with two or three arguments.");
-    return false;
-  }
-
-  static NormalizeParser const parser;
-
-  const auto arguments = parser.Parse(args);
-
-  if (parser.GetInputs().size() != 1) {
-    status.SetError("CMAKE_PATH called with unexpected arguments.");
-    return false;
-  }
-
-  if (args[1].empty()) {
-    status.SetError("Invalid name for output variable.");
-    return false;
-  }
-
-  auto path =
-    cmCMakePath(parser.GetInputs().front(), cmCMakePath::native_format);
-
-  if (arguments.Normalize) {
-    path = path.Normal();
-  }
-
-  status.GetMakefile().AddDefinition(args[1], path.GenericString());
-
-  return true;
-}
-
 bool HandleNativePathCommand(std::vector<std::string> const& args,
                              cmExecutionStatus& status)
 {
@@ -737,12 +732,7 @@ bool HandleCompareCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  std::string inputPath;
-  if (!getInputPath(args[1], status, inputPath)) {
-    return false;
-  }
-
-  cmCMakePath path1(inputPath);
+  cmCMakePath path1(args[1]);
   cmCMakePath path2(args[3]);
   auto result = op->second(path1, path2);
 
@@ -827,7 +817,7 @@ bool HandleHasStemCommand(std::vector<std::string> const& args,
     [](const cmCMakePath& path) -> bool { return path.HasStem(); });
 }
 
-bool HandleHasRelativePathCommand(std::vector<std::string> const& args,
+bool HandleHasRelativePartCommand(std::vector<std::string> const& args,
                                   cmExecutionStatus& status)
 {
   return HandleHasItemCommand(
@@ -939,17 +929,8 @@ bool HandleIsPrefixCommand(std::vector<std::string> const& args,
 bool HandleHashCommand(std::vector<std::string> const& args,
                        cmExecutionStatus& status)
 {
-  if (args.size() < 3 || args.size() > 4) {
-    status.SetError("HASH must be called with two or three arguments.");
-    return false;
-  }
-
-  static NormalizeParser const parser;
-
-  const auto arguments = parser.Parse(args);
-
-  if (parser.GetInputs().size() != 1) {
-    status.SetError("HASH called with unexpected arguments.");
+  if (args.size() != 3) {
+    status.SetError("HASH must be called with two arguments.");
     return false;
   }
 
@@ -958,15 +939,14 @@ bool HandleHashCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  const auto& output = parser.GetInputs().front();
+  const auto& output = args[2];
 
   if (output.empty()) {
     status.SetError("Invalid name for output variable.");
     return false;
   }
 
-  auto hash = hash_value(arguments.Normalize ? cmCMakePath(inputPath).Normal()
-                                             : cmCMakePath(inputPath));
+  auto hash = hash_value(cmCMakePath(inputPath).Normal());
 
   std::ostringstream out;
   out << std::setbase(16) << hash;
@@ -987,17 +967,16 @@ bool cmCMakePathCommand(std::vector<std::string> const& args,
 
   static cmSubcommandTable const subcommand{
     { "GET"_s, HandleGetCommand },
+    { "SET"_s, HandleSetCommand },
     { "APPEND"_s, HandleAppendCommand },
-    { "CONCAT"_s, HandleConcatCommand },
+    { "APPEND_STRING"_s, HandleAppendStringCommand },
     { "REMOVE_FILENAME"_s, HandleRemoveFilenameCommand },
     { "REPLACE_FILENAME"_s, HandleReplaceFilenameCommand },
     { "REMOVE_EXTENSION"_s, HandleRemoveExtensionCommand },
     { "REPLACE_EXTENSION"_s, HandleReplaceExtensionCommand },
     { "NORMAL_PATH"_s, HandleNormalPathCommand },
     { "RELATIVE_PATH"_s, HandleRelativePathCommand },
-    { "PROXIMATE_PATH"_s, HandleProximatePathCommand },
     { "ABSOLUTE_PATH"_s, HandleAbsolutePathCommand },
-    { "CMAKE_PATH"_s, HandleCMakePathCommand },
     { "NATIVE_PATH"_s, HandleNativePathCommand },
     { "CONVERT"_s, HandleConvertCommand },
     { "COMPARE"_s, HandleCompareCommand },
@@ -1007,7 +986,7 @@ bool cmCMakePathCommand(std::vector<std::string> const& args,
     { "HAS_FILENAME"_s, HandleHasFilenameCommand },
     { "HAS_EXTENSION"_s, HandleHasExtensionCommand },
     { "HAS_STEM"_s, HandleHasStemCommand },
-    { "HAS_RELATIVE_PATH"_s, HandleHasRelativePathCommand },
+    { "HAS_RELATIVE_PART"_s, HandleHasRelativePartCommand },
     { "HAS_PARENT_PATH"_s, HandleHasParentPathCommand },
     { "IS_ABSOLUTE"_s, HandleIsAbsoluteCommand },
     { "IS_RELATIVE"_s, HandleIsRelativeCommand },
index b7f08d2..1f99043 100644 (file)
@@ -191,8 +191,7 @@ bool HandleVersionMode(std::vector<std::string> const& args,
     return false;
   }
 
-  status.GetMakefile().SetPolicyVersion(version_min, version_max);
-  return true;
+  return status.GetMakefile().SetPolicyVersion(version_min, version_max);
 }
 
 bool HandleGetWarningMode(std::vector<std::string> const& args,
index 872cb4e..dda3661 100644 (file)
@@ -2,8 +2,11 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCMakePresetsFile.h"
 
+#include <algorithm>
 #include <cstdlib>
 #include <functional>
+#include <iostream>
+#include <iterator>
 #include <utility>
 
 #include <cmext/string_view>
 #include "cmSystemTools.h"
 #include "cmVersion.h"
 
+#define CHECK_OK(expr)                                                        \
+  {                                                                           \
+    auto _result = expr;                                                      \
+    if (_result != ReadFileResult::READ_OK)                                   \
+      return _result;                                                         \
+  }
+
+#define CHECK_EXPAND(out, field, expanders)                                   \
+  {                                                                           \
+    switch (ExpandMacros(field, expanders)) {                                 \
+      case ExpandMacroResult::Error:                                          \
+        return false;                                                         \
+      case ExpandMacroResult::Ignore:                                         \
+        out.reset();                                                          \
+        return true;                                                          \
+      case ExpandMacroResult::Ok:                                             \
+        break;                                                                \
+    }                                                                         \
+  }
+
 namespace {
 enum class CycleStatus
 {
@@ -28,12 +51,13 @@ enum class CycleStatus
 
 using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
 using CacheVariable = cmCMakePresetsFile::CacheVariable;
-using UnexpandedPreset = cmCMakePresetsFile::UnexpandedPreset;
-using ExpandedPreset = cmCMakePresetsFile::ExpandedPreset;
+using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
+using BuildPreset = cmCMakePresetsFile::BuildPreset;
+using TestPreset = cmCMakePresetsFile::TestPreset;
 using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy;
 
 constexpr int MIN_VERSION = 1;
-constexpr int MAX_VERSION = 1;
+constexpr int MAX_VERSION = 2;
 
 struct CMakeVersion
 {
@@ -45,7 +69,9 @@ struct CMakeVersion
 struct RootPresets
 {
   CMakeVersion CMakeMinimumRequired;
-  std::vector<cmCMakePresetsFile::UnexpandedPreset> Presets;
+  std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets;
+  std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets;
+  std::vector<cmCMakePresetsFile::TestPreset> TestPresets;
 };
 
 cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
@@ -181,35 +207,43 @@ auto const PresetOptionalBoolHelper =
   cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK,
                                              PresetBoolHelper);
 
+auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
+
+auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>(
+  ReadFileResult::READ_OK, PresetIntHelper);
+
+auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
+
 auto const PresetWarningsHelper =
-  cmJSONObjectHelper<UnexpandedPreset, ReadFileResult>(
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("dev"_s, &UnexpandedPreset::WarnDev, PresetOptionalBoolHelper, false)
-    .Bind("deprecated"_s, &UnexpandedPreset::WarnDeprecated,
+    .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false)
+    .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
           PresetOptionalBoolHelper, false)
-    .Bind("uninitialized"_s, &UnexpandedPreset::WarnUninitialized,
+    .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
           PresetOptionalBoolHelper, false)
-    .Bind("unusedCli"_s, &UnexpandedPreset::WarnUnusedCli,
+    .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
           PresetOptionalBoolHelper, false)
-    .Bind("systemVars"_s, &UnexpandedPreset::WarnSystemVars,
+    .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
           PresetOptionalBoolHelper, false);
 
 auto const PresetErrorsHelper =
-  cmJSONObjectHelper<UnexpandedPreset, ReadFileResult>(
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("dev"_s, &UnexpandedPreset::ErrorDev, PresetOptionalBoolHelper,
-          false)
-    .Bind("deprecated"_s, &UnexpandedPreset::ErrorDeprecated,
+    .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false)
+    .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
           PresetOptionalBoolHelper, false);
 
 auto const PresetDebugHelper =
-  cmJSONObjectHelper<UnexpandedPreset, ReadFileResult>(
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("output"_s, &UnexpandedPreset::DebugOutput, PresetOptionalBoolHelper,
+    .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper,
           false)
-    .Bind("tryCompile"_s, &UnexpandedPreset::DebugTryCompile,
+    .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
           PresetOptionalBoolHelper, false)
-    .Bind("find"_s, &UnexpandedPreset::DebugFind, PresetOptionalBoolHelper,
+    .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper,
           false);
 
 ReadFileResult ArchToolsetStrategyHelper(
@@ -237,18 +271,18 @@ ReadFileResult ArchToolsetStrategyHelper(
   return ReadFileResult::INVALID_PRESET;
 }
 
-std::function<ReadFileResult(UnexpandedPreset&, const Json::Value*)>
+std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
 ArchToolsetHelper(
-  std::string UnexpandedPreset::*valueField,
-  cm::optional<ArchToolsetStrategy> UnexpandedPreset::*strategyField)
+  std::string ConfigurePreset::*valueField,
+  cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
 {
   auto const objectHelper =
-    cmJSONObjectHelper<UnexpandedPreset, ReadFileResult>(
+    cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
       ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
       .Bind("value", valueField, PresetStringHelper, false)
       .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
   return [valueField, strategyField, objectHelper](
-           UnexpandedPreset& out, const Json::Value* value) -> ReadFileResult {
+           ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
     if (!value) {
       (out.*valueField).clear();
       out.*strategyField = cm::nullopt;
@@ -270,41 +304,395 @@ ArchToolsetHelper(
 }
 
 auto const ArchitectureHelper = ArchToolsetHelper(
-  &UnexpandedPreset::Architecture, &UnexpandedPreset::ArchitectureStrategy);
+  &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
 auto const ToolsetHelper = ArchToolsetHelper(
-  &UnexpandedPreset::Toolset, &UnexpandedPreset::ToolsetStrategy);
+  &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
 
-auto const PresetHelper =
-  cmJSONObjectHelper<UnexpandedPreset, ReadFileResult>(
+auto const ConfigurePresetHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("name"_s, &UnexpandedPreset::Name, PresetStringHelper)
-    .Bind("inherits"_s, &UnexpandedPreset::Inherits, PresetInheritsHelper,
+    .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper)
+    .Bind("inherits"_s, &ConfigurePreset::Inherits, PresetInheritsHelper,
           false)
-    .Bind("hidden"_s, &UnexpandedPreset::Hidden, PresetBoolHelper, false)
+    .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false)
     .Bind<std::nullptr_t>("vendor"_s, nullptr,
                           VendorHelper(ReadFileResult::INVALID_PRESET), false)
-    .Bind("displayName"_s, &UnexpandedPreset::DisplayName, PresetStringHelper,
+    .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper,
           false)
-    .Bind("description"_s, &UnexpandedPreset::Description, PresetStringHelper,
+    .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper,
           false)
-    .Bind("generator"_s, &UnexpandedPreset::Generator, PresetStringHelper,
+    .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper,
           false)
     .Bind("architecture"_s, ArchitectureHelper, false)
     .Bind("toolset"_s, ToolsetHelper, false)
-    .Bind("binaryDir"_s, &UnexpandedPreset::BinaryDir, PresetStringHelper,
+    .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper,
           false)
     .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
-    .Bind("cacheVariables"_s, &UnexpandedPreset::CacheVariables,
+    .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
           VariablesHelper, false)
-    .Bind("environment"_s, &UnexpandedPreset::Environment,
-          EnvironmentMapHelper, false)
+    .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper,
+          false)
     .Bind("warnings"_s, PresetWarningsHelper, false)
     .Bind("errors"_s, PresetErrorsHelper, false)
     .Bind("debug"_s, PresetDebugHelper, false);
 
-auto const PresetsHelper =
-  cmJSONVectorHelper<UnexpandedPreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, PresetHelper);
+auto const BuildPresetHelper =
+  cmJSONObjectHelper<BuildPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &BuildPreset::Name, PresetStringHelper)
+    .Bind("inherits"_s, &BuildPreset::Inherits, PresetInheritsHelper, false)
+    .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
+    .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper,
+          false)
+    .Bind("description"_s, &BuildPreset::Description, PresetStringHelper,
+          false)
+    .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper,
+          false)
+    .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
+          PresetStringHelper, false)
+    .Bind("inheritConfigureEnvironment"_s,
+          &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
+          false)
+    .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false)
+    .Bind("targets"_s, &BuildPreset::Targets, PresetVectorStringHelper, false)
+    .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper,
+          false)
+    .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper,
+          false)
+    .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
+    .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
+          PresetVectorStringHelper, false);
+
+ReadFileResult TestPresetOutputVerbosityHelper(
+  TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
+{
+  if (!value) {
+    out = TestPreset::OutputOptions::VerbosityEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "default") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "verbose") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "extra") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Extra;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalOutputVerbosityHelper =
+  cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetOutputVerbosityHelper);
+
+auto const TestPresetOptionalOutputHelper =
+  cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+      .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
+            PresetOptionalBoolHelper, false)
+      .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
+            TestPresetOptionalOutputVerbosityHelper, false)
+      .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
+            PresetOptionalBoolHelper, false)
+      .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
+            PresetOptionalBoolHelper, false)
+      .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
+            PresetOptionalBoolHelper, false)
+      .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
+            PresetStringHelper, false)
+      .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
+            PresetOptionalBoolHelper, false)
+      .Bind("subprojectSummary"_s,
+            &TestPreset::OutputOptions::SubprojectSummary,
+            PresetOptionalBoolHelper, false)
+      .Bind("maxPassedTestOutputSize"_s,
+            &TestPreset::OutputOptions::MaxPassedTestOutputSize,
+            PresetOptionalIntHelper, false)
+      .Bind("maxFailedTestOutputSize"_s,
+            &TestPreset::OutputOptions::MaxFailedTestOutputSize,
+            PresetOptionalIntHelper, false)
+      .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
+            PresetOptionalIntHelper, false));
+
+auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
+  cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
+            PresetOptionalIntHelper, false)
+      .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
+            PresetOptionalIntHelper, false)
+      .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
+            PresetOptionalIntHelper, false)
+      .Bind("specificTests"_s,
+            &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
+            PresetVectorIntHelper, false));
+
+ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
+  cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isString()) {
+    out.emplace();
+    out->IndexFile = value->asString();
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isObject()) {
+    return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalFilterIncludeHelper =
+  cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper,
+            false)
+      .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper,
+            false)
+      .Bind("index"_s, &TestPreset::IncludeOptions::Index,
+            TestPresetOptionalFilterIncludeIndexHelper, false)
+      .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
+            PresetOptionalBoolHelper, false));
+
+auto const TestPresetOptionalFilterExcludeFixturesHelper =
+  cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
+            PresetStringHelper, false)
+      .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
+            PresetStringHelper, false)
+      .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
+            PresetStringHelper, false));
+
+auto const TestPresetOptionalFilterExcludeHelper =
+  cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper,
+            false)
+      .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper,
+            false)
+      .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
+            TestPresetOptionalFilterExcludeFixturesHelper, false));
+
+ReadFileResult TestPresetExecutionShowOnlyHelper(
+  TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
+{
+  if (!value || !value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "human") {
+    out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "json-v1") {
+    out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionShowOnlyHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetExecutionShowOnlyHelper);
+
+ReadFileResult TestPresetExecutionModeHelper(
+  TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "until-fail") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "until-pass") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "after-timeout") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionRepeatHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
+            TestPresetExecutionModeHelper, true)
+      .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
+            PresetIntHelper, true));
+
+ReadFileResult TestPresetExecutionNoTestsActionHelper(
+  TestPreset::ExecutionOptions::NoTestsActionEnum& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "default") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "error") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "ignore") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionNoTestsActionHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetExecutionNoTestsActionHelper);
+
+auto const TestPresetExecutionHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
+            PresetOptionalBoolHelper, false)
+      .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
+            PresetOptionalBoolHelper, false)
+      .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
+            PresetOptionalIntHelper, false)
+      .Bind("resourceSpecFile"_s,
+            &TestPreset::ExecutionOptions::ResourceSpecFile,
+            PresetStringHelper, false)
+      .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
+            PresetOptionalIntHelper, false)
+      .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
+            TestPresetOptionalExecutionShowOnlyHelper, false)
+      .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
+            TestPresetOptionalExecutionRepeatHelper, false)
+      .Bind("interactiveDebugging"_s,
+            &TestPreset::ExecutionOptions::InteractiveDebugging,
+            PresetOptionalBoolHelper, false)
+      .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
+            PresetOptionalBoolHelper, false)
+      .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
+            PresetOptionalIntHelper, false)
+      .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
+            TestPresetOptionalExecutionNoTestsActionHelper, false));
+
+auto const TestPresetFilterHelper =
+  cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("include"_s, &TestPreset::FilterOptions::Include,
+            TestPresetOptionalFilterIncludeHelper, false)
+      .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
+            TestPresetOptionalFilterExcludeHelper, false));
+
+auto const TestPresetHelper =
+  cmJSONObjectHelper<TestPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &TestPreset::Name, PresetStringHelper)
+    .Bind("inherits"_s, &TestPreset::Inherits, PresetInheritsHelper, false)
+    .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
+    .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false)
+    .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false)
+    .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper,
+          false)
+    .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
+          PresetStringHelper, false)
+    .Bind("inheritConfigureEnvironment"_s,
+          &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
+          false)
+    .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper,
+          false)
+    .Bind("overwriteConfigurationFile"_s,
+          &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper,
+          false)
+    .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
+          false)
+    .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
+    .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
+          false);
+
+auto const ConfigurePresetsHelper =
+  cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+    ConfigurePresetHelper);
+
+auto const BuildPresetsHelper =
+  cmJSONVectorHelper<BuildPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+    BuildPresetHelper);
+
+auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper);
 
 auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
   ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
@@ -320,7 +708,11 @@ auto const RootPresetsHelper =
   cmJSONObjectHelper<RootPresets, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
     .Bind<int>("version"_s, nullptr, VersionHelper)
-    .Bind("configurePresets"_s, &RootPresets::Presets, PresetsHelper, false)
+    .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
+          ConfigurePresetsHelper, false)
+    .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper,
+          false)
+    .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false)
     .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
           CMakeVersionHelper, false)
     .Bind<std::nullptr_t>("vendor"_s, nullptr,
@@ -333,23 +725,33 @@ void InheritString(std::string& child, const std::string& parent)
   }
 }
 
-void InheritOptionalBool(cm::optional<bool>& child,
-                         const cm::optional<bool>& parent)
+template <typename T>
+void InheritOptionalValue(cm::optional<T>& child,
+                          const cm::optional<T>& parent)
 {
   if (!child) {
     child = parent;
   }
 }
 
+template <typename T>
+void InheritVector(std::vector<T>& child, const std::vector<T>& parent)
+{
+  if (child.empty()) {
+    child = parent;
+  }
+}
+
 /**
  * Check preset inheritance for cycles (using a DAG check algorithm) while
  * also bubbling up fields through the inheritance hierarchy, then verify
  * that each preset has the required fields, either directly or through
  * inheritance.
  */
+template <class T>
 ReadFileResult VisitPreset(
-  std::map<std::string, cmCMakePresetsFile::PresetPair>& presets,
-  UnexpandedPreset& preset, std::map<std::string, CycleStatus> cycleStatus)
+  T& preset, std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
+  std::map<std::string, CycleStatus> cycleStatus)
 {
   switch (cycleStatus[preset.Name]) {
     case CycleStatus::InProgress:
@@ -362,80 +764,44 @@ ReadFileResult VisitPreset(
 
   cycleStatus[preset.Name] = CycleStatus::InProgress;
 
-  if (preset.CacheVariables.count("") != 0) {
-    return ReadFileResult::INVALID_PRESET;
-  }
   if (preset.Environment.count("") != 0) {
     return ReadFileResult::INVALID_PRESET;
   }
 
+  CHECK_OK(preset.VisitPresetBeforeInherit())
+
   for (auto const& i : preset.Inherits) {
     auto parent = presets.find(i);
     if (parent == presets.end()) {
       return ReadFileResult::INVALID_PRESET;
     }
 
-    if (!preset.User && parent->second.Unexpanded.User) {
+    auto& parentPreset = parent->second.Unexpanded;
+    if (!preset.User && parentPreset.User) {
       return ReadFileResult::USER_PRESET_INHERITANCE;
     }
 
-    auto result = VisitPreset(presets, parent->second.Unexpanded, cycleStatus);
+    auto result = VisitPreset(parentPreset, presets, cycleStatus);
     if (result != ReadFileResult::READ_OK) {
       return result;
     }
 
-    InheritString(preset.Generator, parent->second.Unexpanded.Generator);
-    InheritString(preset.Architecture, parent->second.Unexpanded.Architecture);
-    InheritString(preset.Toolset, parent->second.Unexpanded.Toolset);
-    if (!preset.ArchitectureStrategy) {
-      preset.ArchitectureStrategy =
-        parent->second.Unexpanded.ArchitectureStrategy;
-    }
-    if (!preset.ToolsetStrategy) {
-      preset.ToolsetStrategy = parent->second.Unexpanded.ToolsetStrategy;
-    }
-    InheritString(preset.BinaryDir, parent->second.Unexpanded.BinaryDir);
-    InheritOptionalBool(preset.WarnDev, parent->second.Unexpanded.WarnDev);
-    InheritOptionalBool(preset.ErrorDev, parent->second.Unexpanded.ErrorDev);
-    InheritOptionalBool(preset.WarnDeprecated,
-                        parent->second.Unexpanded.WarnDeprecated);
-    InheritOptionalBool(preset.ErrorDeprecated,
-                        parent->second.Unexpanded.ErrorDeprecated);
-    InheritOptionalBool(preset.WarnUninitialized,
-                        parent->second.Unexpanded.WarnUninitialized);
-    InheritOptionalBool(preset.WarnUnusedCli,
-                        parent->second.Unexpanded.WarnUnusedCli);
-    InheritOptionalBool(preset.WarnSystemVars,
-                        parent->second.Unexpanded.WarnSystemVars);
-    for (auto const& v : parent->second.Unexpanded.CacheVariables) {
-      preset.CacheVariables.insert(v);
-    }
-    for (auto const& v : parent->second.Unexpanded.Environment) {
+    CHECK_OK(preset.VisitPresetInherit(parentPreset))
+
+    for (auto const& v : parentPreset.Environment) {
       preset.Environment.insert(v);
     }
   }
 
-  if (!preset.Hidden) {
-    if (preset.Generator.empty()) {
-      return ReadFileResult::INVALID_PRESET;
-    }
-    if (preset.BinaryDir.empty()) {
-      return ReadFileResult::INVALID_PRESET;
-    }
-    if (preset.WarnDev == false && preset.ErrorDev == true) {
-      return ReadFileResult::INVALID_PRESET;
-    }
-    if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) {
-      return ReadFileResult::INVALID_PRESET;
-    }
-  }
+  CHECK_OK(preset.VisitPresetAfterInherit())
 
   cycleStatus[preset.Name] = CycleStatus::Verified;
   return ReadFileResult::READ_OK;
 }
 
+template <class T>
 ReadFileResult ComputePresetInheritance(
-  std::map<std::string, cmCMakePresetsFile::PresetPair>& presets)
+  std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets)
 {
   std::map<std::string, CycleStatus> cycleStatus;
   for (auto const& it : presets) {
@@ -443,7 +809,7 @@ ReadFileResult ComputePresetInheritance(
   }
 
   for (auto& it : presets) {
-    auto result = VisitPreset(presets, it.second.Unexpanded, cycleStatus);
+    auto result = VisitPreset<T>(it.second.Unexpanded, presets, cycleStatus);
     if (result != ReadFileResult::READ_OK) {
       return result;
     }
@@ -461,22 +827,16 @@ constexpr const char* ValidPrefixes[] = {
 
 bool PrefixesValidMacroNamespace(const std::string& str)
 {
-  for (auto const& prefix : ValidPrefixes) {
-    if (cmHasPrefix(prefix, str)) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(
+    std::begin(ValidPrefixes), std::end(ValidPrefixes),
+    [&str](const char* prefix) -> bool { return cmHasPrefix(prefix, str); });
 }
 
 bool IsValidMacroNamespace(const std::string& str)
 {
-  for (auto const& prefix : ValidPrefixes) {
-    if (str == prefix) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(
+    std::begin(ValidPrefixes), std::end(ValidPrefixes),
+    [&str](const char* prefix) -> bool { return str == prefix; });
 }
 
 enum class ExpandMacroResult
@@ -486,65 +846,186 @@ enum class ExpandMacroResult
   Error,
 };
 
-ExpandMacroResult VisitEnv(const cmCMakePresetsFile& file,
-                           cmCMakePresetsFile::ExpandedPreset& preset,
-                           std::map<std::string, CycleStatus>& envCycles,
-                           std::string& value, CycleStatus& status);
-ExpandMacroResult ExpandMacros(const cmCMakePresetsFile& file,
-                               cmCMakePresetsFile::ExpandedPreset& preset,
-                               std::map<std::string, CycleStatus>& envCycles,
-                               std::string& out);
-ExpandMacroResult ExpandMacro(const cmCMakePresetsFile& file,
-                              cmCMakePresetsFile::ExpandedPreset& preset,
-                              std::map<std::string, CycleStatus>& envCycles,
-                              std::string& out,
-                              const std::string& macroNamespace,
-                              const std::string& macroName);
+using MacroExpander = std::function<ExpandMacroResult(
+  const std::string&, const std::string&, std::string&)>;
+
+ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
+                           const std::vector<MacroExpander>& macroExpanders);
+ExpandMacroResult ExpandMacros(
+  std::string& out, const std::vector<MacroExpander>& macroExpanders);
+ExpandMacroResult ExpandMacro(
+  std::string& out, const std::string& macroNamespace,
+  const std::string& macroName,
+  const std::vector<MacroExpander>& macroExpanders);
 
 bool ExpandMacros(const cmCMakePresetsFile& file,
-                  const UnexpandedPreset& preset,
-                  cm::optional<ExpandedPreset>& out)
+                  const ConfigurePreset& preset,
+                  cm::optional<ConfigurePreset>& out,
+                  const std::vector<MacroExpander>& macroExpanders)
 {
-  out = preset;
+  std::string binaryDir = preset.BinaryDir;
+  CHECK_EXPAND(out, binaryDir, macroExpanders)
 
-  std::map<std::string, CycleStatus> envCycles;
-  for (auto const& v : out->Environment) {
-    envCycles[v.first] = CycleStatus::Unvisited;
+  if (!cmSystemTools::FileIsFullPath(binaryDir)) {
+    binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
   }
+  out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
+  cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
 
-  for (auto& v : out->Environment) {
-    if (v.second) {
-      switch (VisitEnv(file, *out, envCycles, *v.second, envCycles[v.first])) {
-        case ExpandMacroResult::Error:
-          return false;
-        case ExpandMacroResult::Ignore:
-          out.reset();
-          return true;
-        case ExpandMacroResult::Ok:
-          break;
+  for (auto& variable : out->CacheVariables) {
+    if (variable.second) {
+      CHECK_EXPAND(out, variable.second->Value, macroExpanders)
+    }
+  }
+
+  return true;
+}
+
+bool ExpandMacros(const cmCMakePresetsFile&, const BuildPreset&,
+                  cm::optional<BuildPreset>& out,
+                  const std::vector<MacroExpander>& macroExpanders)
+{
+  for (auto& target : out->Targets) {
+    CHECK_EXPAND(out, target, macroExpanders)
+  }
+
+  for (auto& nativeToolOption : out->NativeToolOptions) {
+    CHECK_EXPAND(out, nativeToolOption, macroExpanders)
+  }
+
+  return true;
+}
+
+bool ExpandMacros(const cmCMakePresetsFile&, const TestPreset&,
+                  cm::optional<TestPreset>& out,
+                  const std::vector<MacroExpander>& macroExpanders)
+{
+  for (auto& overwrite : out->OverwriteConfigurationFile) {
+    CHECK_EXPAND(out, overwrite, macroExpanders);
+  }
+
+  if (out->Output) {
+    CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders)
+  }
+
+  if (out->Filter) {
+    if (out->Filter->Include) {
+      CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders)
+      CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders)
+
+      if (out->Filter->Include->Index) {
+        CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile,
+                     macroExpanders);
+      }
+    }
+
+    if (out->Filter->Exclude) {
+      CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders)
+      CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders)
+
+      if (out->Filter->Exclude->Fixtures) {
+        CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders)
+        CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup,
+                     macroExpanders)
+        CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup,
+                     macroExpanders)
       }
     }
   }
 
-  std::string binaryDir = preset.BinaryDir;
-  switch (ExpandMacros(file, *out, envCycles, binaryDir)) {
-    case ExpandMacroResult::Error:
-      return false;
-    case ExpandMacroResult::Ignore:
-      out.reset();
-      return true;
-    case ExpandMacroResult::Ok:
-      break;
+  if (out->Execution) {
+    CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders)
   }
-  if (!cmSystemTools::FileIsFullPath(binaryDir)) {
-    binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
+
+  return true;
+}
+
+template <class T>
+bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset,
+                  cm::optional<T>& out)
+{
+  out.emplace(preset);
+
+  std::map<std::string, CycleStatus> envCycles;
+  for (auto const& v : out->Environment) {
+    envCycles[v.first] = CycleStatus::Unvisited;
   }
-  out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
-  cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
 
-  for (auto& variable : out->CacheVariables) {
-    if (variable.second) {
-      switch (ExpandMacros(file, *out, envCycles, variable.second->Value)) {
+  std::vector<MacroExpander> macroExpanders;
+
+  MacroExpander defaultMacroExpander =
+    [&file, &preset](const std::string& macroNamespace,
+                     const std::string& macroName,
+                     std::string& macroOut) -> ExpandMacroResult {
+    if (macroNamespace.empty()) {
+      if (macroName == "sourceDir") {
+        macroOut += file.SourceDir;
+        return ExpandMacroResult::Ok;
+      }
+      if (macroName == "sourceParentDir") {
+        macroOut += cmSystemTools::GetParentDirectory(file.SourceDir);
+        return ExpandMacroResult::Ok;
+      }
+      if (macroName == "sourceDirName") {
+        macroOut += cmSystemTools::GetFilenameName(file.SourceDir);
+        return ExpandMacroResult::Ok;
+      }
+      if (macroName == "presetName") {
+        macroOut += preset.Name;
+        return ExpandMacroResult::Ok;
+      }
+      if (macroName == "generator") {
+        // Generator only makes sense if preset is not hidden.
+        if (!preset.Hidden) {
+          macroOut += file.GetGeneratorForPreset(preset.Name);
+        }
+        return ExpandMacroResult::Ok;
+      }
+      if (macroName == "dollar") {
+        macroOut += '$';
+        return ExpandMacroResult::Ok;
+      }
+    }
+
+    return ExpandMacroResult::Ignore;
+  };
+
+  MacroExpander environmentMacroExpander =
+    [&macroExpanders, &out, &envCycles](
+      const std::string& macroNamespace, const std::string& macroName,
+      std::string& result) -> ExpandMacroResult {
+    if (macroNamespace == "env" && !macroName.empty() && out) {
+      auto v = out->Environment.find(macroName);
+      if (v != out->Environment.end() && v->second) {
+        auto e = VisitEnv(*v->second, envCycles[macroName], macroExpanders);
+        if (e != ExpandMacroResult::Ok) {
+          return e;
+        }
+        result += *v->second;
+        return ExpandMacroResult::Ok;
+      }
+    }
+
+    if (macroNamespace == "env" || macroNamespace == "penv") {
+      if (macroName.empty()) {
+        return ExpandMacroResult::Error;
+      }
+      const char* value = std::getenv(macroName.c_str());
+      if (value) {
+        result += value;
+      }
+      return ExpandMacroResult::Ok;
+    }
+
+    return ExpandMacroResult::Ignore;
+  };
+
+  macroExpanders.push_back(defaultMacroExpander);
+  macroExpanders.push_back(environmentMacroExpander);
+
+  for (auto& v : out->Environment) {
+    if (v.second) {
+      switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders)) {
         case ExpandMacroResult::Error:
           return false;
         case ExpandMacroResult::Ignore:
@@ -556,13 +1037,11 @@ bool ExpandMacros(const cmCMakePresetsFile& file,
     }
   }
 
-  return true;
+  return ExpandMacros(file, preset, out, macroExpanders);
 }
 
-ExpandMacroResult VisitEnv(const cmCMakePresetsFile& file,
-                           cmCMakePresetsFile::ExpandedPreset& preset,
-                           std::map<std::string, CycleStatus>& envCycles,
-                           std::string& value, CycleStatus& status)
+ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
+                           const std::vector<MacroExpander>& macroExpanders)
 {
   if (status == CycleStatus::Verified) {
     return ExpandMacroResult::Ok;
@@ -572,7 +1051,7 @@ ExpandMacroResult VisitEnv(const cmCMakePresetsFile& file,
   }
 
   status = CycleStatus::InProgress;
-  auto e = ExpandMacros(file, preset, envCycles, value);
+  auto e = ExpandMacros(value, macroExpanders);
   if (e != ExpandMacroResult::Ok) {
     return e;
   }
@@ -580,10 +1059,8 @@ ExpandMacroResult VisitEnv(const cmCMakePresetsFile& file,
   return ExpandMacroResult::Ok;
 }
 
-ExpandMacroResult ExpandMacros(const cmCMakePresetsFile& file,
-                               cmCMakePresetsFile::ExpandedPreset& preset,
-                               std::map<std::string, CycleStatus>& envCycles,
-                               std::string& out)
+ExpandMacroResult ExpandMacros(
+  std::string& out, const std::vector<MacroExpander>& macroExpanders)
 {
   std::string result;
   std::string macroNamespace;
@@ -630,8 +1107,8 @@ ExpandMacroResult ExpandMacros(const cmCMakePresetsFile& file,
 
       case State::MacroName:
         if (c == '}') {
-          auto e = ExpandMacro(file, preset, envCycles, result, macroNamespace,
-                               macroName);
+          auto e =
+            ExpandMacro(result, macroNamespace, macroName, macroExpanders);
           if (e != ExpandMacroResult::Ok) {
             return e;
           }
@@ -660,70 +1137,232 @@ ExpandMacroResult ExpandMacros(const cmCMakePresetsFile& file,
   return ExpandMacroResult::Ok;
 }
 
-ExpandMacroResult ExpandMacro(const cmCMakePresetsFile& file,
-                              cmCMakePresetsFile::ExpandedPreset& preset,
-                              std::map<std::string, CycleStatus>& envCycles,
-                              std::string& out,
+ExpandMacroResult ExpandMacro(std::string& out,
                               const std::string& macroNamespace,
-                              const std::string& macroName)
+                              const std::string& macroName,
+                              const std::vector<MacroExpander>& macroExpanders)
 {
-  if (macroNamespace.empty()) {
-    if (macroName == "sourceDir") {
-      out += file.SourceDir;
-      return ExpandMacroResult::Ok;
+  for (auto const& macroExpander : macroExpanders) {
+    auto result = macroExpander(macroNamespace, macroName, out);
+    if (result != ExpandMacroResult::Ignore) {
+      return result;
     }
-    if (macroName == "sourceParentDir") {
-      out += cmSystemTools::GetParentDirectory(file.SourceDir);
-      return ExpandMacroResult::Ok;
+  }
+
+  if (macroNamespace == "vendor") {
+    return ExpandMacroResult::Ignore;
+  }
+
+  return ExpandMacroResult::Error;
+}
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit(
+  const cmCMakePresetsFile::Preset& parentPreset)
+{
+  auto& preset = *this;
+  const ConfigurePreset& parent =
+    static_cast<const ConfigurePreset&>(parentPreset);
+  InheritString(preset.Generator, parent.Generator);
+  InheritString(preset.Architecture, parent.Architecture);
+  InheritString(preset.Toolset, parent.Toolset);
+  if (!preset.ArchitectureStrategy) {
+    preset.ArchitectureStrategy = parent.ArchitectureStrategy;
+  }
+  if (!preset.ToolsetStrategy) {
+    preset.ToolsetStrategy = parent.ToolsetStrategy;
+  }
+  InheritString(preset.BinaryDir, parent.BinaryDir);
+  InheritOptionalValue(preset.WarnDev, parent.WarnDev);
+  InheritOptionalValue(preset.ErrorDev, parent.ErrorDev);
+  InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated);
+  InheritOptionalValue(preset.ErrorDeprecated, parent.ErrorDeprecated);
+  InheritOptionalValue(preset.WarnUninitialized, parent.WarnUninitialized);
+  InheritOptionalValue(preset.WarnUnusedCli, parent.WarnUnusedCli);
+  InheritOptionalValue(preset.WarnSystemVars, parent.WarnSystemVars);
+
+  for (auto const& v : parent.CacheVariables) {
+    preset.CacheVariables.insert(v);
+  }
+
+  return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit()
+{
+  auto& preset = *this;
+  if (preset.Environment.count("") != 0) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit()
+{
+  auto& preset = *this;
+  if (!preset.Hidden) {
+    if (preset.Generator.empty()) {
+      return ReadFileResult::INVALID_PRESET;
     }
-    if (macroName == "sourceDirName") {
-      out += cmSystemTools::GetFilenameName(file.SourceDir);
-      return ExpandMacroResult::Ok;
+    if (preset.BinaryDir.empty()) {
+      return ReadFileResult::INVALID_PRESET;
     }
-    if (macroName == "presetName") {
-      out += preset.Name;
-      return ExpandMacroResult::Ok;
+    if (preset.WarnDev == false && preset.ErrorDev == true) {
+      return ReadFileResult::INVALID_PRESET;
     }
-    if (macroName == "generator") {
-      out += preset.Generator;
-      return ExpandMacroResult::Ok;
+    if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) {
+      return ReadFileResult::INVALID_PRESET;
     }
-    if (macroName == "dollar") {
-      out += '$';
-      return ExpandMacroResult::Ok;
+    if (preset.CacheVariables.count("") != 0) {
+      return ReadFileResult::INVALID_PRESET;
     }
   }
 
-  if (macroNamespace == "env" && !macroName.empty()) {
-    auto v = preset.Environment.find(macroName);
-    if (v != preset.Environment.end() && v->second) {
-      auto e =
-        VisitEnv(file, preset, envCycles, *v->second, envCycles[macroName]);
-      if (e != ExpandMacroResult::Ok) {
-        return e;
-      }
-      out += *v->second;
-      return ExpandMacroResult::Ok;
+  return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::BuildPreset::VisitPresetInherit(
+  const cmCMakePresetsFile::Preset& parentPreset)
+{
+  auto& preset = *this;
+  const BuildPreset& parent = static_cast<const BuildPreset&>(parentPreset);
+
+  InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
+  InheritOptionalValue(preset.InheritConfigureEnvironment,
+                       parent.InheritConfigureEnvironment);
+  InheritOptionalValue(preset.Jobs, parent.Jobs);
+  InheritVector(preset.Targets, parent.Targets);
+  InheritString(preset.Configuration, parent.Configuration);
+  InheritOptionalValue(preset.CleanFirst, parent.CleanFirst);
+  InheritOptionalValue(preset.Verbose, parent.Verbose);
+  InheritVector(preset.NativeToolOptions, parent.NativeToolOptions);
+
+  return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit()
+{
+  auto& preset = *this;
+  if (!preset.Hidden && preset.ConfigurePreset.empty()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+  return ReadFileResult::READ_OK;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::TestPreset::VisitPresetInherit(
+  const cmCMakePresetsFile::Preset& parentPreset)
+{
+  auto& preset = *this;
+  const TestPreset& parent = static_cast<const TestPreset&>(parentPreset);
+
+  InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
+  InheritOptionalValue(preset.InheritConfigureEnvironment,
+                       parent.InheritConfigureEnvironment);
+  InheritString(preset.Configuration, parent.Configuration);
+  InheritVector(preset.OverwriteConfigurationFile,
+                parent.OverwriteConfigurationFile);
+
+  if (parent.Output) {
+    if (preset.Output) {
+      auto& output = preset.Output.value();
+      const auto& parentOutput = parent.Output.value();
+      InheritOptionalValue(output.ShortProgress, parentOutput.ShortProgress);
+      InheritOptionalValue(output.Verbosity, parentOutput.Verbosity);
+      InheritOptionalValue(output.Debug, parentOutput.Debug);
+      InheritOptionalValue(output.OutputOnFailure,
+                           parentOutput.OutputOnFailure);
+      InheritOptionalValue(output.Quiet, parentOutput.Quiet);
+      InheritString(output.OutputLogFile, parentOutput.OutputLogFile);
+      InheritOptionalValue(output.LabelSummary, parentOutput.LabelSummary);
+      InheritOptionalValue(output.SubprojectSummary,
+                           parentOutput.SubprojectSummary);
+      InheritOptionalValue(output.MaxPassedTestOutputSize,
+                           parentOutput.MaxPassedTestOutputSize);
+      InheritOptionalValue(output.MaxFailedTestOutputSize,
+                           parentOutput.MaxFailedTestOutputSize);
+      InheritOptionalValue(output.MaxTestNameWidth,
+                           parentOutput.MaxTestNameWidth);
+    } else {
+      preset.Output = parent.Output;
     }
   }
 
-  if (macroNamespace == "env" || macroNamespace == "penv") {
-    if (macroName.empty()) {
-      return ExpandMacroResult::Error;
+  if (parent.Filter) {
+    if (parent.Filter->Include) {
+      if (preset.Filter && preset.Filter->Include) {
+        auto& include = *preset.Filter->Include;
+        const auto& parentInclude = *parent.Filter->Include;
+        InheritString(include.Name, parentInclude.Name);
+        InheritString(include.Label, parentInclude.Label);
+        InheritOptionalValue(include.Index, parentInclude.Index);
+      } else {
+        if (!preset.Filter) {
+          preset.Filter.emplace();
+        }
+        preset.Filter->Include = parent.Filter->Include;
+      }
     }
-    const char* value = std::getenv(macroName.c_str());
-    if (value) {
-      out += value;
+
+    if (parent.Filter->Exclude) {
+      if (preset.Filter && preset.Filter->Exclude) {
+        auto& exclude = *preset.Filter->Exclude;
+        const auto& parentExclude = *parent.Filter->Exclude;
+        InheritString(exclude.Name, parentExclude.Name);
+        InheritString(exclude.Label, parentExclude.Label);
+        InheritOptionalValue(exclude.Fixtures, parentExclude.Fixtures);
+      } else {
+        if (!preset.Filter) {
+          preset.Filter.emplace();
+        }
+        preset.Filter->Exclude = parent.Filter->Exclude;
+      }
     }
-    return ExpandMacroResult::Ok;
   }
 
-  if (macroNamespace == "vendor") {
-    return ExpandMacroResult::Ignore;
+  if (parent.Execution) {
+    if (preset.Execution) {
+      auto& execution = *preset.Execution;
+      const auto& parentExecution = *parent.Execution;
+      InheritOptionalValue(execution.StopOnFailure,
+                           parentExecution.StopOnFailure);
+      InheritOptionalValue(execution.EnableFailover,
+                           parentExecution.EnableFailover);
+      InheritOptionalValue(execution.Jobs, parentExecution.Jobs);
+      InheritString(execution.ResourceSpecFile,
+                    parentExecution.ResourceSpecFile);
+      InheritOptionalValue(execution.TestLoad, parentExecution.TestLoad);
+      InheritOptionalValue(execution.ShowOnly, parentExecution.ShowOnly);
+      InheritOptionalValue(execution.Repeat, parentExecution.Repeat);
+      InheritOptionalValue(execution.InteractiveDebugging,
+                           parentExecution.InteractiveDebugging);
+      InheritOptionalValue(execution.ScheduleRandom,
+                           parentExecution.ScheduleRandom);
+      InheritOptionalValue(execution.Timeout, parentExecution.Timeout);
+      InheritOptionalValue(execution.NoTestsAction,
+                           parentExecution.NoTestsAction);
+    } else {
+      preset.Execution = parent.Execution;
+    }
   }
 
-  return ExpandMacroResult::Error;
+  return ReadFileResult::READ_OK;
 }
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit()
+{
+  auto& preset = *this;
+  if (!preset.Hidden && preset.ConfigurePreset.empty()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+  return ReadFileResult::READ_OK;
 }
 
 std::string cmCMakePresetsFile::GetFilename(const std::string& sourceDir)
@@ -739,17 +1378,25 @@ std::string cmCMakePresetsFile::GetUserFilename(const std::string& sourceDir)
 cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets(
   const std::string& sourceDir, bool allowNoFiles)
 {
-  bool haveOneFile = false;
   this->SourceDir = sourceDir;
-  this->Presets.clear();
-  this->PresetOrder.clear();
+  this->ClearPresets();
 
-  std::vector<std::string> presetOrder;
-  std::map<std::string, PresetPair> presetMap;
+  auto result = this->ReadProjectPresetsInternal(allowNoFiles);
+  if (result != ReadFileResult::READ_OK) {
+    this->ClearPresets();
+  }
+
+  return result;
+}
+
+cmCMakePresetsFile::ReadFileResult
+cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles)
+{
+  bool haveOneFile = false;
 
   std::string filename = GetUserFilename(this->SourceDir);
   if (cmSystemTools::FileExists(filename)) {
-    auto result = this->ReadJSONFile(filename, presetOrder, presetMap, true);
+    auto result = this->ReadJSONFile(filename, true);
     if (result != ReadFileResult::READ_OK) {
       return result;
     }
@@ -758,7 +1405,7 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets(
 
   filename = GetFilename(this->SourceDir);
   if (cmSystemTools::FileExists(filename)) {
-    auto result = this->ReadJSONFile(filename, presetOrder, presetMap, false);
+    auto result = this->ReadJSONFile(filename, false);
     if (result != ReadFileResult::READ_OK) {
       return result;
     }
@@ -770,19 +1417,56 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets(
                         : ReadFileResult::FILE_NOT_FOUND;
   }
 
-  auto result = ComputePresetInheritance(presetMap);
-  if (result != ReadFileResult::READ_OK) {
-    return result;
+  CHECK_OK(ComputePresetInheritance(this->ConfigurePresets))
+  CHECK_OK(ComputePresetInheritance(this->BuildPresets))
+  CHECK_OK(ComputePresetInheritance(this->TestPresets))
+
+  for (auto& it : this->ConfigurePresets) {
+    if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
+      return ReadFileResult::INVALID_MACRO_EXPANSION;
+    }
   }
 
-  for (auto& it : presetMap) {
+  for (auto& it : this->BuildPresets) {
+    if (!it.second.Unexpanded.Hidden) {
+      const auto configurePreset =
+        this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
+      if (configurePreset == this->ConfigurePresets.end()) {
+        return ReadFileResult::INVALID_CONFIGURE_PRESET;
+      }
+
+      if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
+        it.second.Unexpanded.Environment.insert(
+          configurePreset->second.Unexpanded.Environment.begin(),
+          configurePreset->second.Unexpanded.Environment.end());
+      }
+    }
+
+    if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
+      return ReadFileResult::INVALID_MACRO_EXPANSION;
+    }
+  }
+
+  for (auto& it : this->TestPresets) {
+    if (!it.second.Unexpanded.Hidden) {
+      const auto configurePreset =
+        this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
+      if (configurePreset == this->ConfigurePresets.end()) {
+        return ReadFileResult::INVALID_CONFIGURE_PRESET;
+      }
+
+      if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
+        it.second.Unexpanded.Environment.insert(
+          configurePreset->second.Unexpanded.Environment.begin(),
+          configurePreset->second.Unexpanded.Environment.end());
+      }
+    }
+
     if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
       return ReadFileResult::INVALID_MACRO_EXPANSION;
     }
   }
 
-  this->PresetOrder = std::move(presetOrder);
-  this->Presets = std::move(presetMap);
   return ReadFileResult::READ_OK;
 }
 
@@ -821,14 +1505,18 @@ const char* cmCMakePresetsFile::ResultToString(ReadFileResult result)
       return "Project preset inherits from user preset";
     case ReadFileResult::INVALID_MACRO_EXPANSION:
       return "Invalid macro expansion";
+    case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
+      return "File version must be 2 or higher for build and test preset "
+             "support.";
+    case ReadFileResult::INVALID_CONFIGURE_PRESET:
+      return "Invalid \"configurePreset\" field";
   }
 
   return "Unknown error";
 }
 
 cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
-  const std::string& filename, std::vector<std::string>& presetOrder,
-  std::map<std::string, PresetPair>& presetMap, bool user)
+  const std::string& filename, bool user)
 {
   cmsys::ifstream fin(filename.c_str());
   if (!fin) {
@@ -853,6 +1541,12 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
     return ReadFileResult::UNRECOGNIZED_VERSION;
   }
 
+  // Support for build and test presets added in version 2.
+  if (v < 2 &&
+      (root.isMember("buildPresets") || root.isMember("testPresets"))) {
+    return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
+  }
+
   RootPresets presets;
   if ((result = RootPresetsHelper(presets, &root)) !=
       ReadFileResult::READ_OK) {
@@ -871,16 +1565,158 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
     return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
   }
 
-  for (auto& preset : presets.Presets) {
+  for (auto& preset : presets.ConfigurePresets) {
     preset.User = user;
     if (preset.Name.empty()) {
       return ReadFileResult::INVALID_PRESET;
     }
-    if (!presetMap.insert({ preset.Name, { preset, cm::nullopt } }).second) {
+
+    PresetPair<ConfigurePreset> presetPair;
+    presetPair.Unexpanded = preset;
+    presetPair.Expanded = cm::nullopt;
+    if (!this->ConfigurePresets
+           .emplace(std::make_pair(preset.Name, presetPair))
+           .second) {
       return ReadFileResult::DUPLICATE_PRESETS;
     }
-    presetOrder.push_back(preset.Name);
+    this->ConfigurePresetOrder.push_back(preset.Name);
+  }
+
+  for (auto& preset : presets.BuildPresets) {
+    preset.User = user;
+    if (preset.Name.empty()) {
+      return ReadFileResult::INVALID_PRESET;
+    }
+
+    PresetPair<BuildPreset> presetPair;
+    presetPair.Unexpanded = preset;
+    presetPair.Expanded = cm::nullopt;
+    if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
+      return ReadFileResult::DUPLICATE_PRESETS;
+    }
+    this->BuildPresetOrder.push_back(preset.Name);
+  }
+
+  for (auto& preset : presets.TestPresets) {
+    preset.User = user;
+    if (preset.Name.empty()) {
+      return ReadFileResult::INVALID_PRESET;
+    }
+
+    PresetPair<TestPreset> presetPair;
+    presetPair.Unexpanded = preset;
+    presetPair.Expanded = cm::nullopt;
+    if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
+      return ReadFileResult::DUPLICATE_PRESETS;
+    }
+    this->TestPresetOrder.push_back(preset.Name);
   }
 
   return ReadFileResult::READ_OK;
 }
+
+void cmCMakePresetsFile::ClearPresets()
+{
+  this->ConfigurePresets.clear();
+  this->BuildPresets.clear();
+  this->TestPresets.clear();
+
+  this->ConfigurePresetOrder.clear();
+  this->BuildPresetOrder.clear();
+  this->TestPresetOrder.clear();
+}
+
+void cmCMakePresetsFile::PrintPresets(
+  const std::vector<const cmCMakePresetsFile::Preset*>& presets)
+{
+  if (presets.empty()) {
+    return;
+  }
+
+  auto longestPresetName =
+    std::max_element(presets.begin(), presets.end(),
+                     [](const cmCMakePresetsFile::Preset* a,
+                        const cmCMakePresetsFile::Preset* b) {
+                       return a->Name.length() < b->Name.length();
+                     });
+  auto longestLength = (*longestPresetName)->Name.length();
+
+  for (const auto* preset : presets) {
+    std::cout << "  \"" << preset->Name << '"';
+    const auto& description = preset->DisplayName;
+    if (!description.empty()) {
+      for (std::size_t i = 0; i < longestLength - preset->Name.length(); ++i) {
+        std::cout << ' ';
+      }
+      std::cout << " - " << description;
+    }
+    std::cout << '\n';
+  }
+}
+
+void cmCMakePresetsFile::PrintConfigurePresetList() const
+{
+  PrintConfigurePresetList([](const ConfigurePreset&) { return true; });
+}
+
+void cmCMakePresetsFile::PrintConfigurePresetList(
+  const std::function<bool(const ConfigurePreset&)>& filter) const
+{
+  std::vector<const cmCMakePresetsFile::Preset*> presets;
+  for (auto const& p : this->ConfigurePresetOrder) {
+    auto const& preset = this->ConfigurePresets.at(p);
+    if (!preset.Unexpanded.Hidden && preset.Expanded &&
+        filter(preset.Unexpanded)) {
+      presets.push_back(
+        static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
+    }
+  }
+
+  if (!presets.empty()) {
+    std::cout << "Available configure presets:\n\n";
+    cmCMakePresetsFile::PrintPresets(presets);
+  }
+}
+
+void cmCMakePresetsFile::PrintBuildPresetList() const
+{
+  std::vector<const cmCMakePresetsFile::Preset*> presets;
+  for (auto const& p : this->BuildPresetOrder) {
+    auto const& preset = this->BuildPresets.at(p);
+    if (!preset.Unexpanded.Hidden && preset.Expanded) {
+      presets.push_back(
+        static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
+    }
+  }
+
+  if (!presets.empty()) {
+    std::cout << "Available build presets:\n\n";
+    cmCMakePresetsFile::PrintPresets(presets);
+  }
+}
+
+void cmCMakePresetsFile::PrintTestPresetList() const
+{
+  std::vector<const cmCMakePresetsFile::Preset*> presets;
+  for (auto const& p : this->TestPresetOrder) {
+    auto const& preset = this->TestPresets.at(p);
+    if (!preset.Unexpanded.Hidden && preset.Expanded) {
+      presets.push_back(
+        static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
+    }
+  }
+
+  if (!presets.empty()) {
+    std::cout << "Available test presets:\n\n";
+    cmCMakePresetsFile::PrintPresets(presets);
+  }
+}
+
+void cmCMakePresetsFile::PrintAllPresets() const
+{
+  this->PrintConfigurePresetList();
+  std::cout << std::endl;
+  this->PrintBuildPresetList();
+  std::cout << std::endl;
+  this->PrintTestPresetList();
+}
index f6b159a..3067d5e 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #pragma once
 
+#include <functional>
 #include <map>
 #include <string>
 #include <utility>
 class cmCMakePresetsFile
 {
 public:
+  enum class ReadFileResult
+  {
+    READ_OK,
+    FILE_NOT_FOUND,
+    JSON_PARSE_ERROR,
+    INVALID_ROOT,
+    NO_VERSION,
+    INVALID_VERSION,
+    UNRECOGNIZED_VERSION,
+    INVALID_CMAKE_VERSION,
+    UNRECOGNIZED_CMAKE_VERSION,
+    INVALID_PRESETS,
+    INVALID_PRESET,
+    INVALID_VARIABLE,
+    DUPLICATE_PRESETS,
+    CYCLIC_PRESET_INHERITANCE,
+    USER_PRESET_INHERITANCE,
+    INVALID_MACRO_EXPANSION,
+    BUILD_TEST_PRESETS_UNSUPPORTED,
+    INVALID_CONFIGURE_PRESET,
+  };
+
   enum class ArchToolsetStrategy
   {
     Set,
@@ -29,25 +52,51 @@ public:
   {
   public:
 #if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
-    Preset() = default;
-    Preset(const Preset& /*other*/) = default;
-    Preset(Preset&& /*other*/) = default;
-
-    Preset& operator=(const Preset& /*other*/) = default;
-
     // The move assignment operators for several STL classes did not become
     // noexcept until C++17, which causes some tools to warn about this move
     // assignment operator throwing an exception when it shouldn't. Disable the
     // move assignment operator until C++17 is enabled.
-    Preset& operator=(Preset&& /*other*/) = delete;
+    // Explicitly defining a copy assignment operator prevents the compiler
+    // from automatically generating a move assignment operator.
+    Preset& operator=(const Preset& /*other*/) = default;
 #endif
 
+    virtual ~Preset() = default;
+
     std::string Name;
     std::vector<std::string> Inherits;
     bool Hidden;
     bool User;
     std::string DisplayName;
     std::string Description;
+
+    std::map<std::string, cm::optional<std::string>> Environment;
+
+    virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0;
+    virtual ReadFileResult VisitPresetBeforeInherit()
+    {
+      return ReadFileResult::READ_OK;
+    }
+
+    virtual ReadFileResult VisitPresetAfterInherit()
+    {
+      return ReadFileResult::READ_OK;
+    }
+  };
+
+  class ConfigurePreset : public Preset
+  {
+  public:
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+    // The move assignment operators for several STL classes did not become
+    // noexcept until C++17, which causes some tools to warn about this move
+    // assignment operator throwing an exception when it shouldn't. Disable the
+    // move assignment operator until C++17 is enabled.
+    // Explicitly defining a copy assignment operator prevents the compiler
+    // from automatically generating a move assignment operator.
+    ConfigurePreset& operator=(const ConfigurePreset& /*other*/) = default;
+#endif
+
     std::string Generator;
     std::string Architecture;
     cm::optional<ArchToolsetStrategy> ArchitectureStrategy;
@@ -56,7 +105,6 @@ public:
     std::string BinaryDir;
 
     std::map<std::string, cm::optional<CacheVariable>> CacheVariables;
-    std::map<std::string, cm::optional<std::string>> Environment;
 
     cm::optional<bool> WarnDev;
     cm::optional<bool> ErrorDev;
@@ -69,70 +117,182 @@ public:
     cm::optional<bool> DebugOutput;
     cm::optional<bool> DebugTryCompile;
     cm::optional<bool> DebugFind;
+
+    ReadFileResult VisitPresetInherit(const Preset& parent) override;
+    ReadFileResult VisitPresetBeforeInherit() override;
+    ReadFileResult VisitPresetAfterInherit() override;
   };
 
-  class UnexpandedPreset : public Preset
+  class BuildPreset : public Preset
   {
   public:
-    using Preset::Preset;
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+    // The move assignment operators for several STL classes did not become
+    // noexcept until C++17, which causes some tools to warn about this move
+    // assignment operator throwing an exception when it shouldn't. Disable the
+    // move assignment operator until C++17 is enabled.
+    // Explicitly defining a copy assignment operator prevents the compiler
+    // from automatically generating a move assignment operator.
+    BuildPreset& operator=(const BuildPreset& /*other*/) = default;
+#endif
 
-    UnexpandedPreset() = default;
-    UnexpandedPreset(const Preset& preset)
-      : Preset(preset)
-    {
-    }
-    UnexpandedPreset(Preset&& preset)
-      : Preset(std::move(preset))
-    {
-    }
+    std::string ConfigurePreset;
+    cm::optional<bool> InheritConfigureEnvironment;
+    cm::optional<int> Jobs;
+    std::vector<std::string> Targets;
+    std::string Configuration;
+    cm::optional<bool> CleanFirst;
+    cm::optional<bool> Verbose;
+    std::vector<std::string> NativeToolOptions;
+
+    ReadFileResult VisitPresetInherit(const Preset& parent) override;
+    ReadFileResult VisitPresetAfterInherit() override;
   };
 
-  class ExpandedPreset : public Preset
+  class TestPreset : public Preset
   {
   public:
-    using Preset::Preset;
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+    // The move assignment operators for several STL classes did not become
+    // noexcept until C++17, which causes some tools to warn about this move
+    // assignment operator throwing an exception when it shouldn't. Disable the
+    // move assignment operator until C++17 is enabled.
+    // Explicitly defining a copy assignment operator prevents the compiler
+    // from automatically generating a move assignment operator.
+    TestPreset& operator=(const TestPreset& /*other*/) = default;
+#endif
 
-    ExpandedPreset() = default;
-    ExpandedPreset(const Preset& preset)
-      : Preset(preset)
+    struct OutputOptions
     {
-    }
-    ExpandedPreset(Preset&& preset)
-      : Preset(std::move(preset))
+      enum class VerbosityEnum
+      {
+        Default,
+        Verbose,
+        Extra
+      };
+
+      cm::optional<bool> ShortProgress;
+      cm::optional<VerbosityEnum> Verbosity;
+      cm::optional<bool> Debug;
+      cm::optional<bool> OutputOnFailure;
+      cm::optional<bool> Quiet;
+      std::string OutputLogFile;
+      cm::optional<bool> LabelSummary;
+      cm::optional<bool> SubprojectSummary;
+      cm::optional<int> MaxPassedTestOutputSize;
+      cm::optional<int> MaxFailedTestOutputSize;
+      cm::optional<int> MaxTestNameWidth;
+    };
+
+    struct IncludeOptions
     {
-    }
+      struct IndexOptions
+      {
+        cm::optional<int> Start;
+        cm::optional<int> End;
+        cm::optional<int> Stride;
+        std::vector<int> SpecificTests;
+
+        std::string IndexFile;
+      };
+
+      std::string Name;
+      std::string Label;
+      cm::optional<IndexOptions> Index;
+      cm::optional<bool> UseUnion;
+    };
+
+    struct ExcludeOptions
+    {
+      struct FixturesOptions
+      {
+        std::string Any;
+        std::string Setup;
+        std::string Cleanup;
+      };
+
+      std::string Name;
+      std::string Label;
+      cm::optional<FixturesOptions> Fixtures;
+    };
+
+    struct FilterOptions
+    {
+      cm::optional<IncludeOptions> Include;
+      cm::optional<ExcludeOptions> Exclude;
+    };
+
+    struct ExecutionOptions
+    {
+      enum class ShowOnlyEnum
+      {
+        Human,
+        JsonV1
+      };
+
+      struct RepeatOptions
+      {
+        enum class ModeEnum
+        {
+          UntilFail,
+          UntilPass,
+          AfterTimeout
+        };
+
+        ModeEnum Mode;
+        int Count;
+      };
+
+      enum class NoTestsActionEnum
+      {
+        Default,
+        Error,
+        Ignore
+      };
+
+      cm::optional<bool> StopOnFailure;
+      cm::optional<bool> EnableFailover;
+      cm::optional<int> Jobs;
+      std::string ResourceSpecFile;
+      cm::optional<int> TestLoad;
+      cm::optional<ShowOnlyEnum> ShowOnly;
+
+      cm::optional<RepeatOptions> Repeat;
+      cm::optional<bool> InteractiveDebugging;
+      cm::optional<bool> ScheduleRandom;
+      cm::optional<int> Timeout;
+      cm::optional<NoTestsActionEnum> NoTestsAction;
+    };
+
+    std::string ConfigurePreset;
+    cm::optional<bool> InheritConfigureEnvironment;
+    std::string Configuration;
+    std::vector<std::string> OverwriteConfigurationFile;
+    cm::optional<OutputOptions> Output;
+    cm::optional<FilterOptions> Filter;
+    cm::optional<ExecutionOptions> Execution;
+
+    ReadFileResult VisitPresetInherit(const Preset& parent) override;
+    ReadFileResult VisitPresetAfterInherit() override;
   };
 
+  template <class T>
   class PresetPair
   {
   public:
-    UnexpandedPreset Unexpanded;
-    cm::optional<ExpandedPreset> Expanded;
+    T Unexpanded;
+    cm::optional<T> Expanded;
   };
 
-  std::string SourceDir;
-  std::map<std::string, PresetPairPresets;
-  std::vector<std::string> PresetOrder;
+  std::map<std::string, PresetPair<ConfigurePreset>> ConfigurePresets;
+  std::map<std::string, PresetPair<BuildPreset>> BuildPresets;
+  std::map<std::string, PresetPair<TestPreset>> TestPresets;
 
-  enum class ReadFileResult
-  {
-    READ_OK,
-    FILE_NOT_FOUND,
-    JSON_PARSE_ERROR,
-    INVALID_ROOT,
-    NO_VERSION,
-    INVALID_VERSION,
-    UNRECOGNIZED_VERSION,
-    INVALID_CMAKE_VERSION,
-    UNRECOGNIZED_CMAKE_VERSION,
-    INVALID_PRESETS,
-    INVALID_PRESET,
-    INVALID_VARIABLE,
-    DUPLICATE_PRESETS,
-    CYCLIC_PRESET_INHERITANCE,
-    USER_PRESET_INHERITANCE,
-    INVALID_MACRO_EXPANSION,
-  };
+  std::vector<std::string> ConfigurePresetOrder;
+  std::vector<std::string> BuildPresetOrder;
+  std::vector<std::string> TestPresetOrder;
+
+  std::string SourceDir;
 
   static std::string GetFilename(const std::string& sourceDir);
   static std::string GetUserFilename(const std::string& sourceDir);
@@ -140,9 +300,44 @@ public:
                                     bool allowNoFiles = false);
   static const char* ResultToString(ReadFileResult result);
 
+  std::string GetGeneratorForPreset(const std::string& presetName) const
+  {
+    auto configurePresetName = presetName;
+
+    auto buildPresetIterator = this->BuildPresets.find(presetName);
+    if (buildPresetIterator != this->BuildPresets.end()) {
+      configurePresetName =
+        buildPresetIterator->second.Unexpanded.ConfigurePreset;
+    } else {
+      auto testPresetIterator = this->TestPresets.find(presetName);
+      if (testPresetIterator != this->TestPresets.end()) {
+        configurePresetName =
+          testPresetIterator->second.Unexpanded.ConfigurePreset;
+      }
+    }
+
+    auto configurePresetIterator =
+      this->ConfigurePresets.find(configurePresetName);
+    if (configurePresetIterator != this->ConfigurePresets.end()) {
+      return configurePresetIterator->second.Unexpanded.Generator;
+    }
+
+    // This should only happen if the preset is hidden
+    // or (for build or test presets) if ConfigurePreset is invalid.
+    return "";
+  }
+
+  static void PrintPresets(
+    const std::vector<const cmCMakePresetsFile::Preset*>& presets);
+  void PrintConfigurePresetList() const;
+  void PrintConfigurePresetList(
+    const std::function<bool(const ConfigurePreset&)>& filter) const;
+  void PrintBuildPresetList() const;
+  void PrintTestPresetList() const;
+  void PrintAllPresets() const;
+
 private:
-  ReadFileResult ReadJSONFile(const std::string& filename,
-                              std::vector<std::string>& presetOrder,
-                              std::map<std::string, PresetPair>& presetMap,
-                              bool user);
+  ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles);
+  ReadFileResult ReadJSONFile(const std::string& filename, bool user);
+  void ClearPresets();
 };
index 8ebf6d2..438a077 100644 (file)
@@ -221,8 +221,9 @@ void CCONV cmAddUtilityCommand(void* arg, const char* utilityName,
 
   // Pass the call to the makefile instance.
   std::vector<std::string> no_byproducts;
-  mf->AddUtilityCommand(utilityName, (all ? false : true), nullptr,
-                        no_byproducts, depends2, commandLines);
+  mf->AddUtilityCommand(utilityName, !all, nullptr, no_byproducts, depends2,
+                        commandLines,
+                        mf->GetPolicyStatus(cmPolicies::CMP0116));
 }
 
 void CCONV cmAddCustomCommand(void* arg, const char* source,
@@ -263,7 +264,8 @@ void CCONV cmAddCustomCommand(void* arg, const char* source,
   // Pass the call to the makefile instance.
   const char* no_comment = nullptr;
   mf->AddCustomCommandOldStyle(target, outputs2, depends2, source,
-                               commandLines, no_comment);
+                               commandLines, no_comment,
+                               mf->GetPolicyStatus(cmPolicies::CMP0116));
 }
 
 void CCONV cmAddCustomCommandToOutput(void* arg, const char* output,
@@ -298,7 +300,8 @@ void CCONV cmAddCustomCommandToOutput(void* arg, const char* output,
   const char* no_comment = nullptr;
   const char* no_working_dir = nullptr;
   mf->AddCustomCommandToOutput(output, depends2, main_dependency, commandLines,
-                               no_comment, no_working_dir);
+                               no_comment, no_working_dir,
+                               mf->GetPolicyStatus(cmPolicies::CMP0116));
 }
 
 void CCONV cmAddCustomCommandToTarget(void* arg, const char* target,
@@ -340,7 +343,8 @@ void CCONV cmAddCustomCommandToTarget(void* arg, const char* target,
   const char* no_comment = nullptr;
   const char* no_working_dir = nullptr;
   mf->AddCustomCommandToTarget(target, no_byproducts, no_depends, commandLines,
-                               cctype, no_comment, no_working_dir);
+                               cctype, no_comment, no_working_dir,
+                               mf->GetPolicyStatus(cmPolicies::CMP0116));
 }
 
 static void addLinkLibrary(cmMakefile* mf, std::string const& target,
@@ -550,6 +554,11 @@ void* CCONV cmAddSource(void* arg, void* arg2)
   // Create the real cmSourceFile instance and copy over saved information.
   cmSourceFile* rsf = mf->GetOrCreateSource(osf->FullPath);
   rsf->SetProperties(osf->Properties);
+  // In case the properties contain the GENERATED property,
+  // mark the real cmSourceFile as generated.
+  if (rsf->GetIsGenerated()) {
+    rsf->MarkAsGenerated();
+  }
   for (std::string const& d : osf->Depends) {
     rsf->AddDepend(d);
   }
@@ -562,7 +571,7 @@ void* CCONV cmAddSource(void* arg, void* arg2)
   sf->SourceExtension = osf->SourceExtension;
 
   // Store the proxy in the map so it can be re-used and deleted later.
-  auto value = sf.get();
+  auto* value = sf.get();
   cmCPluginAPISourceFiles[rsf] = std::move(sf);
   return value;
 }
@@ -583,14 +592,12 @@ const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop)
 {
   cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg);
   if (cmSourceFile* rsf = sf->RealSourceFile) {
-    cmProp p = rsf->GetProperty(prop);
-    return cmToCStr(p);
+    return cmToCStr(rsf->GetProperty(prop));
   }
   if (!strcmp(prop, "LOCATION")) {
     return sf->FullPath.c_str();
   }
-  cmProp retVal = sf->Properties.GetPropertyValue(prop);
-  return cmToCStr(retVal);
+  return cmToCStr(sf->Properties.GetPropertyValue(prop));
 }
 
 int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop)
index 8cf5ae9..620ba19 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <cctype>
+#include <cerrno>
 #include <chrono>
 #include <cstdio>
 #include <cstdlib>
@@ -17,6 +18,7 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cm/optional>
 #include <cm/string_view>
 #include <cmext/algorithm>
 #include <cmext/string_view>
@@ -37,6 +39,7 @@
 #  include <unistd.h> // IWYU pragma: keep
 #endif
 
+#include "cmCMakePresetsFile.h"
 #include "cmCTestBuildAndTestHandler.h"
 #include "cmCTestBuildHandler.h"
 #include "cmCTestConfigureHandler.h"
@@ -179,6 +182,7 @@ struct cmCTest::Private
 
   // information for the --build-and-test options
   std::string BinaryDir;
+  std::string TestDir;
 
   std::string NotesFiles;
 
@@ -1017,6 +1021,17 @@ int cmCTest::ProcessSteps()
   }
   if (res != 0) {
     cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest" << std::endl);
+    if (!this->Impl->OutputTestOutputOnTestFailure) {
+      const std::string lastTestLog =
+        this->GetBinaryDir() + "/Testing/Temporary/LastTest.log";
+      cmCTestLog(this, ERROR_MESSAGE,
+                 "Output from these tests are in: " << lastTestLog
+                                                    << std::endl);
+      cmCTestLog(this, ERROR_MESSAGE,
+                 "Use \"--rerun-failed --output-on-failure\" to re-run the "
+                 "failed cases verbosely."
+                   << std::endl);
+    }
   }
   return res;
 }
@@ -1313,11 +1328,11 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
   if (result == cmsysProcess_State_Exited) {
     *retVal = cmsysProcess_GetExitValue(cp);
     if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
-      OutputTestErrors(tempOutput);
+      this->OutputTestErrors(tempOutput);
     }
   } else if (result == cmsysProcess_State_Exception) {
     if (this->Impl->OutputTestOutputOnTestFailure) {
-      OutputTestErrors(tempOutput);
+      this->OutputTestErrors(tempOutput);
     }
     *retVal = cmsysProcess_GetExitException(cp);
     std::string outerr = cmStrCat("\n*** Exception executing: ",
@@ -2048,6 +2063,13 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
     i++;
     this->SetNotesFiles(args[i]);
     return true;
+  } else if (this->CheckArgument(arg, "--test-dir"_s)) {
+    if (i >= args.size() - 1) {
+      errormsg = "'--test-dir' requires an argument";
+      return false;
+    }
+    i++;
+    this->Impl->TestDir = std::string(args[i]);
   }
 
   cm::string_view noTestsPrefix = "--no-tests=";
@@ -2237,6 +2259,306 @@ bool cmCTest::AddVariableDefinition(const std::string& arg)
   return false;
 }
 
+void cmCTest::SetPersistentOptionIfNotEmpty(const std::string& value,
+                                            const std::string& optionName)
+{
+  if (!value.empty()) {
+    this->GetTestHandler()->SetPersistentOption(optionName, value.c_str());
+    this->GetMemCheckHandler()->SetPersistentOption(optionName, value.c_str());
+  }
+}
+
+bool cmCTest::SetArgsFromPreset(const std::string& presetName,
+                                bool listPresets)
+{
+  const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+
+  cmCMakePresetsFile settingsFile;
+  auto result = settingsFile.ReadProjectPresets(workingDirectory);
+  if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
+    cmSystemTools::Error(cmStrCat("Could not read presets from ",
+                                  workingDirectory, ": ",
+                                  cmCMakePresetsFile::ResultToString(result)));
+    return false;
+  }
+
+  if (listPresets) {
+    settingsFile.PrintTestPresetList();
+    return true;
+  }
+
+  auto presetPair = settingsFile.TestPresets.find(presetName);
+  if (presetPair == settingsFile.TestPresets.end()) {
+    cmSystemTools::Error(cmStrCat("No such test preset in ", workingDirectory,
+                                  ": \"", presetName, '"'));
+    settingsFile.PrintTestPresetList();
+    return false;
+  }
+
+  if (presetPair->second.Unexpanded.Hidden) {
+    cmSystemTools::Error(cmStrCat("Cannot use hidden test preset in ",
+                                  workingDirectory, ": \"", presetName, '"'));
+    settingsFile.PrintTestPresetList();
+    return false;
+  }
+
+  auto const& expandedPreset = presetPair->second.Expanded;
+  if (!expandedPreset) {
+    cmSystemTools::Error(cmStrCat("Could not evaluate test preset \"",
+                                  presetName, "\": Invalid macro expansion"));
+    settingsFile.PrintTestPresetList();
+    return false;
+  }
+
+  auto configurePresetPair =
+    settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
+  if (configurePresetPair == settingsFile.ConfigurePresets.end()) {
+    cmSystemTools::Error(cmStrCat("No such configure preset in ",
+                                  workingDirectory, ": \"",
+                                  expandedPreset->ConfigurePreset, '"'));
+    settingsFile.PrintConfigurePresetList();
+    return false;
+  }
+
+  if (configurePresetPair->second.Unexpanded.Hidden) {
+    cmSystemTools::Error(cmStrCat("Cannot use hidden configure preset in ",
+                                  workingDirectory, ": \"",
+                                  expandedPreset->ConfigurePreset, '"'));
+    settingsFile.PrintConfigurePresetList();
+    return false;
+  }
+
+  auto const& expandedConfigurePreset = configurePresetPair->second.Expanded;
+  if (!expandedConfigurePreset) {
+    cmSystemTools::Error(cmStrCat("Could not evaluate configure preset \"",
+                                  expandedPreset->ConfigurePreset,
+                                  "\": Invalid macro expansion"));
+    return false;
+  }
+
+  auto presetEnvironment = expandedPreset->Environment;
+  for (auto const& var : presetEnvironment) {
+    if (var.second) {
+      cmSystemTools::PutEnv(cmStrCat(var.first, '=', *var.second));
+    }
+  }
+
+  if (!expandedPreset->Configuration.empty()) {
+    this->SetConfigType(expandedPreset->Configuration);
+  }
+
+  // Set build directory to value specified by the configure preset.
+  this->AddCTestConfigurationOverwrite(
+    cmStrCat("BuildDirectory=", expandedConfigurePreset->BinaryDir));
+  for (const auto& kvp : expandedPreset->OverwriteConfigurationFile) {
+    this->AddCTestConfigurationOverwrite(kvp);
+  }
+
+  if (expandedPreset->Output) {
+    this->Impl->TestProgressOutput =
+      expandedPreset->Output->ShortProgress.value_or(false);
+
+    if (expandedPreset->Output->Verbosity) {
+      const auto& verbosity = *expandedPreset->Output->Verbosity;
+      switch (verbosity) {
+        case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
+          Extra:
+          this->Impl->ExtraVerbose = true;
+          // intentional fallthrough
+        case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
+          Verbose:
+          this->Impl->Verbose = true;
+          break;
+        case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum::
+          Default:
+        default:
+          // leave default settings
+          break;
+      }
+    }
+
+    this->Impl->Debug = expandedPreset->Output->Debug.value_or(false);
+    this->Impl->ShowLineNumbers =
+      expandedPreset->Output->Debug.value_or(false);
+    this->Impl->OutputTestOutputOnTestFailure =
+      expandedPreset->Output->OutputOnFailure.value_or(false);
+    this->Impl->Quiet = expandedPreset->Output->Quiet.value_or(false);
+
+    if (!expandedPreset->Output->OutputLogFile.empty()) {
+      this->SetOutputLogFileName(expandedPreset->Output->OutputLogFile);
+    }
+
+    this->Impl->LabelSummary =
+      expandedPreset->Output->LabelSummary.value_or(true);
+    this->Impl->SubprojectSummary =
+      expandedPreset->Output->SubprojectSummary.value_or(true);
+
+    if (expandedPreset->Output->MaxPassedTestOutputSize) {
+      this->Impl->TestHandler.SetTestOutputSizePassed(
+        *expandedPreset->Output->MaxPassedTestOutputSize);
+    }
+
+    if (expandedPreset->Output->MaxFailedTestOutputSize) {
+      this->Impl->TestHandler.SetTestOutputSizeFailed(
+        *expandedPreset->Output->MaxFailedTestOutputSize);
+    }
+
+    if (expandedPreset->Output->MaxTestNameWidth) {
+      this->Impl->MaxTestNameWidth = *expandedPreset->Output->MaxTestNameWidth;
+    }
+  }
+
+  if (expandedPreset->Filter) {
+    if (expandedPreset->Filter->Include) {
+      this->SetPersistentOptionIfNotEmpty(
+        expandedPreset->Filter->Include->Name, "IncludeRegularExpression");
+      this->SetPersistentOptionIfNotEmpty(
+        expandedPreset->Filter->Include->Label, "LabelRegularExpression");
+
+      if (expandedPreset->Filter->Include->Index) {
+        if (expandedPreset->Filter->Include->Index->IndexFile.empty()) {
+          const auto& start = expandedPreset->Filter->Include->Index->Start;
+          const auto& end = expandedPreset->Filter->Include->Index->End;
+          const auto& stride = expandedPreset->Filter->Include->Index->Stride;
+          std::string indexOptions;
+          indexOptions += (start ? std::to_string(*start) : "") + ",";
+          indexOptions += (end ? std::to_string(*end) : "") + ",";
+          indexOptions += (stride ? std::to_string(*stride) : "") + ",";
+          indexOptions +=
+            cmJoin(expandedPreset->Filter->Include->Index->SpecificTests, ",");
+
+          this->SetPersistentOptionIfNotEmpty(indexOptions,
+                                              "TestsToRunInformation");
+        } else {
+          this->SetPersistentOptionIfNotEmpty(
+            expandedPreset->Filter->Include->Index->IndexFile,
+            "TestsToRunInformation");
+        }
+      }
+
+      if (expandedPreset->Filter->Include->UseUnion.value_or(false)) {
+        this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
+        this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
+      }
+    }
+
+    if (expandedPreset->Filter->Exclude) {
+      this->SetPersistentOptionIfNotEmpty(
+        expandedPreset->Filter->Exclude->Name, "ExcludeRegularExpression");
+      this->SetPersistentOptionIfNotEmpty(
+        expandedPreset->Filter->Exclude->Label,
+        "ExcludeLabelRegularExpression");
+
+      if (expandedPreset->Filter->Exclude->Fixtures) {
+        this->SetPersistentOptionIfNotEmpty(
+          expandedPreset->Filter->Exclude->Fixtures->Any,
+          "ExcludeFixtureRegularExpression");
+        this->SetPersistentOptionIfNotEmpty(
+          expandedPreset->Filter->Exclude->Fixtures->Setup,
+          "ExcludeFixtureSetupRegularExpression");
+        this->SetPersistentOptionIfNotEmpty(
+          expandedPreset->Filter->Exclude->Fixtures->Cleanup,
+          "ExcludeFixtureCleanupRegularExpression");
+      }
+    }
+  }
+
+  if (expandedPreset->Execution) {
+    this->Impl->StopOnFailure =
+      expandedPreset->Execution->StopOnFailure.value_or(false);
+    this->Impl->Failover =
+      expandedPreset->Execution->EnableFailover.value_or(false);
+
+    if (expandedPreset->Execution->Jobs) {
+      auto jobs = *expandedPreset->Execution->Jobs;
+      this->SetParallelLevel(jobs);
+      this->Impl->ParallelLevelSetInCli = true;
+    }
+
+    this->SetPersistentOptionIfNotEmpty(
+      expandedPreset->Execution->ResourceSpecFile, "ResourceSpecFile");
+
+    if (expandedPreset->Execution->TestLoad) {
+      auto testLoad = *expandedPreset->Execution->TestLoad;
+      this->SetTestLoad(testLoad);
+    }
+
+    if (expandedPreset->Execution->ShowOnly) {
+      this->Impl->ShowOnly = true;
+
+      switch (*expandedPreset->Execution->ShowOnly) {
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum::
+          JsonV1:
+          this->Impl->Quiet = true;
+          this->Impl->OutputAsJson = true;
+          this->Impl->OutputAsJsonVersion = 1;
+          break;
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum::
+          Human:
+          // intentional fallthrough (human is the default)
+        default:
+          break;
+      }
+    }
+
+    if (expandedPreset->Execution->Repeat) {
+      this->Impl->RepeatCount = expandedPreset->Execution->Repeat->Count;
+      switch (expandedPreset->Execution->Repeat->Mode) {
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
+          ModeEnum::UntilFail:
+          this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+          break;
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
+          ModeEnum::UntilPass:
+          this->Impl->RepeatMode = cmCTest::Repeat::UntilPass;
+          break;
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions::
+          ModeEnum::AfterTimeout:
+          this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout;
+          break;
+        default:
+          // should never default since mode is required
+          return false;
+      }
+    }
+
+    if (expandedPreset->Execution->InteractiveDebugging) {
+      this->Impl->InteractiveDebugMode =
+        *expandedPreset->Execution->InteractiveDebugging;
+    }
+
+    if (expandedPreset->Execution->ScheduleRandom.value_or(false)) {
+      this->Impl->ScheduleType = "Random";
+    }
+
+    if (expandedPreset->Execution->Timeout) {
+      this->Impl->GlobalTimeout =
+        cmDuration(*expandedPreset->Execution->Timeout);
+    }
+
+    if (expandedPreset->Execution->NoTestsAction) {
+      switch (*expandedPreset->Execution->NoTestsAction) {
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::
+          NoTestsActionEnum::Error:
+          this->Impl->NoTestsMode = cmCTest::NoTests::Error;
+          break;
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::
+          NoTestsActionEnum::Ignore:
+          this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
+          break;
+        case cmCMakePresetsFile::TestPreset::ExecutionOptions::
+          NoTestsActionEnum::Default:
+          break;
+        default:
+          // should never default
+          return false;
+      }
+    }
+  }
+
+  return true;
+}
+
 // the main entry point of ctest, called from main
 int cmCTest::Run(std::vector<std::string>& args, std::string* output)
 {
@@ -2248,6 +2570,43 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
   // copy the command line
   cm::append(this->Impl->InitialCommandLineArguments, args);
 
+  // check if a test preset was specified
+
+  bool listPresets =
+    find(args.begin(), args.end(), "--list-presets") != args.end();
+  auto it =
+    std::find_if(args.begin(), args.end(), [](std::string const& arg) -> bool {
+      return arg == "--preset" || cmHasLiteralPrefix(arg, "--preset=");
+    });
+  if (listPresets || it != args.end()) {
+    std::string errormsg;
+    bool success;
+
+    if (listPresets) {
+      // If listing presets we don't need a presetName
+      success = this->SetArgsFromPreset("", listPresets);
+    } else {
+      if (cmHasLiteralPrefix(*it, "--preset=")) {
+        auto presetName = it->substr(9);
+        success = this->SetArgsFromPreset(presetName, listPresets);
+      } else if (++it != args.end()) {
+        auto presetName = *it;
+        success = this->SetArgsFromPreset(presetName, listPresets);
+      } else {
+        cmSystemTools::Error("'--preset' requires an argument");
+        success = false;
+      }
+    }
+
+    if (listPresets) {
+      return success ? 0 : 1;
+    }
+
+    if (!success) {
+      return 1;
+    }
+  }
+
   // process the command line arguments
   for (size_t i = 1; i < args.size(); ++i) {
     // handle the simple commandline arguments
@@ -2319,7 +2678,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
       this->Impl->ScheduleType = "Random";
     }
 
-    // pass the argument to all the handlers as well, but i may no longer be
+    // pass the argument to all the handlers as well, but it may no longer be
     // set to what it was originally so I'm not sure this is working as
     // intended
     for (auto& handler : this->Impl->GetTestingHandlers()) {
@@ -2456,8 +2815,26 @@ int cmCTest::ExecuteTests()
       handler->SetVerbose(this->Impl->Verbose);
       handler->SetSubmitIndex(this->Impl->SubmitIndex);
     }
-    std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
-    if (!this->Initialize(cwd.c_str(), nullptr)) {
+
+    const std::string currDir = cmSystemTools::GetCurrentWorkingDirectory();
+    std::string workDir = currDir;
+    if (!this->Impl->TestDir.empty()) {
+      workDir = cmSystemTools::CollapseFullPath(this->Impl->TestDir);
+    }
+
+    if (currDir != workDir) {
+      cmCTestLog(this, OUTPUT,
+                 "Internal ctest changing into directory: " << workDir
+                                                            << std::endl);
+      if (cmSystemTools::ChangeDirectory(workDir) != 0) {
+        auto msg = "Failed to change working directory to \"" + workDir +
+          "\" : " + std::strerror(errno) + "\n";
+        cmCTestLog(this, ERROR_MESSAGE, msg);
+        return 1;
+      }
+    }
+
+    if (!this->Initialize(workDir.c_str(), nullptr)) {
       res = 12;
       cmCTestLog(this, ERROR_MESSAGE,
                  "Problem initializing the dashboard." << std::endl);
@@ -2465,6 +2842,10 @@ int cmCTest::ExecuteTests()
       res = this->ProcessSteps();
     }
     this->Finalize();
+
+    if (currDir != workDir) {
+      cmSystemTools::ChangeDirectory(currDir);
+    }
   }
   if (res != 0) {
     cmCTestLog(this, DEBUG,
@@ -2859,7 +3240,7 @@ bool cmCTest::GetFailover() const
 
 bool cmCTest::GetTestProgressOutput() const
 {
-  return this->Impl->TestProgressOutput;
+  return this->Impl->TestProgressOutput && !GetExtraVerbose();
 }
 
 bool cmCTest::GetVerbose() const
index e12f8b0..4669a1c 100644 (file)
@@ -461,6 +461,9 @@ public:
   void SetRunCurrentScript(bool value);
 
 private:
+  void SetPersistentOptionIfNotEmpty(const std::string& value,
+                                     const std::string& optionName);
+
   int GenerateNotesFile(const std::string& files);
 
   void BlockTestErrorDiagnostics();
@@ -484,6 +487,9 @@ private:
   /** add a variable definition from a command line -D value */
   bool AddVariableDefinition(const std::string& arg);
 
+  /** set command line arguments read from a test preset */
+  bool SetArgsFromPreset(const std::string& presetName, bool listPresets);
+
   /** parse and process most common command line arguments */
   bool HandleCommandLineArguments(size_t& i, std::vector<std::string>& args,
                                   std::string& errormsg);
index 8d1a5fd..1a950df 100644 (file)
@@ -183,7 +183,7 @@ bool cmCacheManager::ReadPropertyEntry(const std::string& entryKey,
     if (entryKey.size() > plen && *(end - plen) == '-' &&
         strcmp(end - plen + 1, p) == 0) {
       std::string key = entryKey.substr(0, entryKey.size() - plen);
-      if (auto entry = this->GetCacheEntry(key)) {
+      if (auto* entry = this->GetCacheEntry(key)) {
         // Store this property on its entry.
         entry->SetProperty(p, e.Value.c_str());
       } else {
@@ -498,7 +498,7 @@ const cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry(
 
 cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const
 {
-  if (auto entry = this->GetCacheEntry(key)) {
+  if (const auto* entry = this->GetCacheEntry(key)) {
     if (entry->Initialized) {
       return &entry->GetValue();
     }
index 9aebffc..7a9a7dc 100644 (file)
@@ -74,7 +74,7 @@ public:
 
   cmProp GetCacheEntryValue(const std::string& key) const
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (const auto* entry = this->GetCacheEntry(key)) {
       return &entry->GetValue();
     }
     return nullptr;
@@ -82,14 +82,14 @@ public:
 
   void SetCacheEntryValue(std::string const& key, std::string const& value)
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (auto* entry = this->GetCacheEntry(key)) {
       entry->SetValue(value.c_str());
     }
   }
 
   cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (const auto* entry = this->GetCacheEntry(key)) {
       return entry->GetType();
     }
     return cmStateEnums::UNINITIALIZED;
@@ -98,7 +98,7 @@ public:
   std::vector<std::string> GetCacheEntryPropertyList(
     std::string const& key) const
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (const auto* entry = this->GetCacheEntry(key)) {
       return entry->GetPropertyList();
     }
     return {};
@@ -107,7 +107,7 @@ public:
   cmProp GetCacheEntryProperty(std::string const& key,
                                std::string const& propName) const
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (const auto* entry = this->GetCacheEntry(key)) {
       return entry->GetProperty(propName);
     }
     return nullptr;
@@ -116,7 +116,7 @@ public:
   bool GetCacheEntryPropertyAsBool(std::string const& key,
                                    std::string const& propName) const
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (const auto* entry = this->GetCacheEntry(key)) {
       return entry->GetPropertyAsBool(propName);
     }
     return false;
@@ -126,7 +126,7 @@ public:
                              std::string const& propName,
                              std::string const& value)
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (auto* entry = this->GetCacheEntry(key)) {
       entry->SetProperty(propName, value.c_str());
     }
   }
@@ -134,7 +134,7 @@ public:
   void SetCacheEntryBoolProperty(std::string const& key,
                                  std::string const& propName, bool value)
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (auto* entry = this->GetCacheEntry(key)) {
       entry->SetProperty(propName, value);
     }
   }
@@ -142,7 +142,7 @@ public:
   void RemoveCacheEntryProperty(std::string const& key,
                                 std::string const& propName)
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (auto* entry = this->GetCacheEntry(key)) {
       entry->SetProperty(propName, nullptr);
     }
   }
@@ -152,7 +152,7 @@ public:
                                 std::string const& value,
                                 bool asString = false)
   {
-    if (auto entry = this->GetCacheEntry(key)) {
+    if (auto* entry = this->GetCacheEntry(key)) {
       entry->AppendProperty(propName, value, asString);
     }
   }
diff --git a/Source/cmCheckCustomOutputs.cxx b/Source/cmCheckCustomOutputs.cxx
deleted file mode 100644 (file)
index 7645c88..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmCheckCustomOutputs.h"
-
-#include "cmExecutionStatus.h"
-#include "cmMakefile.h"
-#include "cmStringAlgorithms.h"
-#include "cmSystemTools.h"
-
-bool cmCheckCustomOutputs(const std::vector<std::string>& outputs,
-                          cm::string_view keyword, cmExecutionStatus& status)
-{
-  cmMakefile& mf = status.GetMakefile();
-
-  for (std::string const& o : outputs) {
-    // Make sure the file will not be generated into the source
-    // directory during an out of source build.
-    if (!mf.CanIWriteThisFile(o)) {
-      status.SetError(
-        cmStrCat("attempted to have a file\n  ", o,
-                 "\nin a source directory as an output of custom command."));
-      cmSystemTools::SetFatalErrorOccured();
-      return false;
-    }
-
-    // Make sure the output file name has no invalid characters.
-    std::string::size_type pos = o.find_first_of("#<>");
-    if (pos != std::string::npos) {
-      status.SetError(cmStrCat("called with ", keyword, " containing a \"",
-                               o[pos], "\".  This character is not allowed."));
-      return false;
-    }
-  }
-
-  return true;
-}
diff --git a/Source/cmCheckCustomOutputs.h b/Source/cmCheckCustomOutputs.h
deleted file mode 100644 (file)
index 2752ed4..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <string>
-#include <vector>
-
-#include <cm/string_view>
-
-class cmExecutionStatus;
-
-bool cmCheckCustomOutputs(const std::vector<std::string>& outputs,
-                          cm::string_view keyword, cmExecutionStatus& status);
index d4f5022..deddba8 100644 (file)
@@ -228,7 +228,7 @@ int cmCommandArgumentParserHelper::ParseString(std::string const& str,
 
   yyscan_t yyscanner;
   cmCommandArgument_yylex_init(&yyscanner);
-  auto scanBuf = cmCommandArgument_yy_scan_string(str.c_str(), yyscanner);
+  auto* scanBuf = cmCommandArgument_yy_scan_string(str.c_str(), yyscanner);
   cmCommandArgument_yyset_extra(this, yyscanner);
   cmCommandArgument_SetupEscapes(yyscanner, this->NoEscapeMode);
   int res = cmCommandArgument_yyparse(yyscanner);
@@ -240,7 +240,7 @@ int cmCommandArgumentParserHelper::ParseString(std::string const& str,
 
   this->CleanupParser();
 
-  if (Verbose) {
+  if (this->Verbose) {
     std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]"
               << std::endl;
   }
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h
new file mode 100644 (file)
index 0000000..cbedf0a
--- /dev/null
@@ -0,0 +1,159 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+template <typename FunctionSignature>
+struct cmCommandLineArgument
+{
+  enum class Values
+  {
+    Zero,
+    One,
+    Two,
+    ZeroOrOne,
+    OneOrMore
+  };
+
+  std::string InvalidSyntaxMessage;
+  std::string InvalidValueMessage;
+  std::string Name;
+  Values Type;
+  std::function<FunctionSignature> StoreCall;
+
+  template <typename FunctionType>
+  cmCommandLineArgument(std::string n, Values t, FunctionType&& func)
+    : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
+    , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
+    , Name(std::move(n))
+    , Type(t)
+    , StoreCall(std::forward<FunctionType>(func))
+  {
+  }
+
+  template <typename FunctionType>
+  cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
+                        FunctionType&& func)
+    : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
+    , InvalidValueMessage(std::move(failedMsg))
+    , Name(std::move(n))
+    , Type(t)
+    , StoreCall(std::forward<FunctionType>(func))
+  {
+  }
+
+  bool matches(std::string const& input) const
+  {
+    return (this->Type == Values::Zero) ? (input == this->Name)
+                                        : cmHasPrefix(input, this->Name);
+  }
+
+  template <typename T, typename... CallState>
+  bool parse(std::string const& input, T& index,
+             std::vector<std::string> const& allArgs,
+             CallState&&... state) const
+  {
+    enum class ParseMode
+    {
+      Valid,
+      Invalid,
+      SyntaxError,
+      ValueError
+    };
+    ParseMode parseState = ParseMode::Valid;
+
+    if (this->Type == Values::Zero) {
+      if (input.size() == this->Name.size()) {
+        parseState =
+          this->StoreCall(std::string{}, std::forward<CallState>(state)...)
+          ? ParseMode::Valid
+          : ParseMode::Invalid;
+      } else {
+        parseState = ParseMode::SyntaxError;
+      }
+
+    } else if (this->Type == Values::One || this->Type == Values::ZeroOrOne) {
+      if (input.size() == this->Name.size()) {
+        ++index;
+        if (index >= allArgs.size() || allArgs[index][0] == '-') {
+          if (this->Type == Values::ZeroOrOne) {
+            parseState =
+              this->StoreCall(std::string{}, std::forward<CallState>(state)...)
+              ? ParseMode::Valid
+              : ParseMode::Invalid;
+          } else {
+            parseState = ParseMode::ValueError;
+          }
+        } else {
+          parseState =
+            this->StoreCall(allArgs[index], std::forward<CallState>(state)...)
+            ? ParseMode::Valid
+            : ParseMode::Invalid;
+        }
+      } else {
+        // parse the string to get the value
+        auto possible_value = cm::string_view(input).substr(this->Name.size());
+        if (possible_value.empty()) {
+          parseState = ParseMode::SyntaxError;
+          parseState = ParseMode::ValueError;
+        } else if (possible_value[0] == '=') {
+          possible_value.remove_prefix(1);
+          if (possible_value.empty()) {
+            parseState = ParseMode::ValueError;
+          } else {
+            parseState = this->StoreCall(std::string(possible_value),
+                                         std::forward<CallState>(state)...)
+              ? ParseMode::Valid
+              : ParseMode::Invalid;
+          }
+        }
+        if (parseState == ParseMode::Valid) {
+          parseState = this->StoreCall(std::string(possible_value),
+                                       std::forward<CallState>(state)...)
+            ? ParseMode::Valid
+            : ParseMode::Invalid;
+        }
+      }
+    } else if (this->Type == Values::Two) {
+      if (input.size() == this->Name.size()) {
+        if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
+            allArgs[index + 2][0] == '-') {
+          parseState = ParseMode::ValueError;
+        } else {
+          index += 2;
+          parseState =
+            this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
+                            std::forward<CallState>(state)...)
+            ? ParseMode::Valid
+            : ParseMode::Invalid;
+        }
+      }
+    } else if (this->Type == Values::OneOrMore) {
+      if (input.size() == this->Name.size()) {
+        auto nextValueIndex = index + 1;
+        if (nextValueIndex >= allArgs.size() || allArgs[index + 1][0] == '-') {
+          parseState = ParseMode::ValueError;
+        } else {
+          std::string buffer = allArgs[nextValueIndex++];
+          while (nextValueIndex < allArgs.size() &&
+                 allArgs[nextValueIndex][0] != '-') {
+            buffer = cmStrCat(buffer, ";", allArgs[nextValueIndex++]);
+          }
+          parseState =
+            this->StoreCall(buffer, std::forward<CallState>(state)...)
+            ? ParseMode::Valid
+            : ParseMode::Invalid;
+        }
+      }
+    }
+
+    if (parseState == ParseMode::SyntaxError) {
+      cmSystemTools::Error(this->InvalidSyntaxMessage);
+    } else if (parseState == ParseMode::ValueError) {
+      cmSystemTools::Error(this->InvalidValueMessage);
+    }
+    return (parseState == ParseMode::Valid);
+  }
+};
index c94f128..9e5b783 100644 (file)
@@ -17,6 +17,7 @@
 #include "cmBreakCommand.h"
 #include "cmBuildCommand.h"
 #include "cmCMakeMinimumRequired.h"
+#include "cmCMakePathCommand.h"
 #include "cmCMakePolicyCommand.h"
 #include "cmCommand.h"
 #include "cmConfigureFileCommand.h"
 
 void GetScriptingCommands(cmState* state)
 {
-  state->AddBuiltinCommand("break", cmBreakCommand);
+  state->AddFlowControlCommand("break", cmBreakCommand);
+  state->AddFlowControlCommand("continue", cmContinueCommand);
+  state->AddFlowControlCommand("foreach", cmForEachCommand);
+  state->AddFlowControlCommand("function", cmFunctionCommand);
+  state->AddFlowControlCommand("if", cmIfCommand);
+  state->AddFlowControlCommand("macro", cmMacroCommand);
+  state->AddFlowControlCommand("return", cmReturnCommand);
+  state->AddFlowControlCommand("while", cmWhileCommand);
+
   state->AddBuiltinCommand("cmake_minimum_required", cmCMakeMinimumRequired);
+  state->AddBuiltinCommand("cmake_path", cmCMakePathCommand);
   state->AddBuiltinCommand("cmake_policy", cmCMakePolicyCommand);
   state->AddBuiltinCommand("configure_file", cmConfigureFileCommand);
-  state->AddBuiltinCommand("continue", cmContinueCommand);
   state->AddBuiltinCommand("exec_program", cmExecProgramCommand);
   state->AddBuiltinCommand("execute_process", cmExecuteProcessCommand);
   state->AddBuiltinCommand("file", cmFileCommand);
@@ -131,26 +140,21 @@ void GetScriptingCommands(cmState* state)
   state->AddBuiltinCommand("find_package", cmFindPackage);
   state->AddBuiltinCommand("find_path", cmFindPath);
   state->AddBuiltinCommand("find_program", cmFindProgram);
-  state->AddBuiltinCommand("foreach", cmForEachCommand);
-  state->AddBuiltinCommand("function", cmFunctionCommand);
   state->AddBuiltinCommand("get_cmake_property", cmGetCMakePropertyCommand);
   state->AddBuiltinCommand("get_directory_property",
                            cmGetDirectoryPropertyCommand);
   state->AddBuiltinCommand("get_filename_component",
                            cmGetFilenameComponentCommand);
   state->AddBuiltinCommand("get_property", cmGetPropertyCommand);
-  state->AddBuiltinCommand("if", cmIfCommand);
   state->AddBuiltinCommand("include", cmIncludeCommand);
   state->AddBuiltinCommand("include_guard", cmIncludeGuardCommand);
   state->AddBuiltinCommand("list", cmListCommand);
-  state->AddBuiltinCommand("macro", cmMacroCommand);
   state->AddBuiltinCommand("make_directory", cmMakeDirectoryCommand);
   state->AddBuiltinCommand("mark_as_advanced", cmMarkAsAdvancedCommand);
   state->AddBuiltinCommand("math", cmMathCommand);
   state->AddBuiltinCommand("message", cmMessageCommand);
   state->AddBuiltinCommand("option", cmOptionCommand);
   state->AddBuiltinCommand("cmake_parse_arguments", cmParseArgumentsCommand);
-  state->AddBuiltinCommand("return", cmReturnCommand);
   state->AddBuiltinCommand("separate_arguments", cmSeparateArgumentsCommand);
   state->AddBuiltinCommand("set", cmSetCommand);
   state->AddBuiltinCommand("set_directory_properties",
@@ -159,7 +163,6 @@ void GetScriptingCommands(cmState* state)
   state->AddBuiltinCommand("site_name", cmSiteNameCommand);
   state->AddBuiltinCommand("string", cmStringCommand);
   state->AddBuiltinCommand("unset", cmUnsetCommand);
-  state->AddBuiltinCommand("while", cmWhileCommand);
 
   state->AddUnexpectedCommand(
     "else",
index 2b7c9f6..228cff7 100644 (file)
@@ -27,7 +27,7 @@ cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
       static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
   , GlobalCommonGenerator(static_cast<cmGlobalCommonGenerator*>(
       gt->LocalGenerator->GetGlobalGenerator()))
-  , ConfigNames(LocalCommonGenerator->GetConfigNames())
+  , ConfigNames(this->LocalCommonGenerator->GetConfigNames())
 {
 }
 
index b9f15b7..6225a4a 100644 (file)
@@ -957,6 +957,9 @@ void cmComputeLinkInformation::AddLinkExtension(std::string const& e,
   }
 }
 
+// XXX(clang-tidy): This method's const-ness is platform dependent, so we
+// cannot make it `const` as `clang-tidy` wants us to.
+// NOLINTNEXTLINE(readability-make-member-function-const)
 std::string cmComputeLinkInformation::CreateExtensionRegex(
   std::vector<std::string> const& exts, LinkType type)
 {
index 1f22ce6..85a9d9c 100644 (file)
@@ -525,7 +525,7 @@ void cmComputeTargetDepends::DisplayGraph(Graph const& graph,
 void cmComputeTargetDepends::DisplaySideEffects()
 {
   fprintf(stderr, "The side effects are:\n");
-  int n = static_cast<int>(SideEffects.size());
+  int n = static_cast<int>(this->SideEffects.size());
   for (int depender_index = 0; depender_index < n; ++depender_index) {
     cmGeneratorTarget const* depender = this->Targets[depender_index];
     fprintf(stderr, "target %d is [%s]\n", depender_index,
index 14f10bd..62bc526 100644 (file)
@@ -271,10 +271,10 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
 {
   // Use the policy if it is set.
   if (this->Policy12Status == cmPolicies::NEW) {
-    return GetBooleanValue(newArg);
+    return this->GetBooleanValue(newArg);
   }
   if (this->Policy12Status == cmPolicies::OLD) {
-    return GetBooleanValueOld(newArg, oneArg);
+    return this->GetBooleanValueOld(newArg, oneArg);
   }
 
   // Check policy only if old and new results differ.
@@ -367,7 +367,7 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
     reducible = 0;
     auto arg = newArgs.begin();
     while (arg != newArgs.end()) {
-      if (IsKeyword(keyParenL, *arg)) {
+      if (this->IsKeyword(keyParenL, *arg)) {
         // search for the closing paren for this opening one
         cmArgumentList::iterator argClose;
         argClose = arg;
@@ -531,7 +531,7 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
       argP1 = arg;
       this->IncrementArguments(newArgs, argP1, argP2);
       if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
-          IsKeyword(keyMATCHES, *argP1)) {
+          this->IsKeyword(keyMATCHES, *argP1)) {
         def = this->GetDefinitionIfUnquoted(*arg);
         if (!def) {
           def = &arg->GetValue();
@@ -707,8 +707,8 @@ bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs,
     cmArgumentList::iterator argP2;
     while (arg != newArgs.end()) {
       argP1 = arg;
-      IncrementArguments(newArgs, argP1, argP2);
-      if (argP1 != newArgs.end() && IsKeyword(keyNOT, *arg)) {
+      this->IncrementArguments(newArgs, argP1, argP2);
+      if (argP1 != newArgs.end() && this->IsKeyword(keyNOT, *arg)) {
         bool rhs = this->GetBooleanValueWithAutoDereference(
           *argP1, errorString, status);
         this->HandlePredicate(!rhs, reducible, arg, newArgs, argP1, argP2);
@@ -735,8 +735,8 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs,
     cmArgumentList::iterator argP2;
     while (arg != newArgs.end()) {
       argP1 = arg;
-      IncrementArguments(newArgs, argP1, argP2);
-      if (argP1 != newArgs.end() && IsKeyword(keyAND, *argP1) &&
+      this->IncrementArguments(newArgs, argP1, argP2);
+      if (argP1 != newArgs.end() && this->IsKeyword(keyAND, *argP1) &&
           argP2 != newArgs.end()) {
         lhs =
           this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
index cf32b05..aeca6b4 100644 (file)
@@ -16,8 +16,9 @@
 
 #cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE
 #cmakedefine HAVE_UNSETENV
-#cmakedefine CMAKE_USE_ELF_PARSER
-#cmakedefine CMAKE_USE_MACH_PARSER
+#cmakedefine CMake_USE_ELF_PARSER
+#cmakedefine CMake_USE_MACH_PARSER
+#cmakedefine CMake_USE_XCOFF_PARSER
 #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@
 #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@"
 #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@"
index 68322cc..edd261d 100644 (file)
@@ -3,11 +3,15 @@
 #include "cmConfigureFileCommand.h"
 
 #include <set>
+#include <sstream>
 
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include <sys/types.h>
+
 #include "cmExecutionStatus.h"
+#include "cmFSPermissions.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmNewLineStyle.h"
@@ -60,7 +64,19 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
   }
   bool copyOnly = false;
   bool escapeQuotes = false;
-  bool use_source_permissions = true;
+  bool useSourcePermissions = false;
+  bool noSourcePermissions = false;
+  bool filePermissions = false;
+  std::vector<std::string> filePermissionOptions;
+
+  enum class Doing
+  {
+    DoingNone,
+    DoingFilePermissions,
+    DoneFilePermissions
+  };
+
+  Doing doing = Doing::DoingNone;
 
   static std::set<cm::string_view> noopOptions = {
     /* Legacy.  */
@@ -78,6 +94,9 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
   bool atOnly = false;
   for (unsigned int i = 2; i < args.size(); ++i) {
     if (args[i] == "COPYONLY") {
+      if (doing == Doing::DoingFilePermissions) {
+        doing = Doing::DoneFilePermissions;
+      }
       copyOnly = true;
       if (newLineStyle.IsValid()) {
         status.SetError("COPYONLY could not be used in combination "
@@ -85,13 +104,49 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
         return false;
       }
     } else if (args[i] == "ESCAPE_QUOTES") {
+      if (doing == Doing::DoingFilePermissions) {
+        doing = Doing::DoneFilePermissions;
+      }
       escapeQuotes = true;
     } else if (args[i] == "@ONLY") {
+      if (doing == Doing::DoingFilePermissions) {
+        doing = Doing::DoneFilePermissions;
+      }
       atOnly = true;
     } else if (args[i] == "NO_SOURCE_PERMISSIONS") {
-      use_source_permissions = false;
+      if (doing == Doing::DoingFilePermissions) {
+        status.SetError(" given both FILE_PERMISSIONS and "
+                        "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+        return false;
+      }
+      noSourcePermissions = true;
+    } else if (args[i] == "USE_SOURCE_PERMISSIONS") {
+      if (doing == Doing::DoingFilePermissions) {
+        status.SetError(" given both FILE_PERMISSIONS and "
+                        "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+        return false;
+      }
+      useSourcePermissions = true;
+    } else if (args[i] == "FILE_PERMISSIONS") {
+      if (useSourcePermissions) {
+        status.SetError(" given both FILE_PERMISSIONS and "
+                        "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+        return false;
+      }
+      if (noSourcePermissions) {
+        status.SetError(" given both FILE_PERMISSIONS and "
+                        "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+        return false;
+      }
+
+      if (doing == Doing::DoingNone) {
+        doing = Doing::DoingFilePermissions;
+        filePermissions = true;
+      }
     } else if (noopOptions.find(args[i]) != noopOptions.end()) {
       /* Ignore no-op options.  */
+    } else if (doing == Doing::DoingFilePermissions) {
+      filePermissionOptions.push_back(args[i]);
     } else {
       unknown_args += " ";
       unknown_args += args[i];
@@ -104,9 +159,53 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args,
     status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, msg);
   }
 
-  if (!status.GetMakefile().ConfigureFile(
-        inputFile, outputFile, copyOnly, atOnly, escapeQuotes,
-        use_source_permissions, newLineStyle)) {
+  if (useSourcePermissions && noSourcePermissions) {
+    status.SetError(" given both USE_SOURCE_PERMISSIONS and "
+                    "NO_SOURCE_PERMISSIONS. Only one option allowed.");
+    return false;
+  }
+
+  mode_t permisiions = 0;
+
+  if (filePermissions) {
+    if (filePermissionOptions.empty()) {
+      status.SetError(" given FILE_PERMISSIONS without any options.");
+      return false;
+    }
+
+    std::vector<std::string> invalidOptions;
+    for (auto const& e : filePermissionOptions) {
+      if (!cmFSPermissions::stringToModeT(e, permisiions)) {
+        invalidOptions.push_back(e);
+      }
+    }
+
+    if (!invalidOptions.empty()) {
+      std::ostringstream oss;
+      oss << " given invalid permission ";
+      for (auto i = 0u; i < invalidOptions.size(); i++) {
+        if (i == 0u) {
+          oss << "\"" << invalidOptions[i] << "\"";
+        } else {
+          oss << ",\"" << invalidOptions[i] << "\"";
+        }
+      }
+      oss << ".";
+      status.SetError(oss.str());
+      return false;
+    }
+  }
+
+  if (noSourcePermissions) {
+    permisiions |= cmFSPermissions::mode_owner_read;
+    permisiions |= cmFSPermissions::mode_owner_write;
+    permisiions |= cmFSPermissions::mode_group_read;
+    permisiions |= cmFSPermissions::mode_world_read;
+  }
+
+  if (!status.GetMakefile().ConfigureFile(inputFile, outputFile, copyOnly,
+                                          atOnly, escapeQuotes, permisiions,
+                                          newLineStyle)) {
     status.SetError("Problem configuring file");
     return false;
   }
diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx
deleted file mode 100644 (file)
index e4d0cf1..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmConnection.h"
-
-#include <cassert>
-#include <cstring>
-
-#include <cm3p/uv.h>
-
-#include "cmServer.h"
-
-struct write_req_t
-{
-  uv_write_t req;
-  uv_buf_t buf;
-};
-
-void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle,
-                                             size_t suggested_size,
-                                             uv_buf_t* buf)
-{
-  (void)(handle);
-#ifndef __clang_analyzer__
-  char* rawBuffer = new char[suggested_size];
-  *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
-#else
-  (void)(suggested_size);
-  (void)(buf);
-#endif /* __clang_analyzer__ */
-}
-
-void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread,
-                                     const uv_buf_t* buf)
-{
-  auto conn = static_cast<cmEventBasedConnection*>(stream->data);
-  if (conn) {
-    if (nread >= 0) {
-      conn->ReadData(std::string(buf->base, buf->base + nread));
-    } else {
-      conn->OnDisconnect(static_cast<int>(nread));
-    }
-  }
-
-  delete[](buf->base);
-}
-
-void cmEventBasedConnection::on_close(uv_handle_t* /*handle*/)
-{
-}
-
-void cmEventBasedConnection::on_write(uv_write_t* req, int status)
-{
-  (void)(status);
-
-  // Free req and buffer
-  write_req_t* wr = reinterpret_cast<write_req_t*>(req);
-  delete[](wr->buf.base);
-  delete wr;
-}
-
-void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status)
-{
-  (void)(status);
-  auto conn = static_cast<cmEventBasedConnection*>(stream->data);
-
-  if (conn) {
-    conn->Connect(stream);
-  }
-}
-
-bool cmEventBasedConnection::IsOpen() const
-{
-  return this->WriteStream != nullptr;
-}
-
-void cmEventBasedConnection::WriteData(const std::string& _data)
-{
-#ifndef NDEBUG
-  auto curr_thread_id = uv_thread_self();
-  assert(this->Server);
-  assert(uv_thread_equal(&curr_thread_id, &this->Server->ServeThreadId));
-#endif
-
-#ifndef __clang_analyzer__
-  auto data = _data;
-  assert(this->WriteStream.get());
-  if (BufferStrategy) {
-    data = BufferStrategy->BufferOutMessage(data);
-  }
-
-  auto ds = data.size();
-
-  write_req_t* req = new write_req_t;
-  req->req.data = this;
-  req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds));
-  memcpy(req->buf.base, data.c_str(), ds);
-  uv_write(reinterpret_cast<uv_write_t*>(req), this->WriteStream, &req->buf, 1,
-           on_write);
-#else
-  (void)(_data);
-#endif /* __clang_analyzer__ */
-}
-
-void cmEventBasedConnection::ReadData(const std::string& data)
-{
-  this->RawReadBuffer += data;
-  if (BufferStrategy) {
-    std::string packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
-    while (!packet.empty()) {
-      ProcessRequest(packet);
-      packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
-    }
-  } else {
-    ProcessRequest(this->RawReadBuffer);
-    this->RawReadBuffer.clear();
-  }
-}
-
-cmEventBasedConnection::cmEventBasedConnection(
-  cmConnectionBufferStrategy* bufferStrategy)
-  : BufferStrategy(bufferStrategy)
-{
-}
-
-void cmEventBasedConnection::Connect(uv_stream_t* server)
-{
-  (void)server;
-  Server->OnConnected(nullptr);
-}
-
-void cmEventBasedConnection::OnDisconnect(int onerror)
-{
-  (void)onerror;
-  this->OnConnectionShuttingDown();
-  if (this->Server) {
-    this->Server->OnDisconnect(this);
-  }
-}
-
-cmConnection::~cmConnection() = default;
-
-bool cmConnection::OnConnectionShuttingDown()
-{
-  this->Server = nullptr;
-  return true;
-}
-
-void cmConnection::SetServer(cmServerBase* s)
-{
-  Server = s;
-}
-
-void cmConnection::ProcessRequest(const std::string& request)
-{
-  Server->ProcessRequest(this, request);
-}
-
-bool cmConnection::OnServeStart(std::string* errString)
-{
-  (void)errString;
-  return true;
-}
-
-bool cmEventBasedConnection::OnConnectionShuttingDown()
-{
-  if (this->WriteStream.get()) {
-    this->WriteStream->data = nullptr;
-  }
-
-  WriteStream.reset();
-
-  return true;
-}
diff --git a/Source/cmConnection.h b/Source/cmConnection.h
deleted file mode 100644 (file)
index 5335a7f..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <cstddef>
-#include <memory>
-#include <string>
-
-#include <cm3p/uv.h>
-
-#include "cmUVHandlePtr.h"
-
-class cmServerBase;
-
-/***
- * Given a sequence of bytes with any kind of buffering, instances of this
- * class arrange logical chunks according to whatever the use case is for
- * the connection.
- */
-class cmConnectionBufferStrategy
-{
-public:
-  virtual ~cmConnectionBufferStrategy();
-
-  /***
-   * Called whenever with an active raw buffer. If a logical chunk
-   * becomes available, that chunk is returned and that portion is
-   * removed from the rawBuffer
-   *
-   * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is
-   * free to manipulate this buffer anyway it needs to.
-   *
-   * @return Next chunk from the stream. Returns the empty string if a chunk
-   * isn't ready yet. Users of this interface should repeatedly call this
-   * function until an empty string is returned since its entirely possible
-   * multiple chunks come in a single raw buffer.
-   */
-  virtual std::string BufferMessage(std::string& rawBuffer) = 0;
-
-  /***
-   * Called to properly buffer an outgoing message.
-   *
-   * @param rawBuffer Message to format in the correct way
-   *
-   * @return Formatted message
-   */
-  virtual std::string BufferOutMessage(const std::string& rawBuffer) const
-  {
-    return rawBuffer;
-  };
-  /***
-   * Resets the internal state of the buffering
-   */
-  virtual void clear();
-
-  // TODO: There should be a callback / flag set for errors
-};
-
-class cmConnection
-{
-public:
-  cmConnection() = default;
-
-  cmConnection(cmConnection const&) = delete;
-  cmConnection& operator=(cmConnection const&) = delete;
-
-  virtual void WriteData(const std::string& data) = 0;
-
-  virtual ~cmConnection();
-
-  virtual bool OnConnectionShuttingDown();
-
-  virtual bool IsOpen() const = 0;
-
-  virtual void SetServer(cmServerBase* s);
-
-  virtual void ProcessRequest(const std::string& request);
-
-  virtual bool OnServeStart(std::string* pString);
-
-protected:
-  cmServerBase* Server = nullptr;
-};
-
-/***
- * Abstraction of a connection; ties in event callbacks from libuv and notifies
- * the server when appropriate
- */
-class cmEventBasedConnection : public cmConnection
-{
-
-public:
-  /***
-   * @param bufferStrategy If no strategy is given, it will process the raw
-   * chunks as they come in. The connection
-   * owns the pointer given.
-   */
-  cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = nullptr);
-
-  virtual void Connect(uv_stream_t* server);
-
-  virtual void ReadData(const std::string& data);
-
-  bool IsOpen() const override;
-
-  void WriteData(const std::string& data) override;
-  bool OnConnectionShuttingDown() override;
-
-  virtual void OnDisconnect(int errorCode);
-
-  static void on_close(uv_handle_t* handle);
-
-  template <typename T>
-  static void on_close_delete(uv_handle_t* handle)
-  {
-    delete reinterpret_cast<T*>(handle);
-  }
-
-protected:
-  cm::uv_stream_ptr WriteStream;
-
-  std::string RawReadBuffer;
-
-  std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy;
-
-  static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
-
-  static void on_write(uv_write_t* req, int status);
-
-  static void on_new_connection(uv_stream_t* stream, int status);
-
-  static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size,
-                              uv_buf_t* buf);
-};
index 70be481..8ce9ebc 100644 (file)
@@ -12,8 +12,6 @@ cmConsoleBuf::cmConsoleBuf()
 cmConsoleBuf::cmConsoleBuf() = default;
 #endif
 
-cmConsoleBuf::~cmConsoleBuf() = default;
-
 void cmConsoleBuf::SetUTF8Pipes()
 {
 #if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP)
index 3564598..0a6d3b5 100644 (file)
@@ -16,7 +16,7 @@ class cmConsoleBuf
 #endif
 public:
   cmConsoleBuf();
-  ~cmConsoleBuf();
+  ~cmConsoleBuf() = default;
   cmConsoleBuf(cmConsoleBuf const&) = delete;
   cmConsoleBuf& operator=(cmConsoleBuf const&) = delete;
   void SetUTF8Pipes();
index 9c4deea..3001ae0 100644 (file)
@@ -125,9 +125,9 @@ bool cmCreateTestSourceList(std::vector<std::string> const& args,
     mf.AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function);
   }
   mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode);
-  mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES", functionMapCode);
+  mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTRIES", functionMapCode);
   bool res = true;
-  if (!mf.ConfigureFile(configFile, driver, false, true, false, true)) {
+  if (!mf.ConfigureFile(configFile, driver, false, true, false)) {
     res = false;
   }
 
index b1e63ba..b331862 100644 (file)
@@ -36,7 +36,7 @@ static rhash cmCryptoHash_rhash_init(unsigned int id)
 
 cmCryptoHash::cmCryptoHash(Algo algo)
   : Id(cmCryptoHashAlgoToId[algo])
-  , CTX(cmCryptoHash_rhash_init(Id))
+  , CTX(cmCryptoHash_rhash_init(this->Id))
 {
 }
 
index 149f5e9..f6b9989 100644 (file)
@@ -140,3 +140,13 @@ void cmCustomCommand::SetJobPool(const std::string& job_pool)
 {
   this->JobPool = job_pool;
 }
+
+cmPolicies::PolicyStatus cmCustomCommand::GetCMP0116Status() const
+{
+  return this->CMP0116Status;
+}
+
+void cmCustomCommand::SetCMP0116Status(cmPolicies::PolicyStatus cmp0116)
+{
+  this->CMP0116Status = cmp0116;
+}
index 2036e90..e22c7a4 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "cmCustomCommandLines.h"
 #include "cmListFileCache.h"
+#include "cmPolicies.h"
 
 class cmImplicitDependsList
   : public std::vector<std::pair<std::string, std::string>>
@@ -95,6 +96,10 @@ public:
   const std::string& GetJobPool() const;
   void SetJobPool(const std::string& job_pool);
 
+  /** Set/Get the CMP0116 status (used by the Ninja generator) */
+  cmPolicies::PolicyStatus GetCMP0116Status() const;
+  void SetCMP0116Status(cmPolicies::PolicyStatus cmp0116);
+
 private:
   std::vector<std::string> Outputs;
   std::vector<std::string> Byproducts;
@@ -112,4 +117,5 @@ private:
   bool UsesTerminal = false;
   bool CommandExpandLists = false;
   bool StdPipesUTF8 = false;
+  cmPolicies::PolicyStatus CMP0116Status = cmPolicies::WARN;
 };
index 60504ba..4329caf 100644 (file)
 #include <memory>
 #include <utility>
 
+#include <cm/optional>
+#include <cm/string_view>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
+#include "cmCryptoHash.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmTransformDepfile.h"
 
 namespace {
-void AppendPaths(const std::vector<std::string>& inputs,
-                 cmGeneratorExpression const& ge, cmLocalGenerator* lg,
-                 std::string const& config, std::vector<std::string>& output)
+std::string EvaluateSplitConfigGenex(
+  cm::string_view input, cmGeneratorExpression const& ge, cmLocalGenerator* lg,
+  bool useOutputConfig, std::string const& outputConfig,
+  std::string const& commandConfig,
+  std::set<BT<std::pair<std::string, bool>>>* utils = nullptr)
 {
-  for (std::string const& in : inputs) {
-    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(in);
-    std::vector<std::string> result =
-      cmExpandedList(cge->Evaluate(lg, config));
-    for (std::string& it : result) {
-      cmSystemTools::ConvertToUnixSlashes(it);
-      if (cmSystemTools::FileIsFullPath(it)) {
-        it = cmSystemTools::CollapseFullPath(
-          it, lg->GetMakefile()->GetHomeOutputDirectory());
+  std::string result;
+
+  while (!input.empty()) {
+    // Copy non-genex content directly to the result.
+    std::string::size_type pos = input.find("$<");
+    result += input.substr(0, pos);
+    if (pos == std::string::npos) {
+      break;
+    }
+    input = input.substr(pos);
+
+    // Find the balanced end of this regex.
+    size_t nestingLevel = 1;
+    for (pos = 2; pos < input.size(); ++pos) {
+      cm::string_view cur = input.substr(pos);
+      if (cmHasLiteralPrefix(cur, "$<")) {
+        ++nestingLevel;
+        ++pos;
+        continue;
+      }
+      if (cmHasLiteralPrefix(cur, ">")) {
+        --nestingLevel;
+        if (nestingLevel == 0) {
+          ++pos;
+          break;
+        }
+      }
+    }
+
+    // Split this genex from following input.
+    cm::string_view genex = input.substr(0, pos);
+    input = input.substr(pos);
+
+    // Convert an outer COMMAND_CONFIG or OUTPUT_CONFIG to the matching config.
+    std::string const* config =
+      useOutputConfig ? &outputConfig : &commandConfig;
+    if (nestingLevel == 0) {
+      static cm::string_view const COMMAND_CONFIG = "$<COMMAND_CONFIG:"_s;
+      static cm::string_view const OUTPUT_CONFIG = "$<OUTPUT_CONFIG:"_s;
+      if (cmHasPrefix(genex, COMMAND_CONFIG)) {
+        genex.remove_prefix(COMMAND_CONFIG.size());
+        genex.remove_suffix(1);
+        useOutputConfig = false;
+        config = &commandConfig;
+      } else if (cmHasPrefix(genex, OUTPUT_CONFIG)) {
+        genex.remove_prefix(OUTPUT_CONFIG.size());
+        genex.remove_suffix(1);
+        useOutputConfig = true;
+        config = &outputConfig;
+      }
+    }
+
+    // Evaluate this genex in the selected configuration.
+    std::unique_ptr<cmCompiledGeneratorExpression> cge =
+      ge.Parse(std::string(genex));
+    result += cge->Evaluate(lg, *config);
+
+    // Record targets referenced by the genex.
+    if (utils) {
+      // FIXME: What is the proper condition for a cross-dependency?
+      bool const cross = !useOutputConfig;
+      for (cmGeneratorTarget* gt : cge->GetTargets()) {
+        utils->emplace(BT<std::pair<std::string, bool>>(
+          { gt->GetName(), cross }, cge->GetBacktrace()));
       }
     }
-    cm::append(output, result);
   }
+
+  return result;
 }
+
+std::vector<std::string> EvaluateDepends(std::vector<std::string> const& paths,
+                                         cmGeneratorExpression const& ge,
+                                         cmLocalGenerator* lg,
+                                         std::string const& outputConfig,
+                                         std::string const& commandConfig)
+{
+  std::vector<std::string> depends;
+  for (std::string const& p : paths) {
+    std::string const& ep =
+      EvaluateSplitConfigGenex(p, ge, lg, /*useOutputConfig=*/true,
+                               /*outputConfig=*/outputConfig,
+                               /*commandConfig=*/commandConfig);
+    cm::append(depends, cmExpandedList(ep));
+  }
+  for (std::string& p : depends) {
+    if (cmSystemTools::FileIsFullPath(p)) {
+      p = cmSystemTools::CollapseFullPath(p);
+    } else {
+      cmSystemTools::ConvertToUnixSlashes(p);
+    }
+  }
+  return depends;
 }
 
-cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
-                                                   std::string config,
-                                                   cmLocalGenerator* lg)
-  : CC(cc)
-  , Config(std::move(config))
+std::vector<std::string> EvaluateOutputs(std::vector<std::string> const& paths,
+                                         cmGeneratorExpression const& ge,
+                                         cmLocalGenerator* lg,
+                                         std::string const& config)
+{
+  std::vector<std::string> outputs;
+  for (std::string const& p : paths) {
+    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
+    cm::append(outputs, lg->ExpandCustomCommandOutputPaths(*cge, config));
+  }
+  return outputs;
+}
+}
+
+cmCustomCommandGenerator::cmCustomCommandGenerator(
+  cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg,
+  bool transformDepfile, cm::optional<std::string> crossConfig)
+  : CC(&cc)
+  , OutputConfig(crossConfig ? *crossConfig : config)
+  , CommandConfig(std::move(config))
   , LG(lg)
   , OldStyle(cc.GetEscapeOldStyle())
   , MakeVars(cc.GetEscapeAllowMakeVars())
@@ -52,38 +154,83 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
 {
   cmGeneratorExpression ge(cc.GetBacktrace());
 
-  const cmCustomCommandLines& cmdlines = this->CC.GetCommandLines();
+  const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
   for (cmCustomCommandLine const& cmdline : cmdlines) {
     cmCustomCommandLine argv;
+    // For the command itself, we default to the COMMAND_CONFIG.
+    bool useOutputConfig = false;
     for (std::string const& clarg : cmdline) {
-      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(clarg);
-      std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
-      if (this->CC.GetCommandExpandLists()) {
+      std::string parsed_arg = EvaluateSplitConfigGenex(
+        clarg, ge, this->LG, useOutputConfig, this->OutputConfig,
+        this->CommandConfig, &this->Utilities);
+      if (this->CC->GetCommandExpandLists()) {
         cm::append(argv, cmExpandedList(parsed_arg));
       } else {
         argv.push_back(std::move(parsed_arg));
       }
+
+      // For remaining arguments, we default to the OUTPUT_CONFIG.
+      useOutputConfig = true;
     }
 
-    // Later code assumes at least one entry exists, but expanding
-    // lists on an empty command may have left this empty.
-    // FIXME: Should we define behavior for removing empty commands?
-    if (argv.empty()) {
+    if (!argv.empty()) {
+      // If the command references an executable target by name,
+      // collect the target to add a target-level dependency on it.
+      cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front());
+      if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) {
+        // FIXME: What is the proper condition for a cross-dependency?
+        bool const cross = true;
+        this->Utilities.emplace(BT<std::pair<std::string, bool>>(
+          { gt->GetName(), cross }, cc.GetBacktrace()));
+      }
+    } else {
+      // Later code assumes at least one entry exists, but expanding
+      // lists on an empty command may have left this empty.
+      // FIXME: Should we define behavior for removing empty commands?
       argv.emplace_back();
     }
 
     this->CommandLines.push_back(std::move(argv));
   }
 
-  AppendPaths(cc.GetByproducts(), ge, this->LG, this->Config,
-              this->Byproducts);
-  AppendPaths(cc.GetDepends(), ge, this->LG, this->Config, this->Depends);
+  if (transformDepfile && !this->CommandLines.empty() &&
+      !cc.GetDepfile().empty() &&
+      this->LG->GetGlobalGenerator()->DepfileFormat()) {
+    cmCustomCommandLine argv;
+    argv.push_back(cmSystemTools::GetCMakeCommand());
+    argv.emplace_back("-E");
+    argv.emplace_back("cmake_transform_depfile");
+    argv.push_back(this->LG->GetGlobalGenerator()->GetName());
+    switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
+      case cmDepfileFormat::GccDepfile:
+        argv.emplace_back("gccdepfile");
+        break;
+      case cmDepfileFormat::VsTlog:
+        argv.emplace_back("vstlog");
+        break;
+    }
+    argv.push_back(this->LG->GetSourceDirectory());
+    argv.push_back(this->LG->GetCurrentSourceDirectory());
+    argv.push_back(this->LG->GetBinaryDirectory());
+    argv.push_back(this->LG->GetCurrentBinaryDirectory());
+    argv.push_back(this->GetFullDepfile());
+    argv.push_back(this->GetInternalDepfile());
 
-  const std::string& workingdirectory = this->CC.GetWorkingDirectory();
+    this->CommandLines.push_back(std::move(argv));
+  }
+
+  this->Outputs =
+    EvaluateOutputs(cc.GetOutputs(), ge, this->LG, this->OutputConfig);
+  this->Byproducts =
+    EvaluateOutputs(cc.GetByproducts(), ge, this->LG, this->OutputConfig);
+  this->Depends = EvaluateDepends(cc.GetDepends(), ge, this->LG,
+                                  this->OutputConfig, this->CommandConfig);
+
+  const std::string& workingdirectory = this->CC->GetWorkingDirectory();
   if (!workingdirectory.empty()) {
-    std::unique_ptr<cmCompiledGeneratorExpression> cge =
-      ge.Parse(workingdirectory);
-    this->WorkingDirectory = cge->Evaluate(this->LG, this->Config);
+    this->WorkingDirectory =
+      EvaluateSplitConfigGenex(workingdirectory, ge, this->LG, true,
+                               this->OutputConfig, this->CommandConfig);
     // Convert working directory to a full path.
     if (!this->WorkingDirectory.empty()) {
       std::string const& build_dir = this->LG->GetCurrentBinaryDirectory();
@@ -97,7 +244,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
 
 unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
 {
-  return static_cast<unsigned int>(this->CC.GetCommandLines().size());
+  return static_cast<unsigned int>(this->CommandLines.size());
 }
 
 void cmCustomCommandGenerator::FillEmulatorsWithArguments()
@@ -140,7 +287,7 @@ const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
       (target->IsImported() ||
        target->GetProperty("CROSSCOMPILING_EMULATOR") ||
        !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
-    return target->GetLocation(this->Config).c_str();
+    return target->GetLocation(this->CommandConfig).c_str();
   }
   return nullptr;
 }
@@ -234,9 +381,43 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
   }
 }
 
+std::string cmCustomCommandGenerator::GetFullDepfile() const
+{
+  std::string depfile = this->CC->GetDepfile();
+  if (depfile.empty()) {
+    return "";
+  }
+
+  if (!cmSystemTools::FileIsFullPath(depfile)) {
+    depfile = cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/', depfile);
+  }
+  return cmSystemTools::CollapseFullPath(depfile);
+}
+
+std::string cmCustomCommandGenerator::GetInternalDepfile() const
+{
+  std::string depfile = this->GetFullDepfile();
+  if (depfile.empty()) {
+    return "";
+  }
+
+  cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+  std::string extension;
+  switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
+    case cmDepfileFormat::GccDepfile:
+      extension = ".d";
+      break;
+    case cmDepfileFormat::VsTlog:
+      extension = ".tlog";
+      break;
+  }
+  return cmStrCat(this->LG->GetBinaryDirectory(), "/CMakeFiles/d/",
+                  hash.HashString(depfile), extension);
+}
+
 const char* cmCustomCommandGenerator::GetComment() const
 {
-  return this->CC.GetComment();
+  return this->CC->GetComment();
 }
 
 std::string cmCustomCommandGenerator::GetWorkingDirectory() const
@@ -246,7 +427,7 @@ std::string cmCustomCommandGenerator::GetWorkingDirectory() const
 
 std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const
 {
-  return this->CC.GetOutputs();
+  return this->Outputs;
 }
 
 std::vector<std::string> const& cmCustomCommandGenerator::GetByproducts() const
@@ -258,3 +439,9 @@ std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const
 {
   return this->Depends;
 }
+
+std::set<BT<std::pair<std::string, bool>>> const&
+cmCustomCommandGenerator::GetUtilities() const
+{
+  return this->Utilities;
+}
index 412eba8..4be5b3f 100644 (file)
@@ -4,26 +4,34 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
+#include <cm/optional>
+
 #include "cmCustomCommandLines.h"
+#include "cmListFileCache.h"
 
 class cmCustomCommand;
 class cmLocalGenerator;
 
 class cmCustomCommandGenerator
 {
-  cmCustomCommand const& CC;
-  std::string Config;
+  cmCustomCommand const* CC;
+  std::string OutputConfig;
+  std::string CommandConfig;
   cmLocalGenerator* LG;
   bool OldStyle;
   bool MakeVars;
   cmCustomCommandLines CommandLines;
   std::vector<std::vector<std::string>> EmulatorsWithArguments;
+  std::vector<std::string> Outputs;
   std::vector<std::string> Byproducts;
   std::vector<std::string> Depends;
   std::string WorkingDirectory;
+  std::set<BT<std::pair<std::string, bool>>> Utilities;
 
   void FillEmulatorsWithArguments();
   std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
@@ -31,11 +39,14 @@ class cmCustomCommandGenerator
 
 public:
   cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
-                           cmLocalGenerator* lg);
+                           cmLocalGenerator* lg, bool transformDepfile = true,
+                           cm::optional<std::string> crossConfig = {});
   cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
+  cmCustomCommandGenerator(cmCustomCommandGenerator&&) = default;
   cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
     delete;
-  cmCustomCommand const& GetCC() const { return this->CC; }
+  cmCustomCommandGenerator& operator=(cmCustomCommandGenerator&&) = default;
+  cmCustomCommand const& GetCC() const { return *(this->CC); }
   unsigned int GetNumberOfCommands() const;
   std::string GetCommand(unsigned int c) const;
   void AppendArguments(unsigned int c, std::string& cmd) const;
@@ -44,5 +55,11 @@ public:
   std::vector<std::string> const& GetOutputs() const;
   std::vector<std::string> const& GetByproducts() const;
   std::vector<std::string> const& GetDepends() const;
+  std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
   bool HasOnlyEmptyCommandLines() const;
+  std::string GetFullDepfile() const;
+  std::string GetInternalDepfile() const;
+
+  const std::string& GetOutputConfig() const { return this->OutputConfig; }
+  const std::string& GetCommandConfig() const { return this->CommandConfig; }
 };
index 5c900ce..324da9e 100644 (file)
@@ -27,10 +27,3 @@ enum class cmObjectLibraryCommands
   Reject,
   Accept
 };
-
-/** Utility target output source file name.  */
-struct cmUtilityOutput
-{
-  std::string Name;
-  std::string NameCMP0049;
-};
index d092f4f..566c3bf 100644 (file)
@@ -77,7 +77,7 @@ bool cmDepends::Check(const std::string& makeFile,
   return okay;
 }
 
-void cmDepends::Clear(const std::string& file)
+void cmDepends::Clear(const std::string& file) const
 {
   // Print verbose output.
   if (this->Verbose) {
index 0240da9..76af4db 100644 (file)
@@ -25,7 +25,6 @@ class cmDepends
 public:
   using DependencyMap = std::map<std::string, std::vector<std::string>>;
 
-public:
   /** Instances need to know the build directory name and the relative
       path from the build directory to the target file.  */
   cmDepends(cmLocalUnixMakefileGenerator3* lg = nullptr,
@@ -70,7 +69,7 @@ public:
              DependencyMap& validDeps);
 
   /** Clear dependencies for the target file so they will be regenerated.  */
-  void Clear(const std::string& file);
+  void Clear(const std::string& file) const;
 
   /** Set the file comparison object */
   void SetFileTimeCache(cmFileTimeCache* fc) { this->FileTimeCache = fc; }
index e6aef92..60e8cbf 100644 (file)
@@ -7,6 +7,7 @@
 #include "cmsys/FStream.hxx"
 
 #include "cmFileTime.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmProperty.h"
@@ -215,16 +216,28 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
   // directory.  We must do the same here.
   std::string obj_m = this->LocalGenerator->ConvertToMakefilePath(obj_i);
   internalDepends << obj_i << '\n';
-
-  for (std::string const& dep : dependencies) {
-    makeDepends << obj_m << ": "
-                << this->LocalGenerator->ConvertToMakefilePath(
-                     this->LocalGenerator->MaybeConvertToRelativePath(binDir,
-                                                                      dep))
-                << '\n';
-    internalDepends << ' ' << dep << '\n';
+  if (!dependencies.empty()) {
+    const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
+                                 this->LocalGenerator->GetGlobalGenerator())
+                                 ->LineContinueDirective;
+    bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
+                                   this->LocalGenerator->GetGlobalGenerator())
+                                   ->SupportsLongLineDependencies();
+    if (supportLongLineDepend) {
+      makeDepends << obj_m << ':';
+    }
+    for (std::string const& dep : dependencies) {
+      std::string dependee = this->LocalGenerator->ConvertToMakefilePath(
+        this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep));
+      if (supportLongLineDepend) {
+        makeDepends << ' ' << lineContinue << ' ' << dependee;
+      } else {
+        makeDepends << obj_m << ": " << dependee << '\n';
+      }
+      internalDepends << ' ' << dep << '\n';
+    }
+    makeDepends << '\n';
   }
-  makeDepends << '\n';
 
   return true;
 }
diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx
new file mode 100644 (file)
index 0000000..2b48df9
--- /dev/null
@@ -0,0 +1,252 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmDependsCompiler.h"
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <utility>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cm/vector>
+#include <cmext/string_view>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmFileTime.h"
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLocalUnixMakefileGenerator3.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+bool cmDependsCompiler::CheckDependencies(
+  const std::string& internalDepFile, const std::vector<std::string>& depFiles,
+  cmDepends::DependencyMap& dependencies,
+  const std::function<bool(const std::string&)>& isValidPath)
+{
+  bool status = true;
+  bool forceReadDeps = true;
+
+  cmFileTime internalDepFileTime;
+  // read cached dependencies stored in internal file
+  if (cmSystemTools::FileExists(internalDepFile)) {
+    internalDepFileTime.Load(internalDepFile);
+    forceReadDeps = false;
+
+    // read current dependencies
+    cmsys::ifstream fin(internalDepFile.c_str());
+    if (fin) {
+      std::string line;
+      std::string depender;
+      std::vector<std::string>* currentDependencies = nullptr;
+      while (std::getline(fin, line)) {
+        if (line.empty() || line.front() == '#') {
+          continue;
+        }
+        // Drop carriage return character at the end
+        if (line.back() == '\r') {
+          line.pop_back();
+          if (line.empty()) {
+            continue;
+          }
+        }
+        // Check if this a depender line
+        if (line.front() != ' ') {
+          depender = std::move(line);
+          currentDependencies = &dependencies[depender];
+          continue;
+        }
+        // This is a dependee line
+        if (currentDependencies != nullptr) {
+          currentDependencies->emplace_back(line.substr(1));
+        }
+      }
+      fin.close();
+    }
+  }
+
+  // Now, update dependencies map with all new compiler generated
+  // dependencies files
+  cmFileTime depFileTime;
+  for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) {
+    const auto& source = *dep++;
+    const auto& target = *dep++;
+    const auto& format = *dep++;
+    const auto& depFile = *dep;
+
+    if (!cmSystemTools::FileExists(depFile)) {
+      continue;
+    }
+
+    if (!forceReadDeps) {
+      depFileTime.Load(depFile);
+    }
+    if (forceReadDeps || depFileTime.Compare(internalDepFileTime) >= 0) {
+      status = false;
+      if (this->Verbose) {
+        cmSystemTools::Stdout(cmStrCat("Dependencies file \"", depFile,
+                                       "\" is newer than depends file \"",
+                                       internalDepFile, "\".\n"));
+      }
+
+      std::vector<std::string> depends;
+      if (format == "custom"_s) {
+        auto deps = cmReadGccDepfile(
+          depFile.c_str(), this->LocalGenerator->GetCurrentBinaryDirectory());
+        if (!deps) {
+          continue;
+        }
+
+        for (auto& entry : *deps) {
+          depends = std::move(entry.paths);
+          if (isValidPath) {
+            cm::erase_if(depends, isValidPath);
+          }
+          // copy depends for each target, except first one, which can be
+          // moved
+          for (auto index = entry.rules.size() - 1; index > 0; --index) {
+            dependencies[entry.rules[index]] = depends;
+          }
+          dependencies[entry.rules.front()] = std::move(depends);
+        }
+      } else {
+        if (format == "msvc"_s) {
+          cmsys::ifstream fin(depFile.c_str());
+          if (!fin) {
+            continue;
+          }
+
+          std::string line;
+          if (!isValidPath) {
+            // insert source as first dependency
+            depends.push_back(source);
+          }
+          while (cmSystemTools::GetLineFromStream(fin, line)) {
+            depends.emplace_back(std::move(line));
+          }
+        } else if (format == "gcc"_s) {
+          auto deps = cmReadGccDepfile(depFile.c_str());
+          if (!deps) {
+            continue;
+          }
+
+          // dependencies generated by the compiler contains only one target
+          depends = std::move(deps->front().paths);
+          if (depends.empty()) {
+            // unexpectedly empty, ignore it and continue
+            continue;
+          }
+
+          // depending of the effective format of the dependencies file
+          // generated by the compiler, the target can be wrongly identified
+          // as a dependency so remove it from the list
+          if (depends.front() == target) {
+            depends.erase(depends.begin());
+          }
+
+          // ensure source file is the first dependency
+          if (depends.front() != source) {
+            cm::erase(depends, source);
+            if (!isValidPath) {
+              depends.insert(depends.begin(), source);
+            }
+          } else if (isValidPath) {
+            // remove first dependency because it must not be filtered out
+            depends.erase(depends.begin());
+          }
+        } else {
+          // unknown format, ignore it
+          continue;
+        }
+
+        if (isValidPath) {
+          cm::erase_if(depends, isValidPath);
+          // insert source as first dependency
+          depends.insert(depends.begin(), source);
+        }
+
+        dependencies[target] = std::move(depends);
+      }
+    }
+  }
+
+  return status;
+}
+
+void cmDependsCompiler::WriteDependencies(
+  const cmDepends::DependencyMap& dependencies, std::ostream& makeDepends,
+  std::ostream& internalDepends)
+{
+  // dependencies file consumed by make tool
+  const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
+                               this->LocalGenerator->GetGlobalGenerator())
+                               ->LineContinueDirective;
+  bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
+                                 this->LocalGenerator->GetGlobalGenerator())
+                                 ->SupportsLongLineDependencies();
+  const auto& binDir = this->LocalGenerator->GetBinaryDirectory();
+  cmDepends::DependencyMap makeDependencies(dependencies);
+  std::unordered_set<cm::string_view> phonyTargets;
+
+  // external dependencies file
+  for (auto& node : makeDependencies) {
+    auto target = this->LocalGenerator->ConvertToMakefilePath(
+      this->LocalGenerator->MaybeConvertToRelativePath(binDir, node.first));
+    auto& deps = node.second;
+    std::transform(
+      deps.cbegin(), deps.cend(), deps.begin(),
+      [this, &binDir](const std::string& dep) {
+        return this->LocalGenerator->ConvertToMakefilePath(
+          this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep));
+      });
+
+    bool first_dep = true;
+    if (supportLongLineDepend) {
+      makeDepends << target << ": ";
+    }
+    for (const auto& dep : deps) {
+      if (supportLongLineDepend) {
+        if (first_dep) {
+          first_dep = false;
+          makeDepends << dep;
+        } else {
+          makeDepends << ' ' << lineContinue << "  " << dep;
+        }
+      } else {
+        makeDepends << target << ": " << dep << std::endl;
+      }
+
+      phonyTargets.emplace(dep.data(), dep.length());
+    }
+    makeDepends << std::endl << std::endl;
+  }
+
+  // add phony targets
+  for (const auto& target : phonyTargets) {
+    makeDepends << std::endl << target << ':' << std::endl;
+  }
+
+  // internal dependencies file
+  for (const auto& node : dependencies) {
+    internalDepends << node.first << std::endl;
+    for (const auto& dep : node.second) {
+      internalDepends << ' ' << dep << std::endl;
+    }
+    internalDepends << std::endl;
+  }
+}
+
+void cmDependsCompiler::ClearDependencies(
+  const std::vector<std::string>& depFiles)
+{
+  for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) {
+    dep += 3;
+    cmSystemTools::RemoveFile(*dep);
+  }
+}
diff --git a/Source/cmDependsCompiler.h b/Source/cmDependsCompiler.h
new file mode 100644 (file)
index 0000000..838156d
--- /dev/null
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <functional>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmDepends.h"
+
+class cmLocalUnixMakefileGenerator3;
+
+/** \class cmDepends
+ * \brief Dependencies files manager.
+ *
+ * This class is responsible for maintaining a compiler_depends.make file in
+ * the build tree corresponding to an object file.
+ */
+class cmDependsCompiler
+{
+public:
+  cmDependsCompiler() = default;
+  ~cmDependsCompiler() = default;
+
+  /** should this be verbose in its output */
+  void SetVerbose(bool verb) { this->Verbose = verb; }
+
+  /** Set the local generator for the directory in which we are
+      scanning dependencies.  This is not a full local generator; it
+      has been setup to do relative path conversions for the current
+      directory.  */
+  void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg)
+  {
+    this->LocalGenerator = lg;
+  }
+
+  /** Read dependencies for the target file. Return true if
+      dependencies didn't changed and false if not.
+      Up-to-date Dependencies will be stored in deps. */
+  bool CheckDependencies(
+    const std::string& internalDepFile,
+    const std::vector<std::string>& depFiles,
+    cmDepends::DependencyMap& dependencies,
+    const std::function<bool(const std::string&)>& isValidPath);
+
+  /** Write dependencies for the target file.  */
+  void WriteDependencies(const cmDepends::DependencyMap& dependencies,
+                         std::ostream& makeDepends,
+                         std::ostream& internalDepends);
+
+  /** Clear dependencies for the target so they will be regenerated.  */
+  void ClearDependencies(const std::vector<std::string>& depFiles);
+
+private:
+  bool Verbose = false;
+  cmLocalUnixMakefileGenerator3* LocalGenerator = nullptr;
+};
index a239418..1a06f31 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "cmFortranParser.h" /* Interface to parser object.  */
 #include "cmGeneratedFileStream.h"
+#include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
@@ -320,14 +321,28 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
   std::string obj_i = this->MaybeConvertToRelativePath(binDir, obj);
   std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i);
   internalDepends << obj_i << "\n " << src << '\n';
-  for (std::string const& i : info.Includes) {
-    makeDepends << obj_m << ": "
-                << cmSystemTools::ConvertToOutputPath(
-                     this->MaybeConvertToRelativePath(binDir, i))
-                << '\n';
-    internalDepends << ' ' << i << '\n';
+  if (!info.Includes.empty()) {
+    const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
+                                 this->LocalGenerator->GetGlobalGenerator())
+                                 ->LineContinueDirective;
+    bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
+                                   this->LocalGenerator->GetGlobalGenerator())
+                                   ->SupportsLongLineDependencies();
+    if (supportLongLineDepend) {
+      makeDepends << obj_m << ':';
+    }
+    for (std::string const& i : info.Includes) {
+      std::string dependee = cmSystemTools::ConvertToOutputPath(
+        this->MaybeConvertToRelativePath(binDir, i));
+      if (supportLongLineDepend) {
+        makeDepends << ' ' << lineContinue << ' ' << dependee;
+      } else {
+        makeDepends << obj_m << ": " << dependee << '\n';
+      }
+      internalDepends << ' ' << i << '\n';
+    }
+    makeDepends << '\n';
   }
-  makeDepends << '\n';
 
   // Write module requirements to the output stream.
   for (std::string const& i : info.Requires) {
index fc1bbdd..0c5d310 100644 (file)
@@ -103,7 +103,7 @@ void cmDependsJavaParserHelper::SafePrintMissing(const char* str, int line,
     std::cout << "- " << strlen(str) << std::endl;
   }
 }
-void cmDependsJavaParserHelper::Print(const char* place, const char* str)
+void cmDependsJavaParserHelper::Print(const char* place, const char* str) const
 {
   if (this->Verbose) {
     std::cout << "[" << place << "=" << str << "]" << std::endl;
index 869b7d4..4057bb7 100644 (file)
@@ -85,7 +85,7 @@ private:
 
   void PrintClasses();
 
-  void Print(const char* place, const char* str);
+  void Print(const char* place, const char* str) const;
   void CombineUnions(char** out, const char* in1, char** in2, const char* sep);
   void SafePrintMissing(const char* str, int line, int cnt);
 
index 1bc453d..3619ade 100644 (file)
@@ -194,7 +194,7 @@ void cmDocumentation::addCTestStandardDocSections()
 {
   // This is currently done for backward compatibility reason
   // We may suppress some of these.
-  addCMakeStandardDocSections();
+  this->addCMakeStandardDocSections();
 }
 
 void cmDocumentation::addCPackStandardDocSections()
index a8d81f7..deffdb6 100644 (file)
@@ -379,7 +379,7 @@ private:
 
     // Fix the byte order of the header.
     if (this->NeedSwap) {
-      ByteSwap(x);
+      this->ByteSwap(x);
     }
     return true;
   }
@@ -387,7 +387,7 @@ private:
   {
     if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
         this->NeedSwap) {
-      ByteSwap(x);
+      this->ByteSwap(x);
     }
     return !this->Stream->fail();
   }
@@ -395,7 +395,7 @@ private:
   {
     if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) &&
         this->NeedSwap) {
-      ByteSwap(x);
+      this->ByteSwap(x);
     }
     return !this->Stream->fail();
   }
@@ -573,7 +573,7 @@ std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
     dyn.d_un.d_val = static_cast<tagtype>(entry.second);
 
     if (this->NeedSwap) {
-      ByteSwap(dyn);
+      this->ByteSwap(dyn);
     }
 
     char* pdyn = reinterpret_cast<char*>(&dyn);
index 99eb4f4..c479e2b 100644 (file)
@@ -10,8 +10,8 @@
 #include <utility>
 #include <vector>
 
-#if !defined(CMAKE_USE_ELF_PARSER)
-#  error "This file may be included only if CMAKE_USE_ELF_PARSER is enabled."
+#if !defined(CMake_USE_ELF_PARSER)
+#  error "This file may be included only if CMake_USE_ELF_PARSER is enabled."
 #endif
 
 class cmELFInternal;
index 5a85b7d..ffcc415 100644 (file)
@@ -231,7 +231,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
   }
   if (echo_stdout || echo_stderr) {
     std::string command;
-    for (auto& cmd : arguments.Commands) {
+    for (const auto& cmd : arguments.Commands) {
       command += "'";
       command += cmJoin(cmd, "' '");
       command += "'";
index cbae4e5..7015a01 100644 (file)
@@ -707,7 +707,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
       break;
     }
     input.replace(pos, endPos - pos + 1, targetName);
-    lastPos = endPos;
+    lastPos = pos + targetName.size();
   }
 
   pos = 0;
@@ -924,13 +924,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
 
   // Isolate the file policy level.
   // Support CMake versions as far back as 2.6 but also support using NEW
-  // policy settings for up to CMake 3.17 (this upper limit may be reviewed
+  // policy settings for up to CMake 3.18 (this upper limit may be reviewed
   // and increased from time to time). This reduces the opportunity for CMake
   // warnings when an older export file is later used with newer CMake
   // versions.
   /* clang-format off */
   os << "cmake_policy(PUSH)\n"
-     << "cmake_policy(VERSION 2.6...3.17)\n";
+     << "cmake_policy(VERSION 2.6...3.18)\n";
   /* clang-format on */
 }
 
@@ -1214,7 +1214,7 @@ bool cmExportFileGenerator::PopulateExportProperties(
   cmGeneratorTarget* gte, ImportPropertyMap& properties,
   std::string& errorMessage)
 {
-  auto& targetProperties = gte->Target->GetProperties();
+  const auto& targetProperties = gte->Target->GetProperties();
   if (cmProp exportProperties =
         targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) {
     for (auto& prop : cmExpandedList(*exportProperties)) {
index 0b9b183..3c69c50 100644 (file)
@@ -290,6 +290,7 @@ bool cmExportInstallFileGenerator::GenerateImportFileConfig(
     cmSystemTools::Error(e.str());
     return false;
   }
+  exportFileStream.SetCopyIfDifferent(true);
   std::ostream& os = exportFileStream;
 
   // Start with the import file header.
index 56dfc6c..cc8b8b7 100644 (file)
@@ -42,20 +42,22 @@ int cmExprParserHelper::ParseString(const char* str, int verb)
   try {
     int res = cmExpr_yyparse(yyscanner);
     if (res != 0) {
-      std::string e = cmStrCat("cannot parse the expression: \"", InputBuffer,
-                               "\": ", ErrorString, '.');
+      std::string e =
+        cmStrCat("cannot parse the expression: \"", this->InputBuffer,
+                 "\": ", this->ErrorString, '.');
       this->SetError(std::move(e));
     }
   } catch (std::runtime_error const& fail) {
-    std::string e = cmStrCat("cannot evaluate the expression: \"", InputBuffer,
-                             "\": ", fail.what(), '.');
+    std::string e = cmStrCat("cannot evaluate the expression: \"",
+                             this->InputBuffer, "\": ", fail.what(), '.');
     this->SetError(std::move(e));
   } catch (std::out_of_range const&) {
-    std::string e = "cannot evaluate the expression: \"" + InputBuffer +
+    std::string e = "cannot evaluate the expression: \"" + this->InputBuffer +
       "\": a numeric value is out of range.";
     this->SetError(std::move(e));
   } catch (...) {
-    std::string e = "cannot parse the expression: \"" + InputBuffer + "\".";
+    std::string e =
+      "cannot parse the expression: \"" + this->InputBuffer + "\".";
     this->SetError(std::move(e));
   }
   cmExpr_yylex_destroy(yyscanner);
@@ -63,7 +65,7 @@ int cmExprParserHelper::ParseString(const char* str, int verb)
     return 0;
   }
 
-  if (Verbose) {
+  if (this->Verbose) {
     std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]"
               << std::endl;
   }
index 54dd6a4..919e492 100644 (file)
@@ -27,7 +27,7 @@ public:
 
   void SetResult(KWIML_INT_int64_t value);
 
-  KWIML_INT_int64_t GetResult() { return this->Result; }
+  KWIML_INT_int64_t GetResult() const { return this->Result; }
 
   const char* GetError() { return this->ErrorString.c_str(); }
 
index 3ade67b..311a2ef 100644 (file)
@@ -52,8 +52,8 @@ public:
   //! Generate the project files, the Makefiles have already been generated
   virtual void Generate() = 0;
 
-  void SetName(const std::string& n) { Name = n; }
-  std::string GetName() const { return Name; }
+  void SetName(const std::string& n) { this->Name = n; }
+  std::string GetName() const { return this->Name; }
 
   virtual bool Open(const std::string& bindir, const std::string& projectName,
                     bool dryRun);
@@ -104,7 +104,7 @@ public:
   CreateExternalMakefileProjectGenerator() const override
   {
     std::unique_ptr<cmExternalMakefileProjectGenerator> p(new T);
-    p->SetName(GetName());
+    p->SetName(this->GetName());
     return p;
   }
 };
index 87b8f9b..f217201 100644 (file)
@@ -112,10 +112,10 @@ void Tree::InsertPath(const std::vector<std::string>& split,
                       const std::string& fileName)
 {
   if (start == split.size()) {
-    files.insert(fileName);
+    this->files.insert(fileName);
     return;
   }
-  for (Tree& folder : folders) {
+  for (Tree& folder : this->folders) {
     if (folder.path == split[start]) {
       if (start + 1 < split.size()) {
         folder.InsertPath(split, start + 1, fileName);
@@ -131,19 +131,19 @@ void Tree::InsertPath(const std::vector<std::string>& split,
   newFolder.path = split[start];
   if (start + 1 < split.size()) {
     newFolder.InsertPath(split, start + 1, fileName);
-    folders.push_back(newFolder);
+    this->folders.push_back(newFolder);
     return;
   }
   // last part of split
   newFolder.files.insert(fileName);
-  folders.push_back(newFolder);
+  this->folders.push_back(newFolder);
 }
 
 void Tree::BuildVirtualFolder(cmXMLWriter& xml) const
 {
   xml.StartElement("Option");
   std::string virtualFolders = "CMake Files\\;";
-  for (Tree const& folder : folders) {
+  for (Tree const& folder : this->folders) {
     folder.BuildVirtualFolderImpl(virtualFolders, "");
   }
   xml.Attribute("virtualFolders", virtualFolders);
@@ -153,15 +153,15 @@ void Tree::BuildVirtualFolder(cmXMLWriter& xml) const
 void Tree::BuildVirtualFolderImpl(std::string& virtualFolders,
                                   const std::string& prefix) const
 {
-  virtualFolders += "CMake Files\\" + prefix + path + "\\;";
-  for (Tree const& folder : folders) {
-    folder.BuildVirtualFolderImpl(virtualFolders, prefix + path + "\\");
+  virtualFolders += "CMake Files\\" + prefix + this->path + "\\;";
+  for (Tree const& folder : this->folders) {
+    folder.BuildVirtualFolderImpl(virtualFolders, prefix + this->path + "\\");
   }
 }
 
 void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const
 {
-  for (std::string const& f : files) {
+  for (std::string const& f : this->files) {
     xml.StartElement("Unit");
     xml.Attribute("filename", fsPath + f);
 
@@ -171,7 +171,7 @@ void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const
 
     xml.EndElement();
   }
-  for (Tree const& folder : folders) {
+  for (Tree const& folder : this->folders) {
     folder.BuildUnitImpl(xml, "", fsPath);
   }
 }
@@ -180,20 +180,21 @@ void Tree::BuildUnitImpl(cmXMLWriter& xml,
                          const std::string& virtualFolderPath,
                          const std::string& fsPath) const
 {
-  for (std::string const& f : files) {
+  for (std::string const& f : this->files) {
     xml.StartElement("Unit");
-    xml.Attribute("filename", cmStrCat(fsPath, path, "/", f));
+    xml.Attribute("filename", cmStrCat(fsPath, this->path, "/", f));
 
     xml.StartElement("Option");
-    xml.Attribute("virtualFolder",
-                  cmStrCat("CMake Files\\", virtualFolderPath, path, "\\"));
+    xml.Attribute(
+      "virtualFolder",
+      cmStrCat("CMake Files\\", virtualFolderPath, this->path, "\\"));
     xml.EndElement();
 
     xml.EndElement();
   }
-  for (Tree const& folder : folders) {
-    folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, path, "\\"),
-                         cmStrCat(fsPath, path, "/"));
+  for (Tree const& folder : this->folders) {
+    folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, this->path, "\\"),
+                         cmStrCat(fsPath, this->path, "/"));
   }
 }
 
@@ -340,7 +341,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
   all_files_map_t allFiles;
   std::vector<std::string> cFiles;
 
-  auto cm = this->GlobalGenerator->GetCMakeInstance();
+  auto* cm = this->GlobalGenerator->GetCMakeInstance();
 
   for (cmLocalGenerator* lg : lgs) {
     cmMakefile* makefile = lg->GetMakefile();
index 95cfb0a..549b08b 100644 (file)
@@ -64,7 +64,7 @@ void cmExtraCodeLiteGenerator::Generate()
   for (auto const& it : projectMap) {
     cmLocalGenerator* lg = it.second[0];
     const cmMakefile* mf = lg->GetMakefile();
-    this->ConfigName = GetConfigurationName(mf);
+    this->ConfigName = this->GetConfigurationName(mf);
 
     if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
       workspaceOutputDir = lg->GetCurrentBinaryDirectory();
@@ -89,9 +89,9 @@ void cmExtraCodeLiteGenerator::Generate()
 
   std::vector<std::string> ProjectNames;
   if (targetsAreProjects) {
-    ProjectNames = CreateProjectsByTarget(&xml);
+    ProjectNames = this->CreateProjectsByTarget(&xml);
   } else {
-    ProjectNames = CreateProjectsByProjectMaps(&xml);
+    ProjectNames = this->CreateProjectsByProjectMaps(&xml);
   }
 
   xml.StartElement("BuildMatrix");
@@ -142,7 +142,7 @@ std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget(
           xml->Attribute("Active", "No");
           xml->EndElement();
 
-          CreateNewProjectFile(lt.get(), filename);
+          this->CreateNewProjectFile(lt.get(), filename);
           break;
         default:
           break;
@@ -268,7 +268,7 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
     cmMakefile* makefile = lg->GetMakefile();
     for (const auto& target : lg->GetGeneratorTargets()) {
       projectType =
-        CollectSourceFiles(makefile, target.get(), cFiles, otherFiles);
+        this->CollectSourceFiles(makefile, target.get(), cFiles, otherFiles);
     }
   }
 
@@ -276,8 +276,8 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
   // their relative path)
   std::string projectPath = cmSystemTools::GetFilenamePath(filename);
 
-  CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
-                             projectType, "");
+  this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
+                                   projectType, "");
 
   xml.EndElement(); // CodeLite_Project
 }
@@ -402,7 +402,7 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries(
   const std::string& projectType, const std::string& targetName)
 {
   cmXMLWriter& xml(*_xml);
-  FindMatchingHeaderfiles(cFiles, otherFiles);
+  this->FindMatchingHeaderfiles(cFiles, otherFiles);
   // Create 2 virtual folders: src and include
   // and place all the implementation files into the src
   // folder, the rest goes to the include folder
@@ -498,10 +498,10 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries(
 
   xml.StartElement("CustomBuild");
   xml.Attribute("Enabled", "yes");
-  xml.Element("RebuildCommand", GetRebuildCommand(mf, targetName));
-  xml.Element("CleanCommand", GetCleanCommand(mf, targetName));
-  xml.Element("BuildCommand", GetBuildCommand(mf, targetName));
-  xml.Element("SingleFileCommand", GetSingleFileBuildCommand(mf));
+  xml.Element("RebuildCommand", this->GetRebuildCommand(mf, targetName));
+  xml.Element("CleanCommand", this->GetCleanCommand(mf, targetName));
+  xml.Element("BuildCommand", this->GetBuildCommand(mf, targetName));
+  xml.Element("SingleFileCommand", this->GetSingleFileBuildCommand(mf));
   xml.Element("PreprocessFileCommand");
   xml.Element("WorkingDirectory", "$(WorkspacePath)");
   xml.EndElement(); // CustomBuild
@@ -570,14 +570,14 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile(
   std::map<std::string, cmSourceFile*> cFiles;
   std::set<std::string> otherFiles;
 
-  projectType = CollectSourceFiles(mf, gt, cFiles, otherFiles);
+  projectType = this->CollectSourceFiles(mf, gt, cFiles, otherFiles);
 
   // Get the project path ( we need it later to convert files to
   // their relative path)
   std::string projectPath = cmSystemTools::GetFilenamePath(filename);
 
-  CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
-                             projectType, targetName);
+  this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
+                                   projectType, targetName);
 
   xml.EndElement(); // CodeLite_Project
 }
@@ -648,7 +648,7 @@ std::string cmExtraCodeLiteGenerator::GetCleanCommand(
 {
   std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
   std::ostringstream ss;
-  std::string buildcommand = GetBuildCommand(mf, "");
+  std::string buildcommand = this->GetBuildCommand(mf, "");
   if (!targetName.empty() && generator == "Ninja") {
     ss << buildcommand << " -t clean " << targetName;
   } else {
@@ -660,8 +660,8 @@ std::string cmExtraCodeLiteGenerator::GetCleanCommand(
 std::string cmExtraCodeLiteGenerator::GetRebuildCommand(
   const cmMakefile* mf, const std::string& targetName) const
 {
-  return GetCleanCommand(mf, targetName) + " && " +
-    GetBuildCommand(mf, targetName);
+  return this->GetCleanCommand(mf, targetName) + " && " +
+    this->GetBuildCommand(mf, targetName);
 }
 
 std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand(
index 2478585..2bb1c04 100644 (file)
@@ -24,7 +24,6 @@ protected:
   std::string WorkspacePath;
   unsigned int CpuCount = 2;
 
-protected:
   std::string GetCodeLiteCompilerName(const cmMakefile* mf) const;
   std::string GetConfigurationName(const cmMakefile* mf) const;
   std::string GetBuildCommand(const cmMakefile* mf,
index 7c36144..a92f6e3 100644 (file)
@@ -132,7 +132,7 @@ void cmExtraSublimeTextGenerator::CreateNewProjectFile(
   // doesn't currently support these settings per build system, only project
   // wide
   MapSourceFileFlags sourceFileFlags;
-  AppendAllTargets(lgs, mf, fout, sourceFileFlags);
+  this->AppendAllTargets(lgs, mf, fout, sourceFileFlags);
 
   // End of build_systems
   fout << "\n\t]";
@@ -349,6 +349,11 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
   if (language.empty()) {
     language = "C";
   }
+
+  // Explicitly add the explicit language flag before any other flag
+  // so user flags can override it.
+  gtgt->AddExplicitLanguageFlags(flags, *source);
+
   std::string const& config =
     lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
 
index d88617a..77d5795 100644 (file)
@@ -10,6 +10,7 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
@@ -98,9 +99,11 @@ bool cmFLTKWrapUICommand(std::vector<std::string> const& args,
       const char* no_comment = nullptr;
       const char* no_working_dir = nullptr;
       mf.AddCustomCommandToOutput(cxxres, depends, no_main_dependency,
-                                  commandLines, no_comment, no_working_dir);
+                                  commandLines, no_comment, no_working_dir,
+                                  mf.GetPolicyStatus(cmPolicies::CMP0116));
       mf.AddCustomCommandToOutput(hname, depends, no_main_dependency,
-                                  commandLines, no_comment, no_working_dir);
+                                  commandLines, no_comment, no_working_dir,
+                                  mf.GetPolicyStatus(cmPolicies::CMP0116));
 
       cmSourceFile* sf = mf.GetSource(cxxres);
       sf->AddDepend(hname);
index c2ab2f1..d2a9bec 100644 (file)
@@ -18,6 +18,7 @@
 #include "cmFileAPICMakeFiles.h"
 #include "cmFileAPICache.h"
 #include "cmFileAPICodemodel.h"
+#include "cmFileAPIToolchains.h"
 #include "cmGlobalGenerator.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -262,6 +263,17 @@ bool cmFileAPI::ReadQuery(std::string const& query,
     objects.push_back(o);
     return true;
   }
+  if (kindName == ObjectKindName(ObjectKind::Toolchains)) {
+    Object o;
+    o.Kind = ObjectKind::Toolchains;
+    if (verStr == "v1") {
+      o.Version = 1;
+    } else {
+      return false;
+    }
+    objects.push_back(o);
+    return true;
+  }
   if (kindName == ObjectKindName(ObjectKind::InternalTest)) {
     Object o;
     o.Kind = ObjectKind::InternalTest;
@@ -402,6 +414,7 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind)
     "codemodel",  //
     "cache",      //
     "cmakeFiles", //
+    "toolchains", //
     "__test"      //
   };
   return objectKindNames[size_t(kind)];
@@ -435,6 +448,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object)
     case ObjectKind::CMakeFiles:
       value = this->BuildCMakeFiles(object);
       break;
+    case ObjectKind::Toolchains:
+      value = this->BuildToolchains(object);
+      break;
     case ObjectKind::InternalTest:
       value = this->BuildInternalTest(object);
       break;
@@ -491,6 +507,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
     r.Kind = ObjectKind::Cache;
   } else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) {
     r.Kind = ObjectKind::CMakeFiles;
+  } else if (kindName == this->ObjectKindName(ObjectKind::Toolchains)) {
+    r.Kind = ObjectKind::Toolchains;
   } else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
     r.Kind = ObjectKind::InternalTest;
   } else {
@@ -518,6 +536,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
     case ObjectKind::CMakeFiles:
       this->BuildClientRequestCMakeFiles(r, versions);
       break;
+    case ObjectKind::Toolchains:
+      this->BuildClientRequestToolchains(r, versions);
+      break;
     case ObjectKind::InternalTest:
       this->BuildClientRequestInternalTest(r, versions);
       break;
@@ -765,6 +786,40 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
   return cmakeFiles;
 }
 
+// The "toolchains" object kind.
+
+static unsigned int const ToolchainsV1Minor = 0;
+
+void cmFileAPI::BuildClientRequestToolchains(
+  ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+  // Select a known version from those requested.
+  for (RequestVersion const& v : versions) {
+    if ((v.Major == 1 && v.Minor <= ToolchainsV1Minor)) {
+      r.Version = v.Major;
+      break;
+    }
+  }
+  if (!r.Version) {
+    r.Error = NoSupportedVersion(versions);
+  }
+}
+
+Json::Value cmFileAPI::BuildToolchains(Object const& object)
+{
+  Json::Value toolchains = cmFileAPIToolchainsDump(*this, object.Version);
+  toolchains["kind"] = this->ObjectKindName(object.Kind);
+
+  Json::Value& version = toolchains["version"];
+  if (object.Version == 1) {
+    version = BuildVersion(1, ToolchainsV1Minor);
+  } else {
+    return toolchains; // should be unreachable
+  }
+
+  return toolchains;
+}
+
 // The "__test" object kind is for internal testing of CMake.
 
 static unsigned int const InternalTestV1Minor = 3;
@@ -828,5 +883,13 @@ Json::Value cmFileAPI::ReportCapabilities()
     requests.append(std::move(request)); // NOLINT(*)
   }
 
+  {
+    Json::Value request = Json::objectValue;
+    request["kind"] = ObjectKindName(ObjectKind::Toolchains);
+    Json::Value& versions = request["version"] = Json::arrayValue;
+    versions.append(BuildVersion(1, ToolchainsV1Minor));
+    requests.append(std::move(request)); // NOLINT(*)
+  }
+
   return capabilities;
 }
index 086a92a..22302b4 100644 (file)
@@ -56,6 +56,7 @@ private:
     CodeModel,
     Cache,
     CMakeFiles,
+    Toolchains,
     InternalTest
   };
 
@@ -200,6 +201,10 @@ private:
     ClientRequest& r, std::vector<RequestVersion> const& versions);
   Json::Value BuildCMakeFiles(Object const& object);
 
+  void BuildClientRequestToolchains(
+    ClientRequest& r, std::vector<RequestVersion> const& versions);
+  Json::Value BuildToolchains(Object const& object);
+
   void BuildClientRequestInternalTest(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
   Json::Value BuildInternalTest(Object const& object);
index 1e4f3b6..e208ca8 100644 (file)
@@ -41,7 +41,7 @@ CMakeFiles::CMakeFiles(cmFileAPI& fileAPI, unsigned long version)
   , CMakeModules(cmSystemTools::GetCMakeRoot() + "/Modules")
   , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
   , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
-  , OutOfSource(TopBuild != TopSource)
+  , OutOfSource(this->TopBuild != this->TopSource)
 {
   static_cast<void>(this->Version);
 }
@@ -50,7 +50,7 @@ Json::Value CMakeFiles::Dump()
 {
   Json::Value cmakeFiles = Json::objectValue;
   cmakeFiles["paths"] = this->DumpPaths();
-  cmakeFiles["inputs"] = DumpInputs();
+  cmakeFiles["inputs"] = this->DumpInputs();
   return cmakeFiles;
 }
 
index 3ba943a..ddae527 100644 (file)
@@ -44,7 +44,7 @@ Cache::Cache(cmFileAPI& fileAPI, unsigned long version)
 Json::Value Cache::Dump()
 {
   Json::Value cache = Json::objectValue;
-  cache["entries"] = DumpEntries();
+  cache["entries"] = this->DumpEntries();
   return cache;
 }
 
index 4a53c8a..9061109 100644 (file)
@@ -145,7 +145,7 @@ class JBTIndex
 {
 public:
   JBTIndex() = default;
-  explicit operator bool() const { return Index != None; }
+  explicit operator bool() const { return this->Index != None; }
   Json::ArrayIndex Index = None;
   static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1);
 };
@@ -1324,7 +1324,7 @@ Json::Value Target::DumpInstallDestinations()
 {
   Json::Value destinations = Json::arrayValue;
   auto installGens = this->GT->Target->GetInstallGenerators();
-  for (auto itGen : installGens) {
+  for (auto* itGen : installGens) {
     destinations.append(this->DumpInstallDestination(itGen));
   }
   return destinations;
diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx
new file mode 100644 (file)
index 0000000..722c114
--- /dev/null
@@ -0,0 +1,151 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmFileAPIToolchains.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm3p/json/value.h>
+
+#include "cmFileAPI.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+namespace {
+
+struct ToolchainVariable
+{
+  std::string ObjectKey;
+  std::string VariableSuffix;
+  bool IsList;
+};
+
+class Toolchains
+{
+  cmFileAPI& FileAPI;
+  unsigned long Version;
+
+  static const std::vector<ToolchainVariable> CompilerVariables;
+  static const std::vector<ToolchainVariable> CompilerImplicitVariables;
+  static const ToolchainVariable SourceFileExtensionsVariable;
+
+  Json::Value DumpToolchains();
+  Json::Value DumpToolchain(std::string const& lang);
+  Json::Value DumpToolchainVariables(
+    cmMakefile const* mf, std::string const& lang,
+    std::vector<ToolchainVariable> const& variables);
+  void DumpToolchainVariable(cmMakefile const* mf, Json::Value& object,
+                             std::string const& lang,
+                             ToolchainVariable const& variable);
+
+public:
+  Toolchains(cmFileAPI& fileAPI, unsigned long version);
+  Json::Value Dump();
+};
+
+const std::vector<ToolchainVariable> Toolchains::CompilerVariables{
+  { "path", "COMPILER", false },
+  { "id", "COMPILER_ID", false },
+  { "version", "COMPILER_VERSION", false },
+  { "target", "COMPILER_TARGET", false },
+};
+
+const std::vector<ToolchainVariable> Toolchains::CompilerImplicitVariables{
+  { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true },
+  { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true },
+  { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", true },
+  { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true },
+};
+
+const ToolchainVariable Toolchains::SourceFileExtensionsVariable{
+  "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true
+};
+
+Toolchains::Toolchains(cmFileAPI& fileAPI, unsigned long version)
+  : FileAPI(fileAPI)
+  , Version(version)
+{
+  static_cast<void>(this->Version);
+}
+
+Json::Value Toolchains::Dump()
+{
+  Json::Value toolchains = Json::objectValue;
+  toolchains["toolchains"] = this->DumpToolchains();
+  return toolchains;
+}
+
+Json::Value Toolchains::DumpToolchains()
+{
+  Json::Value toolchains = Json::arrayValue;
+
+  for (std::string const& lang :
+       this->FileAPI.GetCMakeInstance()->GetState()->GetEnabledLanguages()) {
+    toolchains.append(this->DumpToolchain(lang));
+  }
+
+  return toolchains;
+}
+
+Json::Value Toolchains::DumpToolchain(std::string const& lang)
+{
+  const auto& mf =
+    this->FileAPI.GetCMakeInstance()->GetGlobalGenerator()->GetMakefiles()[0];
+  Json::Value toolchain = Json::objectValue;
+  toolchain["language"] = lang;
+  toolchain["compiler"] =
+    this->DumpToolchainVariables(mf.get(), lang, CompilerVariables);
+  toolchain["compiler"]["implicit"] =
+    this->DumpToolchainVariables(mf.get(), lang, CompilerImplicitVariables);
+  this->DumpToolchainVariable(mf.get(), toolchain, lang,
+                              SourceFileExtensionsVariable);
+  return toolchain;
+}
+
+Json::Value Toolchains::DumpToolchainVariables(
+  cmMakefile const* mf, std::string const& lang,
+  std::vector<ToolchainVariable> const& variables)
+{
+  Json::Value object = Json::objectValue;
+  for (const auto& variable : variables) {
+    this->DumpToolchainVariable(mf, object, lang, variable);
+  }
+  return object;
+}
+
+void Toolchains::DumpToolchainVariable(cmMakefile const* mf,
+                                       Json::Value& object,
+                                       std::string const& lang,
+                                       ToolchainVariable const& variable)
+{
+  std::string const variableName =
+    cmStrCat("CMAKE_", lang, "_", variable.VariableSuffix);
+
+  if (variable.IsList) {
+    std::vector<std::string> values;
+    if (mf->GetDefExpandList(variableName, values)) {
+      Json::Value jsonArray = Json::arrayValue;
+      for (std::string const& value : values) {
+        jsonArray.append(value);
+      }
+      object[variable.ObjectKey] = jsonArray;
+    }
+  } else {
+    cmProp def = mf->GetDefinition(variableName);
+    if (def) {
+      object[variable.ObjectKey] = *def;
+    }
+  }
+}
+}
+
+Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI, unsigned long version)
+{
+  Toolchains toolchains(fileAPI, version);
+  return toolchains.Dump();
+}
diff --git a/Source/cmFileAPIToolchains.h b/Source/cmFileAPIToolchains.h
new file mode 100644 (file)
index 0000000..c188807
--- /dev/null
@@ -0,0 +1,12 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <cm3p/json/value.h>
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI,
+                                           unsigned long version);
index 8a3aad2..f674833 100644 (file)
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
@@ -63,7 +64,7 @@
 #  include "cmFileLockResult.h"
 #endif
 
-#if defined(CMAKE_USE_ELF_PARSER)
+#if defined(CMake_USE_ELF_PARSER)
 #  include "cmELF.h"
 #endif
 
@@ -333,7 +334,7 @@ bool HandleStringsCommand(std::vector<std::string> const& args,
     arg_limit_count,
     arg_length_minimum,
     arg_length_maximum,
-    arg__maximum,
+    arg_maximum,
     arg_regex,
     arg_encoding
   };
@@ -557,8 +558,7 @@ bool HandleStringsCommand(std::vector<std::string> const& args,
       // back subsequent characters
       if ((current_str.length() != num_utf8_bytes)) {
         for (unsigned int j = 0; j < current_str.size() - 1; j++) {
-          c = current_str[current_str.size() - 1 - j];
-          fin.putback(static_cast<char>(c));
+          fin.putback(current_str[current_str.size() - 1 - j]);
         }
         current_str.clear();
       }
@@ -1198,7 +1198,7 @@ bool HandleReadElfCommand(std::vector<std::string> const& args,
     return false;
   }
 
-#if defined(CMAKE_USE_ELF_PARSER)
+#if defined(CMake_USE_ELF_PARSER)
   cmELF elf(fileNameArg.c_str());
 
   if (!arguments.RPath.empty()) {
@@ -2290,6 +2290,7 @@ void AddEvaluationFile(const std::string& inputName,
                        const std::string& targetName,
                        const std::string& outputExpr,
                        const std::string& condition, bool inputIsContent,
+                       const std::string& newLineCharacter, mode_t permissions,
                        cmExecutionStatus& status)
 {
   cmListFileBacktrace lfbt = status.GetMakefile().GetBacktrace();
@@ -2304,7 +2305,7 @@ void AddEvaluationFile(const std::string& inputName,
 
   status.GetMakefile().AddEvaluationFile(
     inputName, targetName, std::move(outputCge), std::move(conditionCge),
-    inputIsContent);
+    newLineCharacter, permissions, inputIsContent);
 }
 
 bool HandleGenerateCommand(std::vector<std::string> const& args,
@@ -2314,49 +2315,171 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
     status.SetError("Incorrect arguments to GENERATE subcommand.");
     return false;
   }
-  if (args[1] != "OUTPUT") {
+
+  struct Arguments
+  {
+    std::string Output;
+    std::string Input;
+    std::string Content;
+    std::string Condition;
+    std::string Target;
+    std::string NewLineStyle;
+    bool NoSourcePermissions = false;
+    bool UseSourcePermissions = false;
+    std::vector<std::string> FilePermissions;
+  };
+
+  static auto const parser =
+    cmArgumentParser<Arguments>{}
+      .Bind("OUTPUT"_s, &Arguments::Output)
+      .Bind("INPUT"_s, &Arguments::Input)
+      .Bind("CONTENT"_s, &Arguments::Content)
+      .Bind("CONDITION"_s, &Arguments::Condition)
+      .Bind("TARGET"_s, &Arguments::Target)
+      .Bind("NO_SOURCE_PERMISSIONS"_s, &Arguments::NoSourcePermissions)
+      .Bind("USE_SOURCE_PERMISSIONS"_s, &Arguments::UseSourcePermissions)
+      .Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions)
+      .Bind("NEWLINE_STYLE"_s, &Arguments::NewLineStyle);
+
+  std::vector<std::string> unparsedArguments;
+  std::vector<std::string> keywordsMissingValues;
+  std::vector<std::string> parsedKeywords;
+  Arguments const arguments =
+    parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments,
+                 &keywordsMissingValues, &parsedKeywords);
+
+  if (!keywordsMissingValues.empty()) {
+    status.SetError("Incorrect arguments to GENERATE subcommand.");
+    return false;
+  }
+
+  if (!unparsedArguments.empty()) {
+    status.SetError("Unknown argument to GENERATE subcommand.");
+    return false;
+  }
+
+  bool mandatoryOptionsSpecified = false;
+  if (parsedKeywords.size() > 1) {
+    const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s;
+    const bool inputOrContentSpecified =
+      parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s;
+    if (outputOprionSpecified && inputOrContentSpecified) {
+      mandatoryOptionsSpecified = true;
+    }
+  }
+  if (!mandatoryOptionsSpecified) {
     status.SetError("Incorrect arguments to GENERATE subcommand.");
     return false;
   }
 
-  std::string condition;
-  std::string target;
+  const bool conditionOptionSpecified =
+    std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) !=
+    parsedKeywords.end();
+  if (conditionOptionSpecified && arguments.Condition.empty()) {
+    status.SetError("CONDITION of sub-command GENERATE must not be empty "
+                    "if specified.");
+    return false;
+  }
 
-  for (std::size_t i = 5; i < args.size();) {
-    const std::string& arg = args[i++];
+  const bool targetOptionSpecified =
+    std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) !=
+    parsedKeywords.end();
+  if (targetOptionSpecified && arguments.Target.empty()) {
+    status.SetError("TARGET of sub-command GENERATE must not be empty "
+                    "if specified.");
+    return false;
+  }
+
+  const bool outputOptionSpecified =
+    std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) !=
+    parsedKeywords.end();
+  if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) {
+    status.SetError("Incorrect arguments to GENERATE subcommand.");
+    return false;
+  }
 
-    if (args.size() - i == 0) {
-      status.SetError("Incorrect arguments to GENERATE subcommand.");
+  const bool inputIsContent = parsedKeywords[1] != "INPUT"_s;
+  if (inputIsContent && parsedKeywords[1] != "CONTENT") {
+    status.SetError("Unknown argument to GENERATE subcommand.");
+  }
+
+  const bool newLineStyleSpecified =
+    std::find(parsedKeywords.begin(), parsedKeywords.end(),
+              "NEWLINE_STYLE"_s) != parsedKeywords.end();
+  cmNewLineStyle newLineStyle;
+  if (newLineStyleSpecified) {
+    std::string errorMessage;
+    if (!newLineStyle.ReadFromArguments(args, errorMessage)) {
+      status.SetError(cmStrCat("GENERATE ", errorMessage));
       return false;
     }
+  }
 
-    const std::string& value = args[i++];
+  std::string input = arguments.Input;
+  if (inputIsContent) {
+    input = arguments.Content;
+  }
 
-    if (value.empty()) {
-      status.SetError(
-        arg + " of sub-command GENERATE must not be empty if specified.");
+  if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) {
+    status.SetError("given both NO_SOURCE_PERMISSIONS and "
+                    "USE_SOURCE_PERMISSIONS. Only one option allowed.");
+    return false;
+  }
+
+  if (!arguments.FilePermissions.empty()) {
+    if (arguments.NoSourcePermissions) {
+      status.SetError("given both NO_SOURCE_PERMISSIONS and "
+                      "FILE_PERMISSIONS. Only one option allowed.");
+      return false;
+    }
+    if (arguments.UseSourcePermissions) {
+      status.SetError("given both USE_SOURCE_PERMISSIONS and "
+                      "FILE_PERMISSIONS. Only one option allowed.");
       return false;
     }
+  }
 
-    if (arg == "CONDITION") {
-      condition = value;
-    } else if (arg == "TARGET") {
-      target = value;
-    } else {
-      status.SetError("Unknown argument to GENERATE subcommand.");
+  if (arguments.UseSourcePermissions) {
+    if (inputIsContent) {
+      status.SetError("given USE_SOURCE_PERMISSIONS without a file INPUT.");
       return false;
     }
   }
 
-  std::string output = args[2];
-  const bool inputIsContent = args[3] != "INPUT";
-  if (inputIsContent && args[3] != "CONTENT") {
-    status.SetError("Incorrect arguments to GENERATE subcommand.");
-    return false;
+  mode_t permisiions = 0;
+  if (arguments.NoSourcePermissions) {
+    permisiions |= cmFSPermissions::mode_owner_read;
+    permisiions |= cmFSPermissions::mode_owner_write;
+    permisiions |= cmFSPermissions::mode_group_read;
+    permisiions |= cmFSPermissions::mode_world_read;
   }
-  std::string input = args[4];
 
-  AddEvaluationFile(input, target, output, condition, inputIsContent, status);
+  if (!arguments.FilePermissions.empty()) {
+    std::vector<std::string> invalidOptions;
+    for (auto const& e : arguments.FilePermissions) {
+      if (!cmFSPermissions::stringToModeT(e, permisiions)) {
+        invalidOptions.push_back(e);
+      }
+    }
+    if (!invalidOptions.empty()) {
+      std::ostringstream oss;
+      oss << "given invalid permission ";
+      for (auto i = 0u; i < invalidOptions.size(); i++) {
+        if (i == 0u) {
+          oss << "\"" << invalidOptions[i] << "\"";
+        } else {
+          oss << ",\"" << invalidOptions[i] << "\"";
+        }
+      }
+      oss << ".";
+      status.SetError(oss.str());
+      return false;
+    }
+  }
+
+  AddEvaluationFile(input, arguments.Target, arguments.Output,
+                    arguments.Condition, inputIsContent,
+                    newLineStyle.GetCharacters(), permisiions, status);
   return true;
 }
 
@@ -2902,17 +3025,60 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
 bool HandleConfigureCommand(std::vector<std::string> const& args,
                             cmExecutionStatus& status)
 {
-  if (args.size() < 5) {
-    status.SetError("Incorrect arguments to CONFIGURE subcommand.");
+  struct Arguments
+  {
+    std::string Output;
+    std::string Content;
+    bool EscapeQuotes = false;
+    bool AtOnly = false;
+    std::string NewlineStyle;
+  };
+
+  static auto const parser =
+    cmArgumentParser<Arguments>{}
+      .Bind("OUTPUT"_s, &Arguments::Output)
+      .Bind("CONTENT"_s, &Arguments::Content)
+      .Bind("ESCAPE_QUOTES"_s, &Arguments::EscapeQuotes)
+      .Bind("@ONLY"_s, &Arguments::AtOnly)
+      .Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle);
+
+  std::vector<std::string> unrecognizedArguments;
+  std::vector<std::string> keywordsMissingArguments;
+  std::vector<std::string> parsedKeywords;
+  auto parsedArgs =
+    parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+                 &keywordsMissingArguments, &parsedKeywords);
+
+  auto argIt = unrecognizedArguments.begin();
+  if (argIt != unrecognizedArguments.end()) {
+    status.SetError(
+      cmStrCat("CONFIGURE Unrecognized argument: \"", *argIt, "\""));
+    cmSystemTools::SetFatalErrorOccured();
     return false;
   }
-  if (args[1] != "OUTPUT") {
-    status.SetError("Incorrect arguments to CONFIGURE subcommand.");
-    return false;
+
+  std::vector<std::string> mandatoryOptions{ "OUTPUT", "CONTENT" };
+  for (auto const& e : mandatoryOptions) {
+    const bool optionHasNoValue =
+      std::find(keywordsMissingArguments.begin(),
+                keywordsMissingArguments.end(),
+                e) != keywordsMissingArguments.end();
+    if (optionHasNoValue) {
+      status.SetError(cmStrCat("CONFIGURE ", e, " option needs a value."));
+      cmSystemTools::SetFatalErrorOccured();
+      return false;
+    }
   }
-  if (args[3] != "CONTENT") {
-    status.SetError("Incorrect arguments to CONFIGURE subcommand.");
-    return false;
+
+  for (auto const& e : mandatoryOptions) {
+    const bool optionGiven =
+      std::find(parsedKeywords.begin(), parsedKeywords.end(), e) !=
+      parsedKeywords.end();
+    if (!optionGiven) {
+      status.SetError(cmStrCat("CONFIGURE ", e, " option is mandatory."));
+      cmSystemTools::SetFatalErrorOccured();
+      return false;
+    }
   }
 
   std::string errorMessage;
@@ -2922,28 +3088,9 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
     return false;
   }
 
-  bool escapeQuotes = false;
-  bool atOnly = false;
-  for (unsigned int i = 5; i < args.size(); ++i) {
-    if (args[i] == "@ONLY") {
-      atOnly = true;
-    } else if (args[i] == "ESCAPE_QUOTES") {
-      escapeQuotes = true;
-    } else if (args[i] == "NEWLINE_STYLE" || args[i] == "LF" ||
-               args[i] == "UNIX" || args[i] == "CRLF" || args[i] == "WIN32" ||
-               args[i] == "DOS") {
-      /* Options handled by NewLineStyle member above.  */
-    } else {
-      status.SetError(
-        cmStrCat("CONFIGURE Unrecognized argument \"", args[i], "\""));
-      return false;
-    }
-  }
-
   // Check for generator expressions
-  const std::string input = args[4];
   std::string outputFile = cmSystemTools::CollapseFullPath(
-    args[2], status.GetMakefile().GetCurrentBinaryDirectory());
+    parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory());
 
   std::string::size_type pos = outputFile.find_first_of("<>");
   if (pos != std::string::npos) {
@@ -2974,11 +3121,11 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
     cmSystemTools::MakeDirectory(path);
   }
 
-  std::string newLineCharacters;
+  std::string newLineCharacters = "\n";
   bool open_with_binary_flag = false;
   if (newLineStyle.IsValid()) {
-    open_with_binary_flag = true;
     newLineCharacters = newLineStyle.GetCharacters();
+    open_with_binary_flag = true;
   }
 
   cmGeneratedFileStream fout;
@@ -2992,13 +3139,18 @@ bool HandleConfigureCommand(std::vector<std::string> const& args,
   fout.SetCopyIfDifferent(true);
 
   // copy input to output and expand variables from input at the same time
-  std::stringstream sin(input, std::ios::in);
+  std::stringstream sin(parsedArgs.Content, std::ios::in);
   std::string inLine;
   std::string outLine;
-  while (cmSystemTools::GetLineFromStream(sin, inLine)) {
+  bool hasNewLine = false;
+  while (cmSystemTools::GetLineFromStream(sin, inLine, &hasNewLine)) {
     outLine.clear();
-    makeFile.ConfigureString(inLine, outLine, atOnly, escapeQuotes);
-    fout << outLine << newLineCharacters;
+    makeFile.ConfigureString(inLine, outLine, parsedArgs.AtOnly,
+                             parsedArgs.EscapeQuotes);
+    fout << outLine;
+    if (hasNewLine || newLineStyle.IsValid()) {
+      fout << newLineCharacters;
+    }
   }
 
   // close file before attempting to copy
index 6010233..5d197d2 100644 (file)
@@ -80,7 +80,9 @@ bool cmFileLock::IsLocked(const std::string& filename) const
 }
 
 #if defined(_WIN32)
+// NOLINTNEXTLINE(bugprone-suspicious-include)
 #  include "cmFileLockWin32.cxx"
 #else
+// NOLINTNEXTLINE(bugprone-suspicious-include)
 #  include "cmFileLockUnix.cxx"
 #endif
index 2b125af..94baea1 100644 (file)
@@ -57,7 +57,7 @@ private:
   BOOL LockFile(DWORD flags);
 #else
   int File = -1;
-  int LockFile(int cmd, int type);
+  int LockFile(int cmd, int type) const;
 #endif
 
   std::string Filename;
index e1f6e94..99f6885 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmFileLockPool.h"
 
+#include <algorithm>
 #include <cassert>
 #include <utility>
 
@@ -145,10 +146,8 @@ cmFileLockResult cmFileLockPool::ScopePool::Release(
 bool cmFileLockPool::ScopePool::IsAlreadyLocked(
   const std::string& filename) const
 {
-  for (auto const& lock : this->Locks) {
-    if (lock.IsLocked(filename)) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(this->Locks.begin(), this->Locks.end(),
+                     [&filename](cmFileLock const& lock) -> bool {
+                       return lock.IsLocked(filename);
+                     });
 }
index 1456ea8..613c6ee 100644 (file)
@@ -64,7 +64,7 @@ cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds)
   }
 }
 
-int cmFileLock::LockFile(int cmd, int type)
+int cmFileLock::LockFile(int cmd, int type) const
 {
   struct ::flock lock;
   lock.l_start = 0;
diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx
deleted file mode 100644 (file)
index 8cfdb2d..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmFileMonitor.h"
-
-#include <cassert>
-#include <cstddef>
-#include <unordered_map>
-#include <utility>
-
-#include <cm/memory>
-
-#include "cmsys/SystemTools.hxx"
-
-namespace {
-void on_directory_change(uv_fs_event_t* handle, const char* filename,
-                         int events, int status);
-void on_fs_close(uv_handle_t* handle);
-} // namespace
-
-class cmIBaseWatcher
-{
-public:
-  virtual ~cmIBaseWatcher() = default;
-
-  virtual void Trigger(const std::string& pathSegment, int events,
-                       int status) const = 0;
-  virtual std::string Path() const = 0;
-  virtual uv_loop_t* Loop() const = 0;
-
-  virtual void StartWatching() = 0;
-  virtual void StopWatching() = 0;
-
-  virtual std::vector<std::string> WatchedFiles() const = 0;
-  virtual std::vector<std::string> WatchedDirectories() const = 0;
-};
-
-class cmVirtualDirectoryWatcher : public cmIBaseWatcher
-{
-public:
-  ~cmVirtualDirectoryWatcher() override = default;
-
-  cmIBaseWatcher* Find(const std::string& ps)
-  {
-    const auto i = this->Children.find(ps);
-    return (i == this->Children.end()) ? nullptr : i->second.get();
-  }
-
-  void Trigger(const std::string& pathSegment, int events,
-               int status) const final
-  {
-    if (pathSegment.empty()) {
-      for (auto const& child : this->Children) {
-        child.second->Trigger(std::string(), events, status);
-      }
-    } else {
-      const auto i = this->Children.find(pathSegment);
-      if (i != this->Children.end()) {
-        i->second->Trigger(std::string(), events, status);
-      }
-    }
-  }
-
-  void StartWatching() override
-  {
-    for (auto const& child : this->Children) {
-      child.second->StartWatching();
-    }
-  }
-
-  void StopWatching() override
-  {
-    for (auto const& child : this->Children) {
-      child.second->StopWatching();
-    }
-  }
-
-  std::vector<std::string> WatchedFiles() const final
-  {
-    std::vector<std::string> result;
-    for (auto const& child : this->Children) {
-      for (std::string const& f : child.second->WatchedFiles()) {
-        result.push_back(f);
-      }
-    }
-    return result;
-  }
-
-  std::vector<std::string> WatchedDirectories() const override
-  {
-    std::vector<std::string> result;
-    for (auto const& child : this->Children) {
-      for (std::string const& dir : child.second->WatchedDirectories()) {
-        result.push_back(dir);
-      }
-    }
-    return result;
-  }
-
-  void Reset() { this->Children.clear(); }
-
-  void AddChildWatcher(const std::string& ps, cmIBaseWatcher* watcher)
-  {
-    assert(!ps.empty());
-    assert(this->Children.find(ps) == this->Children.end());
-    assert(watcher);
-
-    this->Children.emplace(ps, std::unique_ptr<cmIBaseWatcher>(watcher));
-  }
-
-private:
-  std::unordered_map<std::string, std::unique_ptr<cmIBaseWatcher>>
-    Children; // owned!
-};
-
-// Root of all the different (on windows!) root directories:
-class cmRootWatcher : public cmVirtualDirectoryWatcher
-{
-public:
-  cmRootWatcher(uv_loop_t* loop)
-    : mLoop(loop)
-  {
-    assert(loop);
-  }
-
-  std::string Path() const final
-  {
-    assert(false);
-    return std::string();
-  }
-  uv_loop_t* Loop() const final { return this->mLoop; }
-
-private:
-  uv_loop_t* const mLoop; // no ownership!
-};
-
-// Real directories:
-class cmRealDirectoryWatcher : public cmVirtualDirectoryWatcher
-{
-public:
-  cmRealDirectoryWatcher(cmVirtualDirectoryWatcher* p, const std::string& ps)
-    : Parent(p)
-    , PathSegment(ps)
-  {
-    assert(p);
-    assert(!ps.empty());
-
-    p->AddChildWatcher(ps, this);
-  }
-
-  void StartWatching() final
-  {
-    if (!this->Handle) {
-      this->Handle = new uv_fs_event_t;
-
-      uv_fs_event_init(this->Loop(), this->Handle);
-      this->Handle->data = this;
-      uv_fs_event_start(this->Handle, &on_directory_change, Path().c_str(), 0);
-    }
-    cmVirtualDirectoryWatcher::StartWatching();
-  }
-
-  void StopWatching() final
-  {
-    if (this->Handle) {
-      uv_fs_event_stop(this->Handle);
-      if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(this->Handle))) {
-        uv_close(reinterpret_cast<uv_handle_t*>(this->Handle), &on_fs_close);
-      }
-      this->Handle = nullptr;
-    }
-    cmVirtualDirectoryWatcher::StopWatching();
-  }
-
-  uv_loop_t* Loop() const final { return this->Parent->Loop(); }
-
-  std::vector<std::string> WatchedDirectories() const override
-  {
-    std::vector<std::string> result = { Path() };
-    for (std::string const& dir :
-         cmVirtualDirectoryWatcher::WatchedDirectories()) {
-      result.push_back(dir);
-    }
-    return result;
-  }
-
-protected:
-  cmVirtualDirectoryWatcher* const Parent;
-  const std::string PathSegment;
-
-private:
-  uv_fs_event_t* Handle = nullptr; // owner!
-};
-
-// Root directories:
-class cmRootDirectoryWatcher : public cmRealDirectoryWatcher
-{
-public:
-  cmRootDirectoryWatcher(cmRootWatcher* p, const std::string& ps)
-    : cmRealDirectoryWatcher(p, ps)
-  {
-  }
-
-  std::string Path() const final { return this->PathSegment; }
-};
-
-// Normal directories below root:
-class cmDirectoryWatcher : public cmRealDirectoryWatcher
-{
-public:
-  cmDirectoryWatcher(cmRealDirectoryWatcher* p, const std::string& ps)
-    : cmRealDirectoryWatcher(p, ps)
-  {
-  }
-
-  std::string Path() const final
-  {
-    return this->Parent->Path() + this->PathSegment + "/";
-  }
-};
-
-class cmFileWatcher : public cmIBaseWatcher
-{
-public:
-  cmFileWatcher(cmRealDirectoryWatcher* p, const std::string& ps,
-                cmFileMonitor::Callback cb)
-    : Parent(p)
-    , PathSegment(ps)
-    , CbList({ std::move(cb) })
-  {
-    assert(p);
-    assert(!ps.empty());
-    p->AddChildWatcher(ps, this);
-  }
-
-  void StartWatching() final {}
-
-  void StopWatching() final {}
-
-  void AppendCallback(cmFileMonitor::Callback const& cb)
-  {
-    this->CbList.push_back(cb);
-  }
-
-  std::string Path() const final
-  {
-    return this->Parent->Path() + this->PathSegment;
-  }
-
-  std::vector<std::string> WatchedDirectories() const final { return {}; }
-
-  std::vector<std::string> WatchedFiles() const final
-  {
-    return { this->Path() };
-  }
-
-  void Trigger(const std::string& ps, int events, int status) const final
-  {
-    assert(ps.empty());
-    assert(status == 0);
-    static_cast<void>(ps);
-
-    const std::string path = this->Path();
-    for (cmFileMonitor::Callback const& cb : this->CbList) {
-      cb(path, events, status);
-    }
-  }
-
-  uv_loop_t* Loop() const final { return this->Parent->Loop(); }
-
-private:
-  cmRealDirectoryWatcher* Parent;
-  const std::string PathSegment;
-  std::vector<cmFileMonitor::Callback> CbList;
-};
-
-namespace {
-
-void on_directory_change(uv_fs_event_t* handle, const char* filename,
-                         int events, int status)
-{
-  const cmIBaseWatcher* const watcher =
-    static_cast<const cmIBaseWatcher*>(handle->data);
-  const std::string pathSegment(filename ? filename : "");
-  watcher->Trigger(pathSegment, events, status);
-}
-
-void on_fs_close(uv_handle_t* handle)
-{
-  delete reinterpret_cast<uv_fs_event_t*>(handle);
-}
-
-} // namespace
-
-cmFileMonitor::cmFileMonitor(uv_loop_t* l)
-  : Root(cm::make_unique<cmRootWatcher>(l))
-{
-}
-
-cmFileMonitor::~cmFileMonitor() = default;
-
-void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths,
-                                 Callback const& cb)
-{
-  for (std::string const& p : paths) {
-    std::vector<std::string> pathSegments;
-    cmsys::SystemTools::SplitPath(p, pathSegments, true);
-    const bool pathIsFile = !cmsys::SystemTools::FileIsDirectory(p);
-
-    const size_t segmentCount = pathSegments.size();
-    if (segmentCount < 2) { // Expect at least rootdir and filename
-      continue;
-    }
-    cmVirtualDirectoryWatcher* currentWatcher = this->Root.get();
-    for (size_t i = 0; i < segmentCount; ++i) {
-      assert(currentWatcher);
-
-      const bool fileSegment = (i == segmentCount - 1 && pathIsFile);
-      const bool rootSegment = (i == 0);
-      assert(
-        !(fileSegment &&
-          rootSegment)); // Can not be both filename and root part of the path!
-
-      const std::string& currentSegment = pathSegments[i];
-      if (currentSegment.empty()) {
-        continue;
-      }
-
-      cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment);
-      if (!nextWatcher) {
-        if (rootSegment) { // Root part
-          assert(currentWatcher == this->Root.get());
-          nextWatcher =
-            new cmRootDirectoryWatcher(this->Root.get(), currentSegment);
-          assert(currentWatcher->Find(currentSegment) == nextWatcher);
-        } else if (fileSegment) { // File part
-          assert(currentWatcher != this->Root.get());
-          nextWatcher = new cmFileWatcher(
-            dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher),
-            currentSegment, cb);
-          assert(currentWatcher->Find(currentSegment) == nextWatcher);
-        } else { // Any normal directory in between
-          nextWatcher = new cmDirectoryWatcher(
-            dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher),
-            currentSegment);
-          assert(currentWatcher->Find(currentSegment) == nextWatcher);
-        }
-      } else {
-        if (fileSegment) {
-          auto filePtr = dynamic_cast<cmFileWatcher*>(nextWatcher);
-          assert(filePtr);
-          filePtr->AppendCallback(cb);
-          continue;
-        }
-      }
-      currentWatcher = dynamic_cast<cmVirtualDirectoryWatcher*>(nextWatcher);
-    }
-  }
-  this->Root->StartWatching();
-}
-
-void cmFileMonitor::StopMonitoring()
-{
-  this->Root->StopWatching();
-  this->Root->Reset();
-}
-
-std::vector<std::string> cmFileMonitor::WatchedFiles() const
-{
-  std::vector<std::string> result;
-  if (this->Root) {
-    result = this->Root->WatchedFiles();
-  }
-  return result;
-}
-
-std::vector<std::string> cmFileMonitor::WatchedDirectories() const
-{
-  std::vector<std::string> result;
-  if (this->Root) {
-    result = this->Root->WatchedDirectories();
-  }
-  return result;
-}
diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h
deleted file mode 100644 (file)
index fc75b0c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <cm3p/uv.h>
-
-class cmRootWatcher;
-
-class cmFileMonitor
-{
-
-public:
-  cmFileMonitor(uv_loop_t* l);
-  ~cmFileMonitor();
-
-  cmFileMonitor(cmFileMonitor const&) = delete;
-  cmFileMonitor& operator=(cmFileMonitor const&) = delete;
-
-  using Callback = std::function<void(const std::string&, int, int)>;
-  void MonitorPaths(const std::vector<std::string>& paths, Callback const& cb);
-  void StopMonitoring();
-
-  std::vector<std::string> WatchedFiles() const;
-  std::vector<std::string> WatchedDirectories() const;
-
-private:
-  std::unique_ptr<cmRootWatcher> Root;
-};
index bb3f610..6b52230 100644 (file)
@@ -16,15 +16,16 @@ cmFilePathChecksum::cmFilePathChecksum(std::string const& currentSrcDir,
                                        std::string const& projectSrcDir,
                                        std::string const& projectBinDir)
 {
-  setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir);
+  this->setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir,
+                        projectBinDir);
 }
 
 cmFilePathChecksum::cmFilePathChecksum(cmMakefile* makefile)
 {
-  setupParentDirs(makefile->GetCurrentSourceDirectory(),
-                  makefile->GetCurrentBinaryDirectory(),
-                  makefile->GetHomeDirectory(),
-                  makefile->GetHomeOutputDirectory());
+  this->setupParentDirs(makefile->GetCurrentSourceDirectory(),
+                        makefile->GetCurrentBinaryDirectory(),
+                        makefile->GetHomeDirectory(),
+                        makefile->GetHomeOutputDirectory());
 }
 
 void cmFilePathChecksum::setupParentDirs(std::string const& currentSrcDir,
@@ -81,5 +82,5 @@ std::string cmFilePathChecksum::get(std::string const& filePath) const
 std::string cmFilePathChecksum::getPart(std::string const& filePath,
                                         size_t length) const
 {
-  return get(filePath).substr(0, length);
+  return this->get(filePath).substr(0, length);
 }
index d8fe24c..bd896f5 100644 (file)
@@ -62,14 +62,14 @@ public:
 cmFileTimes::cmFileTimes() = default;
 cmFileTimes::cmFileTimes(std::string const& fileName)
 {
-  Load(fileName);
+  this->Load(fileName);
 }
 cmFileTimes::~cmFileTimes() = default;
 
 bool cmFileTimes::Load(std::string const& fileName)
 {
   std::unique_ptr<Times> ptr;
-  if (IsValid()) {
+  if (this->IsValid()) {
     // Invalidate this and re-use times
     ptr.swap(this->times);
   } else {
@@ -103,7 +103,7 @@ bool cmFileTimes::Load(std::string const& fileName)
 
 bool cmFileTimes::Store(std::string const& fileName) const
 {
-  if (!IsValid()) {
+  if (!this->IsValid()) {
     return false;
   }
 
index f1916f7..50d64fd 100644 (file)
@@ -19,7 +19,7 @@ public:
   ~cmFileTimes();
 
   //! @return true, if file times were loaded successfully
-  bool IsValid() const { return (times != nullptr); }
+  bool IsValid() const { return (this->times != nullptr); }
   //! Try to load the file times from @a fileName and @return IsValid()
   bool Load(std::string const& fileName);
   //! Stores the file times at @a fileName (if IsValid())
index dee91d7..d2f9619 100644 (file)
@@ -182,7 +182,7 @@ void cmFindCommon::SelectDefaultSearchModes()
       { this->NoCMakeSystemPath, "CMAKE_FIND_USE_CMAKE_SYSTEM_PATH" } }
   };
 
-  for (auto& path : search_paths) {
+  for (auto const& path : search_paths) {
     cmProp def = this->Makefile->GetDefinition(path.second);
     if (def) {
       path.first = !cmIsOn(*def);
@@ -289,7 +289,7 @@ void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore)
 void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore)
 {
   std::vector<std::string> ignoreVec;
-  GetIgnoredPaths(ignoreVec);
+  this->GetIgnoredPaths(ignoreVec);
   ignore.insert(ignoreVec.begin(), ignoreVec.end());
 }
 
index b87dfe3..49b1bd7 100644 (file)
@@ -31,7 +31,7 @@ cmFindLibraryCommand::cmFindLibraryCommand(cmExecutionStatus& status)
 // cmFindLibraryCommand
 bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
-  this->DebugMode = ComputeIfDebugModeWanted();
+  this->DebugMode = this->ComputeIfDebugModeWanted();
   this->VariableDocumentation = "Path to a library.";
   this->CMakePathName = "LIBRARY";
   if (!this->ParseArguments(argsIn)) {
index 92b1e80..3719fe1 100644 (file)
@@ -144,7 +144,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
     this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]);
   }
 
-  this->DebugMode = ComputeIfDebugModeWanted();
+  this->DebugMode = this->ComputeIfDebugModeWanted();
   this->DebugBuffer.clear();
 
   // Lookup target architecture, if any.
@@ -534,7 +534,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
         loadedPackage = true;
       } else {
         // The package was not loaded. Report errors.
-        if (HandlePackageMode(HandlePackageModeType::Module)) {
+        if (this->HandlePackageMode(HandlePackageModeType::Module)) {
           loadedPackage = true;
         }
       }
@@ -1145,34 +1145,27 @@ bool cmFindPackageCommand::FindConfig()
 bool cmFindPackageCommand::FindPrefixedConfig()
 {
   std::vector<std::string> const& prefixes = this->SearchPaths;
-  for (std::string const& p : prefixes) {
-    if (this->SearchPrefix(p)) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(
+    prefixes.begin(), prefixes.end(),
+    [this](std::string const& p) -> bool { return this->SearchPrefix(p); });
 }
 
 bool cmFindPackageCommand::FindFrameworkConfig()
 {
   std::vector<std::string> const& prefixes = this->SearchPaths;
-  for (std::string const& p : prefixes) {
-    if (this->SearchFrameworkPrefix(p)) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(prefixes.begin(), prefixes.end(),
+                     [this](std::string const& p) -> bool {
+                       return this->SearchFrameworkPrefix(p);
+                     });
 }
 
 bool cmFindPackageCommand::FindAppBundleConfig()
 {
   std::vector<std::string> const& prefixes = this->SearchPaths;
-  for (std::string const& p : prefixes) {
-    if (this->SearchAppBundlePrefix(p)) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(prefixes.begin(), prefixes.end(),
+                     [this](std::string const& p) -> bool {
+                       return this->SearchAppBundlePrefix(p);
+                     });
 }
 
 bool cmFindPackageCommand::ReadListFile(const std::string& f,
@@ -2070,8 +2063,8 @@ public:
   void SetSort(cmFindPackageCommand::SortOrderType o,
                cmFindPackageCommand::SortDirectionType d)
   {
-    SortOrder = o;
-    SortDirection = d;
+    this->SortOrder = o;
+    this->SortDirection = d;
   }
 
 protected:
@@ -2102,8 +2095,8 @@ private:
     // before testing the matches check if there is a specific sorting order to
     // perform
     if (this->SortOrder != cmFindPackageCommand::None) {
-      cmFindPackageCommand::Sort(matches.begin(), matches.end(), SortOrder,
-                                 SortDirection);
+      cmFindPackageCommand::Sort(matches.begin(), matches.end(),
+                                 this->SortOrder, this->SortDirection);
     }
 
     for (std::string const& i : matches) {
index 4bab469..3fb0826 100644 (file)
@@ -22,7 +22,7 @@ cmFindPathCommand::cmFindPathCommand(cmExecutionStatus& status)
 // cmFindPathCommand
 bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
-  this->DebugMode = ComputeIfDebugModeWanted();
+  this->DebugMode = this->ComputeIfDebugModeWanted();
   this->VariableDocumentation = "Path to a file.";
   this->CMakePathName = "INCLUDE";
   if (!this->ParseArguments(argsIn)) {
@@ -80,8 +80,8 @@ std::string cmFindPathCommand::FindHeader()
   return header;
 }
 
-std::string cmFindPathCommand::FindHeaderInFramework(std::string const& file,
-                                                     std::string const& dir)
+std::string cmFindPathCommand::FindHeaderInFramework(
+  std::string const& file, std::string const& dir) const
 {
   std::string fileName = file;
   std::string frameWorkName;
index b9fe673..6101ea1 100644 (file)
@@ -29,7 +29,7 @@ public:
 
 private:
   std::string FindHeaderInFramework(std::string const& file,
-                                    std::string const& dir);
+                                    std::string const& dir) const;
   std::string FindHeader();
   std::string FindNormalHeader(cmFindBaseDebugState& debug);
   std::string FindFrameworkHeader(cmFindBaseDebugState& debug);
index 77728ec..c22462e 100644 (file)
@@ -2,6 +2,9 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmFindProgramCommand.h"
 
+#include <algorithm>
+#include <string>
+
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
@@ -60,44 +63,42 @@ struct cmFindProgramHelper
   }
   bool CheckCompoundNames()
   {
-    for (std::string const& n : this->Names) {
-      // Only perform search relative to current directory if the file name
-      // contains a directory separator.
-      if (n.find('/') != std::string::npos) {
-        if (this->CheckDirectoryForName("", n)) {
-          return true;
-        }
-      }
-    }
-    return false;
+    return std::any_of(this->Names.begin(), this->Names.end(),
+                       [this](std::string const& n) -> bool {
+                         // Only perform search relative to current directory
+                         // if the file name contains a directory separator.
+                         return n.find('/') != std::string::npos &&
+                           this->CheckDirectoryForName("", n);
+                       });
   }
   bool CheckDirectory(std::string const& path)
   {
-    for (std::string const& n : this->Names) {
-      if (this->CheckDirectoryForName(path, n)) {
-        return true;
-      }
-    }
-    return false;
+    return std::any_of(this->Names.begin(), this->Names.end(),
+                       [this, &path](std::string const& n) -> bool {
+                         // Only perform search relative to current directory
+                         // if the file name contains a directory separator.
+                         return this->CheckDirectoryForName(path, n);
+                       });
   }
   bool CheckDirectoryForName(std::string const& path, std::string const& name)
   {
-    for (std::string const& ext : this->Extensions) {
-      if (!ext.empty() && cmHasSuffix(name, ext)) {
-        continue;
-      }
-      this->TestNameExt = cmStrCat(name, ext);
-      this->TestPath =
-        cmSystemTools::CollapseFullPath(this->TestNameExt, path);
-      bool exists = this->FileIsExecutable(this->TestPath);
-      exists ? this->DebugSearches.FoundAt(this->TestPath)
-             : this->DebugSearches.FailedAt(this->TestPath);
-      if (exists) {
-        this->BestPath = this->TestPath;
-        return true;
-      }
-    }
-    return false;
+    return std::any_of(this->Extensions.begin(), this->Extensions.end(),
+                       [this, &path, &name](std::string const& ext) -> bool {
+                         if (!ext.empty() && cmHasSuffix(name, ext)) {
+                           return false;
+                         }
+                         this->TestNameExt = cmStrCat(name, ext);
+                         this->TestPath = cmSystemTools::CollapseFullPath(
+                           this->TestNameExt, path);
+                         bool exists = this->FileIsExecutable(this->TestPath);
+                         exists ? this->DebugSearches.FoundAt(this->TestPath)
+                                : this->DebugSearches.FailedAt(this->TestPath);
+                         if (exists) {
+                           this->BestPath = this->TestPath;
+                           return true;
+                         }
+                         return false;
+                       });
   }
   bool FileIsExecutable(std::string const& file) const
   {
@@ -152,7 +153,7 @@ cmFindProgramCommand::cmFindProgramCommand(cmExecutionStatus& status)
 // cmFindProgramCommand
 bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
-  this->DebugMode = ComputeIfDebugModeWanted();
+  this->DebugMode = this->ComputeIfDebugModeWanted();
   this->VariableDocumentation = "Path to a program.";
   this->CMakePathName = "PROGRAM";
   // call cmFindBase::ParseArguments
@@ -171,7 +172,7 @@ bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
     return true;
   }
 
-  std::string const result = FindProgram();
+  std::string const result = this->FindProgram();
   if (!result.empty()) {
     // Save the value in the cache
     this->Makefile->AddCacheDefinition(this->VariableName, result,
@@ -198,7 +199,7 @@ std::string cmFindProgramCommand::FindProgram()
   std::string program;
 
   if (this->SearchAppBundleFirst || this->SearchAppBundleOnly) {
-    program = FindAppBundle();
+    program = this->FindAppBundle();
   }
   if (program.empty() && !this->SearchAppBundleOnly) {
     program = this->FindNormalProgram();
@@ -274,7 +275,7 @@ std::string cmFindProgramCommand::FindAppBundle()
       cmSystemTools::FindDirectory(appName, this->SearchPaths, true);
 
     if (!appPath.empty()) {
-      std::string executable = GetBundleExecutable(appPath);
+      std::string executable = this->GetBundleExecutable(appPath);
       if (!executable.empty()) {
         return cmSystemTools::CollapseFullPath(executable);
       }
index b4b493b..38abeba 100644 (file)
@@ -44,7 +44,6 @@ private:
   virtual bool Replay(std::vector<cmListFileFunction> functions,
                       cmExecutionStatus& status) = 0;
 
-private:
   cmListFileContext StartingContext;
   std::vector<cmListFileFunction> Functions;
   unsigned int ScopeDepth = 1;
index 71c82d6..1359009 100644 (file)
@@ -163,8 +163,11 @@ bool cmFunctionFunctionBlocker::Replay(
   f.FilePath = this->GetStartingContext().FilePath;
   f.Line = this->GetStartingContext().Line;
   mf.RecordPolicies(f.Policies);
-  mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f));
-  return true;
+  return mf.GetState()->AddScriptedCommand(
+    this->Args.front(),
+    BT<cmState::Command>(std::move(f),
+                         mf.GetBacktrace().Push(this->GetStartingContext())),
+    mf);
 }
 
 } // anonymous namespace
index 957896f..c782bcd 100644 (file)
@@ -27,23 +27,30 @@ bool cmGccDepfileLexerHelper::readFile(const char* filePath)
   if (!file) {
     return false;
   }
-  newEntry();
+  this->newEntry();
   yyscan_t scanner;
   cmGccDepfile_yylex_init(&scanner);
   cmGccDepfile_yyset_extra(this, scanner);
   cmGccDepfile_yyrestart(file, scanner);
   cmGccDepfile_yylex(scanner);
   cmGccDepfile_yylex_destroy(scanner);
-  sanitizeContent();
+  this->sanitizeContent();
   fclose(file);
-  return true;
+  return this->HelperState != State::Failed;
 }
 
 void cmGccDepfileLexerHelper::newEntry()
 {
+  if (this->HelperState == State::Rule && !this->Content.empty()) {
+    if (!this->Content.back().rules.empty() &&
+        !this->Content.back().rules.back().empty()) {
+      this->HelperState = State::Failed;
+    }
+    return;
+  }
   this->HelperState = State::Rule;
   this->Content.emplace_back();
-  newRule();
+  this->newRule();
 }
 
 void cmGccDepfileLexerHelper::newRule()
@@ -56,20 +63,22 @@ void cmGccDepfileLexerHelper::newRule()
 
 void cmGccDepfileLexerHelper::newDependency()
 {
-  // printf("NEW DEP\n");
+  if (this->HelperState == State::Failed) {
+    return;
+  }
   this->HelperState = State::Dependency;
-  if (this->Content.back().paths.empty() ||
-      !this->Content.back().paths.back().empty()) {
-    this->Content.back().paths.emplace_back();
+  auto& entry = this->Content.back();
+  if (entry.paths.empty() || !entry.paths.back().empty()) {
+    entry.paths.emplace_back();
   }
 }
 
 void cmGccDepfileLexerHelper::newRuleOrDependency()
 {
   if (this->HelperState == State::Rule) {
-    newRule();
-  } else {
-    newDependency();
+    this->newRule();
+  } else if (this->HelperState == State::Dependency) {
+    this->newDependency();
   }
 }
 
@@ -93,6 +102,8 @@ void cmGccDepfileLexerHelper::addToCurrentPath(const char* s)
       }
       dst = &dep->paths.back();
     } break;
+    case State::Failed:
+      return;
   }
   dst->append(s);
 }
index 07ca61d..91132f5 100644 (file)
@@ -29,7 +29,8 @@ private:
   enum class State
   {
     Rule,
-    Dependency
+    Dependency,
+    Failed,
   };
   State HelperState = State::Rule;
 };
index 9d70ede..6436baa 100644 (file)
@@ -4,15 +4,43 @@
 
 #include <type_traits>
 #include <utility>
+#include <vector>
+
+#include <cm/optional>
 
 #include "cmGccDepfileLexerHelper.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
 
-cmGccDepfileContent cmReadGccDepfile(const char* filePath)
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath,
+                                                   const std::string& prefix)
 {
-  cmGccDepfileContent result;
   cmGccDepfileLexerHelper helper;
-  if (helper.readFile(filePath)) {
-    result = std::move(helper).extractContent();
+  if (!helper.readFile(filePath)) {
+    return cm::nullopt;
+  }
+  auto deps = cm::make_optional(std::move(helper).extractContent());
+
+  for (auto& dep : *deps) {
+    for (auto& rule : dep.rules) {
+      if (!prefix.empty() && !cmSystemTools::FileIsFullPath(rule)) {
+        rule = cmStrCat(prefix, '/', rule);
+      }
+      if (cmSystemTools::FileIsFullPath(rule)) {
+        rule = cmSystemTools::CollapseFullPath(rule);
+      }
+      cmSystemTools::ConvertToLongPath(rule);
+    }
+    for (auto& path : dep.paths) {
+      if (!prefix.empty() && !cmSystemTools::FileIsFullPath(path)) {
+        path = cmStrCat(prefix, '/', path);
+      }
+      if (cmSystemTools::FileIsFullPath(path)) {
+        path = cmSystemTools::CollapseFullPath(path);
+      }
+      cmSystemTools::ConvertToLongPath(path);
+    }
   }
-  return result;
+
+  return deps;
 }
index 395dd77..c8a3748 100644 (file)
@@ -2,6 +2,14 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #pragma once
 
+#include <string>
+
+#include <cm/optional>
+
 #include "cmGccDepfileReaderTypes.h"
 
-cmGccDepfileContent cmReadGccDepfile(const char* filePath);
+/*
+ * Read dependencies file and append prefix to all relative paths
+ */
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(
+  const char* filePath, const std::string& prefix = {});
index 2768547..43f384a 100644 (file)
 #endif
 
 cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding)
-  : OriginalLocale(getloc())
+  : OriginalLocale(this->getloc())
 {
 #ifndef CMAKE_BOOTSTRAP
   if (encoding != codecvt::None) {
-    imbue(std::locale(OriginalLocale, new codecvt(encoding)));
+    this->imbue(std::locale(this->OriginalLocale, new codecvt(encoding)));
   }
 #else
   static_cast<void>(encoding);
@@ -28,7 +28,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding)
 cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
                                              bool quiet, Encoding encoding)
   : cmGeneratedFileStreamBase(name)
-  , Stream(TempName.c_str())
+  , Stream(this->TempName.c_str())
 {
   // Check if the file opened.
   if (!*this && !quiet) {
@@ -37,7 +37,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
   }
 #ifndef CMAKE_BOOTSTRAP
   if (encoding != codecvt::None) {
-    imbue(std::locale(getloc(), new codecvt(encoding)));
+    this->imbue(std::locale(this->getloc(), new codecvt(encoding)));
   }
 #else
   static_cast<void>(encoding);
index e223f15..a1fce55 100644 (file)
@@ -28,7 +28,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   , Backtrace(std::move(backtrace))
   , TransitivePropertiesOnly(false)
 {
-  Initialize();
+  this->Initialize();
 }
 
 cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
@@ -42,7 +42,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   , Backtrace()
   , TransitivePropertiesOnly(false)
 {
-  Initialize();
+  this->Initialize();
 }
 
 void cmGeneratorExpressionDAGChecker::Initialize()
@@ -52,7 +52,7 @@ void cmGeneratorExpressionDAGChecker::Initialize()
 
 #define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() ||
 
-  if (CheckResult == DAG &&
+  if (this->CheckResult == DAG &&
       (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
         TEST_TRANSITIVE_PROPERTY_METHOD) false)) // NOLINT(*)
 #undef TEST_TRANSITIVE_PROPERTY_METHOD
index 53225cd..93b44db 100644 (file)
@@ -89,7 +89,6 @@ private:
   Result CheckGraph() const;
   void Initialize();
 
-private:
   const cmGeneratorExpressionDAGChecker* const Parent;
   cmGeneratorTarget const* Target;
   const std::string Property;
index 9e5023d..9fae15a 100644 (file)
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmSourceFile.h"
-#include "cmSourceFileLocationKind.h"
 #include "cmSystemTools.h"
 
 cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile(
   std::string input, std::string target,
   std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
   std::unique_ptr<cmCompiledGeneratorExpression> condition,
-  bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070)
+  bool inputIsContent, std::string newLineCharacter, mode_t permissions,
+  cmPolicies::PolicyStatus policyStatusCMP0070)
   : Input(std::move(input))
   , Target(std::move(target))
   , OutputFileExpr(std::move(outputFileExpr))
   , Condition(std::move(condition))
   , InputIsContent(inputIsContent)
+  , NewLineCharacter(std::move(newLineCharacter))
   , PolicyStatusCMP0070(policyStatusCMP0070)
+  , Permissions(permissions)
 {
 }
 
@@ -38,7 +40,7 @@ void cmGeneratorExpressionEvaluationFile::Generate(
   std::map<std::string, std::string>& outputFiles, mode_t perm)
 {
   std::string rawCondition = this->Condition->GetInput();
-  cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(Target);
+  cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target);
   if (!rawCondition.empty()) {
     std::string condResult =
       this->Condition->Evaluate(lg, config, target, nullptr, nullptr, lang);
@@ -81,9 +83,33 @@ void cmGeneratorExpressionEvaluationFile::Generate(
   this->Files.push_back(outputFileName);
   outputFiles[outputFileName] = outputContent;
 
-  cmGeneratedFileStream fout(outputFileName);
+  bool openWithBinaryFlag = false;
+  if (!this->NewLineCharacter.empty()) {
+    openWithBinaryFlag = true;
+  }
+  cmGeneratedFileStream fout;
+  fout.Open(outputFileName, false, openWithBinaryFlag);
+  if (!fout) {
+    lg->IssueMessage(MessageType::FATAL_ERROR,
+                     "Could not open file for write in copy operation " +
+                       outputFileName);
+    return;
+  }
   fout.SetCopyIfDifferent(true);
-  fout << outputContent;
+  std::istringstream iss(outputContent);
+  std::string line;
+  bool hasNewLine = false;
+  while (cmSystemTools::GetLineFromStream(iss, line, &hasNewLine)) {
+    fout << line;
+    if (!this->NewLineCharacter.empty()) {
+      fout << this->NewLineCharacter;
+    } else if (hasNewLine) {
+      // if new line character is not specified, the file will be opened in
+      // text mode. So, "\n" will be translated to the correct newline
+      // ending based on the platform.
+      fout << "\n";
+    }
+  }
   if (fout.Close() && perm) {
     cmSystemTools::SetPermissions(outputFileName.c_str(), perm);
   }
@@ -94,16 +120,12 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
 {
   std::vector<std::string> enabledLanguages;
   cmGlobalGenerator* gg = lg->GetGlobalGenerator();
-  cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(Target);
+  cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target);
   gg->GetEnabledLanguages(enabledLanguages);
 
   for (std::string const& le : enabledLanguages) {
     std::string const name = this->GetOutputFileName(lg, target, config, le);
-    cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource(
-      name, false, cmSourceFileLocationKind::Known);
-    // Tell TraceDependencies that the file is not expected to exist
-    // on disk yet.  We generate it after that runs.
-    sf->SetProperty("GENERATED", "1");
+    cmSourceFile* sf = lg->GetMakefile()->GetOrCreateGeneratedSource(name);
 
     // Tell the build system generators that there is no build rule
     // to generate the file.
@@ -116,14 +138,15 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile(
 
 void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg)
 {
-  mode_t perm = 0;
   std::string inputContent;
   if (this->InputIsContent) {
     inputContent = this->Input;
   } else {
     const std::string inputFileName = this->GetInputFileName(lg);
     lg->GetMakefile()->AddCMakeDependFile(inputFileName);
-    cmSystemTools::GetPermissions(inputFileName.c_str(), perm);
+    if (!this->Permissions) {
+      cmSystemTools::GetPermissions(inputFileName.c_str(), this->Permissions);
+    }
     cmsys::ifstream fin(inputFileName.c_str());
     if (!fin) {
       std::ostringstream e;
@@ -157,7 +180,8 @@ void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg)
 
   for (std::string const& le : enabledLanguages) {
     for (std::string const& li : allConfigs) {
-      this->Generate(lg, li, le, inputExpression.get(), outputFiles, perm);
+      this->Generate(lg, li, le, inputExpression.get(), outputFiles,
+                     this->Permissions);
       if (cmSystemTools::GetFatalErrorOccured()) {
         return;
       }
index 2cd35ae..0eb78ac 100644 (file)
@@ -24,7 +24,8 @@ public:
     std::string input, std::string target,
     std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr,
     std::unique_ptr<cmCompiledGeneratorExpression> condition,
-    bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070);
+    bool inputIsContent, std::string newLineCharacter, mode_t permissions,
+    cmPolicies::PolicyStatus policyStatusCMP0070);
 
   void Generate(cmLocalGenerator* lg);
 
@@ -51,12 +52,13 @@ private:
   std::string FixRelativePath(std::string const& filePath, PathRole role,
                               cmLocalGenerator* lg);
 
-private:
   const std::string Input;
   const std::string Target;
   const std::unique_ptr<cmCompiledGeneratorExpression> OutputFileExpr;
   const std::unique_ptr<cmCompiledGeneratorExpression> Condition;
   std::vector<std::string> Files;
   const bool InputIsContent;
+  const std::string NewLineCharacter;
   cmPolicies::PolicyStatus PolicyStatusCMP0070;
+  mode_t Permissions;
 };
index 4129a0c..fec309c 100644 (file)
@@ -31,7 +31,7 @@ std::string GeneratorExpressionContent::ProcessArbitraryContent(
 
   const auto pend = this->ParamChildren.end();
   for (; pit != pend; ++pit) {
-    for (auto& pExprEval : *pit) {
+    for (const auto& pExprEval : *pit) {
       if (node->RequiresLiteralInput()) {
         if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
           reportError(context, this->GetOriginalExpression(),
@@ -63,7 +63,7 @@ std::string GeneratorExpressionContent::Evaluate(
 {
   std::string identifier;
   {
-    for (auto& pExprEval : this->IdentifierChildren) {
+    for (const auto& pExprEval : this->IdentifierChildren) {
       identifier += pExprEval->Evaluate(context, dagChecker);
       if (context->HadError) {
         return std::string();
@@ -124,7 +124,7 @@ std::string GeneratorExpressionContent::EvaluateParameters(
         return std::string();
       }
       std::string parameter;
-      for (auto& pExprEval : *pit) {
+      for (const auto& pExprEval : *pit) {
         parameter += pExprEval->Evaluate(context, dagChecker);
         if (context->HadError) {
           return std::string();
index 3e7737e..8f47c0b 100644 (file)
@@ -60,7 +60,7 @@ struct TextContent : public cmGeneratorExpressionEvaluator
 
   void Extend(size_t length) { this->Length += length; }
 
-  size_t GetLength() { return this->Length; }
+  size_t GetLength() const { return this->Length; }
 
 private:
   const char* Content;
@@ -108,7 +108,6 @@ private:
     std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit)
     const;
 
-private:
   cmGeneratorExpressionEvaluatorVector IdentifierChildren;
   std::vector<cmGeneratorExpressionEvaluatorVector> ParamChildren;
   const char* StartContent;
index a7f090a..b8c38c0 100644 (file)
@@ -35,14 +35,14 @@ std::vector<cmGeneratorExpressionToken> cmGeneratorExpressionLexer::Tokenize(
                               2);
           upto = c + 2;
           ++c;
-          SawBeginExpression = true;
+          this->SawBeginExpression = true;
         }
         break;
       case '>':
         InsertText(upto, c, result);
         result.emplace_back(cmGeneratorExpressionToken::EndExpression, c, 1);
         upto = c + 1;
-        SawGeneratorExpression = SawBeginExpression;
+        this->SawGeneratorExpression = this->SawBeginExpression;
         break;
       case ':':
         InsertText(upto, c, result);
index 4ca7405..e40316e 100644 (file)
@@ -677,7 +677,7 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
     }
     static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
 
-    for (auto& param : parameters) {
+    for (auto const& param : parameters) {
 
       if (!compilerIdValidator.find(param)) {
         reportError(context, content->GetOriginalExpression(),
@@ -805,7 +805,7 @@ struct PlatformIdNode : public cmGeneratorExpressionNode
       return parameters.front().empty() ? "1" : "0";
     }
 
-    for (auto& param : parameters) {
+    for (auto const& param : parameters) {
       if (param == platformId) {
         return "1";
       }
@@ -901,7 +901,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
       return std::string();
     }
     context->HadContextSensitiveCondition = true;
-    for (auto& param : parameters) {
+    for (auto const& param : parameters) {
       if (context->Config.empty()) {
         if (param.empty()) {
           return "1";
@@ -927,7 +927,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
         if (cmProp mapValue = context->CurrentTarget->GetProperty(mapProp)) {
           cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs);
 
-          for (auto& param : parameters) {
+          for (auto const& param : parameters) {
             if (cm::contains(mappedConfigs, cmSystemTools::UpperCase(param))) {
               return "1";
             }
@@ -995,7 +995,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
       return context->Language;
     }
 
-    for (auto& param : parameters) {
+    for (auto const& param : parameters) {
       if (context->Language == param) {
         return "1";
       }
@@ -1101,7 +1101,7 @@ static const struct LinkLanguageNode : public cmGeneratorExpressionNode
       return context->Language;
     }
 
-    for (auto& param : parameters) {
+    for (auto const& param : parameters) {
       if (context->Language == param) {
         return "1";
       }
@@ -1129,7 +1129,7 @@ struct LinkerId
     }
     static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$");
 
-    for (auto& param : parameters) {
+    for (auto const& param : parameters) {
       if (!linkerIdValidator.find(param)) {
         reportError(context, content->GetOriginalExpression(),
                     "Expression syntax not recognized.");
index c2c9ef7..794c1a1 100644 (file)
@@ -22,7 +22,7 @@ cmGeneratorExpressionParser::cmGeneratorExpressionParser(
 void cmGeneratorExpressionParser::Parse(
   cmGeneratorExpressionEvaluatorVector& result)
 {
-  it = this->Tokens.begin();
+  this->it = this->Tokens.begin();
 
   while (this->it != this->Tokens.end()) {
     this->ParseContent(result);
index d49bf3e..efaef3e 100644 (file)
@@ -24,7 +24,6 @@ private:
   void ParseContent(cmGeneratorExpressionEvaluatorVector&);
   void ParseGeneratorExpression(cmGeneratorExpressionEvaluatorVector&);
 
-private:
   std::vector<cmGeneratorExpressionToken>::const_iterator it;
   const std::vector<cmGeneratorExpressionToken> Tokens;
   unsigned int NestingLevel;
index c299dad..d7e9952 100644 (file)
@@ -24,9 +24,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
-#include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
-#include "cmCustomCommandLines.h"
 #include "cmFileTimes.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
@@ -254,7 +252,7 @@ EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries(
 {
   EvaluatedTargetPropertyEntries out;
   out.Entries.reserve(in.size());
-  for (auto& entry : in) {
+  for (auto const& entry : in) {
     out.Entries.emplace_back(EvaluateTargetPropertyEntry(
       thisTarget, config, lang, dagChecker, *entry));
   }
@@ -332,7 +330,7 @@ cmGeneratorTarget::~cmGeneratorTarget() = default;
 const std::string& cmGeneratorTarget::GetSourcesProperty() const
 {
   std::vector<std::string> values;
-  for (auto& se : this->SourceEntries) {
+  for (auto const& se : this->SourceEntries) {
     values.push_back(se->GetInput());
   }
   static std::string value;
@@ -559,7 +557,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
 
     // Frameworks created by multi config generators can have a special
     // framework postfix.
-    frameworkPostfix = GetFrameworkMultiConfigPostfix(config);
+    frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config);
     if (!frameworkPostfix.empty()) {
       postfix = &frameworkPostfix;
     }
@@ -578,7 +576,7 @@ std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
 
     if (!this->IsImported() && postfix &&
         (this->IsFrameworkOnApple() &&
-         !GetGlobalGenerator()->IsMultiConfig())) {
+         !this->GetGlobalGenerator()->IsMultiConfig())) {
       postfix = nullptr;
     }
   }
@@ -992,9 +990,8 @@ cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const
 bool cmGeneratorTarget::GetLanguageStandardRequired(
   std::string const& lang) const
 {
-  cmProp p =
-    this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED");
-  return cmIsOn(p);
+  return cmIsOn(
+    this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED"));
 }
 
 void cmGeneratorTarget::GetModuleDefinitionSources(
@@ -1539,10 +1536,14 @@ bool processSources(cmGeneratorTarget const* tgt,
     for (std::string& src : entry.Values) {
       cmSourceFile* sf = mf->GetOrCreateSource(src);
       std::string e;
-      std::string fullPath = sf->ResolveFullPath(&e);
+      std::string w;
+      std::string fullPath = sf->ResolveFullPath(&e, &w);
+      cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
+      if (!w.empty()) {
+        cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace());
+      }
       if (fullPath.empty()) {
         if (!e.empty()) {
-          cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
           cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace());
         }
         return contextDependent;
@@ -2002,17 +2003,16 @@ bool cmGeneratorTarget::NeedRelinkBeforeInstall(
   // this target must be relinked.
   bool have_rpath =
     this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config);
-  bool is_ninja =
-    this->LocalGenerator->GetGlobalGenerator()->GetName() == "Ninja";
+  bool is_ninja = this->LocalGenerator->GetGlobalGenerator()->IsNinja();
 
   if (have_rpath && is_ninja) {
     std::ostringstream w;
     /* clang-format off */
     w <<
-      "The install of the " << this->GetName() << " target requires "
-      "changing an RPATH from the build tree, but this is not supported "
-      "with the Ninja generator unless on an ELF-based platform.  The "
-      "CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
+      "The install of the " << this->GetName() << " target requires changing "
+      "an RPATH from the build tree, but this is not supported with the Ninja "
+      "generator unless on an ELF-based or XCOFF-based platform.  "
+      "The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this "
       "relinking step."
       ;
     /* clang-format on */
@@ -2058,20 +2058,29 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const
     return true;
   }
 
-#if defined(CMAKE_USE_ELF_PARSER)
-  // Enable if the rpath flag uses a separator and the target uses ELF
-  // binaries.
+#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER)
+  // Enable if the rpath flag uses a separator and the target uses
+  // binaries we know how to edit.
   std::string ll = this->GetLinkerLanguage(config);
   if (!ll.empty()) {
     std::string sepVar =
       cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP");
     cmProp sep = this->Makefile->GetDefinition(sepVar);
     if (cmNonempty(sep)) {
-      // TODO: Add ELF check to ABI detection and get rid of
+      // TODO: Add binary format check to ABI detection and get rid of
       // CMAKE_EXECUTABLE_FORMAT.
       if (cmProp fmt =
             this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) {
-        return (*fmt == "ELF");
+#  if defined(CMake_USE_ELF_PARSER)
+        if (*fmt == "ELF") {
+          return true;
+        }
+#  endif
+#  if defined(CMake_USE_XCOFF_PARSER)
+        if (*fmt == "XCOFF") {
+          return true;
+        }
+#  endif
       }
     }
   }
@@ -2500,9 +2509,9 @@ public:
     }
   }
 
-  bool GetHadLinkLanguageSensitiveCondition()
+  bool GetHadLinkLanguageSensitiveCondition() const
   {
-    return HadLinkLanguageSensitiveCondition;
+    return this->HadLinkLanguageSensitiveCondition;
   }
 
 private:
@@ -2639,8 +2648,12 @@ void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
     LinkClosure linkClosure;
     linkClosure.LinkerLanguage = this->LinkerLanguage;
 
+    bool hasHardCodedLinkerLanguage = this->Target->GetProperty("HAS_CXX") ||
+      !this->Target->GetSafeProperty("LINKER_LANGUAGE").empty();
+
     // Get languages built in this target.
-    secondPass = this->ComputeLinkClosure(config, linkClosure, false);
+    secondPass = this->ComputeLinkClosure(config, linkClosure, false) &&
+      !hasHardCodedLinkerLanguage;
     this->LinkerLanguage = linkClosure.LinkerLanguage;
     if (!secondPass) {
       lc = std::move(linkClosure);
@@ -2888,9 +2901,6 @@ private:
   bool IsUtility(std::string const& dep);
   void CheckCustomCommand(cmCustomCommand const& cc);
   void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
-  void FollowCommandDepends(cmCustomCommand const& cc,
-                            const std::string& config,
-                            std::set<std::string>& emitted);
 };
 
 cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target)
@@ -2986,7 +2996,8 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
   auto i = this->NameMap.lower_bound(name);
   if (i == this->NameMap.end() || i->first != name) {
     // Check if we know how to generate this file.
-    cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name);
+    cmSourcesWithOutput sources =
+      this->LocalGenerator->GetSourcesWithOutput(name);
     // If we failed to find a target or source and we have a relative path, it
     // might be a valid source if made relative to the current binary
     // directory.
@@ -2996,7 +3007,7 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
         cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
       fullname = cmSystemTools::CollapseFullPath(
         fullname, this->Makefile->GetHomeOutputDirectory());
-      sources = this->Makefile->GetSourcesWithOutput(fullname);
+      sources = this->LocalGenerator->GetSourcesWithOutput(fullname);
     }
     i = this->NameMap.emplace_hint(i, name, sources);
   }
@@ -3065,7 +3076,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
     } else {
       // The original name of the dependency was not a full path.  It
       // must name a target, so add the target-level dependency.
-      this->GeneratorTarget->Target->AddUtility(util, false);
+      this->GeneratorTarget->Target->AddUtility(util, true);
       return true;
     }
   }
@@ -3076,71 +3087,28 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
 
 void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
 {
-  // Transform command names that reference targets built in this
-  // project to corresponding target-level dependencies.
-  cmGeneratorExpression ge(cc.GetBacktrace());
-
-  // Add target-level dependencies referenced by generator expressions.
-  std::set<cmGeneratorTarget*> targets;
-
-  for (cmCustomCommandLine const& cCmdLine : cc.GetCommandLines()) {
-    std::string const& command = cCmdLine.front();
-    // Check for a target with this name.
-    if (cmGeneratorTarget* t =
-          this->LocalGenerator->FindGeneratorTargetToUse(command)) {
-      if (t->GetType() == cmStateEnums::EXECUTABLE) {
-        // The command refers to an executable target built in
-        // this project.  Add the target-level dependency to make
-        // sure the executable is up to date before this custom
-        // command possibly runs.
-        this->GeneratorTarget->Target->AddUtility(command, true);
+  // Collect dependencies referenced by all configurations.
+  std::set<std::string> depends;
+  for (std::string const& config :
+       this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
+    for (cmCustomCommandGenerator const& ccg :
+         this->LocalGenerator->MakeCustomCommandGenerators(cc, config)) {
+      // Collect target-level dependencies referenced in command lines.
+      for (auto const& util : ccg.GetUtilities()) {
+        this->GeneratorTarget->Target->AddUtility(util);
       }
-    }
 
-    // Check for target references in generator expressions.
-    std::vector<std::string> const& configs =
-      this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
-    for (std::string const& c : configs) {
-      for (std::string const& cl : cCmdLine) {
-        const std::unique_ptr<cmCompiledGeneratorExpression> cge =
-          ge.Parse(cl);
-        cge->SetQuiet(true);
-        cge->Evaluate(this->GeneratorTarget->GetLocalGenerator(), c);
-        std::set<cmGeneratorTarget*> geTargets = cge->GetTargets();
-        targets.insert(geTargets.begin(), geTargets.end());
-      }
+      // Collect file-level dependencies referenced in DEPENDS.
+      depends.insert(ccg.GetDepends().begin(), ccg.GetDepends().end());
     }
   }
 
-  for (cmGeneratorTarget* target : targets) {
-    this->GeneratorTarget->Target->AddUtility(target->GetName(), true);
-  }
-
-  // Queue the custom command dependencies.
-  std::set<std::string> emitted;
-  std::vector<std::string> const& configs =
-    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
-  for (std::string const& conf : configs) {
-    this->FollowCommandDepends(cc, conf, emitted);
-  }
-}
-
-void cmTargetTraceDependencies::FollowCommandDepends(
-  cmCustomCommand const& cc, const std::string& config,
-  std::set<std::string>& emitted)
-{
-  cmCustomCommandGenerator ccg(cc, config,
-                               this->GeneratorTarget->LocalGenerator);
-
-  const std::vector<std::string>& depends = ccg.GetDepends();
-
+  // Queue file-level dependencies.
   for (std::string const& dep : depends) {
-    if (emitted.insert(dep).second) {
-      if (!this->IsUtility(dep)) {
-        // The dependency does not name a target and may be a file we
-        // know how to generate.  Queue it.
-        this->FollowName(dep);
-      }
+    if (!this->IsUtility(dep)) {
+      // The dependency does not name a target and may be a file we
+      // know how to generate.  Queue it.
+      this->FollowName(dep);
     }
   }
 }
@@ -3200,6 +3168,30 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config,
   }
 }
 
+void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
+                                                 cmSourceFile const& sf) const
+{
+  cmProp lang = sf.GetProperty("LANGUAGE");
+  if (!lang) {
+    return;
+  }
+
+  switch (this->GetPolicyStatusCMP0119()) {
+    case cmPolicies::WARN:
+    case cmPolicies::OLD:
+      // The OLD behavior is to not add explicit language flags.
+      return;
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::NEW:
+      // The NEW behavior is to add explicit language flags.
+      break;
+  }
+
+  this->LocalGenerator->AppendFeatureOptions(flags, *lang,
+                                             "EXPLICIT_LANGUAGE");
+}
+
 void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
 {
   const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES");
@@ -3298,7 +3290,7 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
       flags += " --cuda-gpu-arch=sm_" + architecture.name;
 
       if (!architecture.real) {
-        Makefile->IssueMessage(
+        this->Makefile->IssueMessage(
           MessageType::WARNING,
           "Clang doesn't support disabling CUDA real code generation.");
       }
@@ -4071,7 +4063,7 @@ std::string cmGeneratorTarget::GetPchFileObject(const std::string& config,
     }
     std::string& filename = inserted.first->second;
 
-    auto pchSf = this->Makefile->GetOrCreateSource(
+    auto* pchSf = this->Makefile->GetOrCreateSource(
       pchSource, false, cmSourceFileLocationKind::Known);
 
     filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
@@ -4988,7 +4980,7 @@ void cmGeneratorTarget::GetFullNameInternal(
   // the base, because the suffix ends up being used in Xcode's
   // EXECUTABLE_SUFFIX attribute.
   if (this->IsFrameworkOnApple() &&
-      GetGlobalGenerator()->GetName() == "Xcode") {
+      this->GetGlobalGenerator()->GetName() == "Xcode") {
     targetSuffix = &configPostfix;
   } else {
     outBase += configPostfix;
@@ -6511,15 +6503,14 @@ bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
   if (cmProp config_outdir = this->GetProperty(configProp)) {
     // Use the user-specified per-configuration output directory.
     out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator,
-                                          config);
+                                          config, this);
 
     // Skip per-configuration subdirectory.
     conf.clear();
   } else if (cmProp outdir = this->GetProperty(propertyName)) {
     // Use the user-specified output directory.
-    out =
-      cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config);
-
+    out = cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator,
+                                          config, this);
     // Skip per-configuration subdirectory if the value contained a
     // generator expression.
     if (out != *outdir) {
@@ -7059,7 +7050,7 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
   return &impl;
 }
 
-bool cmGeneratorTarget::GetConfigCommonSourceFiles(
+bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode(
   std::vector<cmSourceFile*>& files) const
 {
   std::vector<std::string> const& configs =
@@ -7380,7 +7371,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
       std::string name = this->CheckCMP0004(lib);
       if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW) {
         // resolve alias name
-        auto target = this->Makefile->FindTargetToUse(name);
+        auto* target = this->Makefile->FindTargetToUse(name);
         if (target) {
           name = target->GetName();
         }
index 2517b72..8fe70ab 100644 (file)
@@ -430,8 +430,9 @@ public:
 
   /** Get source files common to all configurations and diagnose cases
       with per-config sources.  Excludes sources added by a TARGET_OBJECTS
-      generator expression.  */
-  bool GetConfigCommonSourceFiles(std::vector<cmSourceFile*>& files) const;
+      generator expression.  Do not use outside the Xcode generator.  */
+  bool GetConfigCommonSourceFilesForXcode(
+    std::vector<cmSourceFile*>& files) const;
 
   bool HaveBuildTreeRPATH(const std::string& config) const;
 
@@ -447,6 +448,9 @@ public:
   void GetAppleArchs(const std::string& config,
                      std::vector<std::string>& archVec) const;
 
+  void AddExplicitLanguageFlags(std::string& flags,
+                                cmSourceFile const& sf) const;
+
   void AddCUDAArchitectureFlags(std::string& flags) const;
   void AddCUDAToolkitFlags(std::string& flags) const;
 
@@ -581,7 +585,8 @@ public:
     std::string PdbDir;
     bool empty() const
     {
-      return OutDir.empty() && ImpDir.empty() && PdbDir.empty();
+      return this->OutDir.empty() && this->ImpDir.empty() &&
+        this->PdbDir.empty();
     }
   };
 
index c2098c0..7fbd479 100644 (file)
@@ -50,6 +50,10 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args,
       return false;
     }
     ++i;
+    if (i == args.end()) {
+      status.SetError("called with incorrect number of arguments");
+      return false;
+    }
   }
 
   // OK, now we have the directory to process, we just get the requested
@@ -67,27 +71,30 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args,
     return true;
   }
 
+  if (i->empty()) {
+    status.SetError("given empty string for the property name to get");
+    return false;
+  }
+
   const char* prop = nullptr;
-  if (!i->empty()) {
-    if (*i == "DEFINITIONS") {
-      switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0059)) {
-        case cmPolicies::WARN:
-          status.GetMakefile().IssueMessage(
-            MessageType::AUTHOR_WARNING,
-            cmPolicies::GetPolicyWarning(cmPolicies::CMP0059));
-          CM_FALLTHROUGH;
-        case cmPolicies::OLD:
-          StoreResult(status.GetMakefile(), variable,
-                      status.GetMakefile().GetDefineFlagsCMP0059());
-          return true;
-        case cmPolicies::NEW:
-        case cmPolicies::REQUIRED_ALWAYS:
-        case cmPolicies::REQUIRED_IF_USED:
-          break;
-      }
+  if (*i == "DEFINITIONS") {
+    switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0059)) {
+      case cmPolicies::WARN:
+        status.GetMakefile().IssueMessage(
+          MessageType::AUTHOR_WARNING,
+          cmPolicies::GetPolicyWarning(cmPolicies::CMP0059));
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        StoreResult(status.GetMakefile(), variable,
+                    status.GetMakefile().GetDefineFlagsCMP0059());
+        return true;
+      case cmPolicies::NEW:
+      case cmPolicies::REQUIRED_ALWAYS:
+      case cmPolicies::REQUIRED_IF_USED:
+        break;
     }
-    prop = cmToCStr(dir->GetProperty(*i));
   }
+  prop = cmToCStr(dir->GetProperty(*i));
   StoreResult(status.GetMakefile(), variable, prop);
   return true;
 }
index 3a5b39d..cb657f9 100644 (file)
@@ -172,7 +172,7 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args,
 
   std::vector<cmMakefile*> source_file_directory_makefiles;
   bool file_scopes_handled =
-    SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
+    SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
       status, source_file_directory_option_enabled,
       source_file_target_option_enabled, source_file_directories,
       source_file_target_directories, source_file_directory_makefiles);
@@ -280,8 +280,9 @@ bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name,
 
   // Get the property.
   cmake* cm = status.GetMakefile().GetCMakeInstance();
-  cmProp p = cm->GetState()->GetGlobalProperty(propertyName);
-  return StoreResult(infoType, status.GetMakefile(), variable, cmToCStr(p));
+  return StoreResult(
+    infoType, status.GetMakefile(), variable,
+    cmToCStr(cm->GetState()->GetGlobalProperty(propertyName)));
 }
 
 bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
@@ -327,8 +328,8 @@ bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
   }
 
   // Get the property.
-  cmProp p = mf->GetProperty(propertyName);
-  return StoreResult(infoType, status.GetMakefile(), variable, cmToCStr(p));
+  return StoreResult(infoType, status.GetMakefile(), variable,
+                     cmToCStr(mf->GetProperty(propertyName)));
 }
 
 bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
@@ -358,15 +359,14 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name,
       }
       return StoreResult(infoType, status.GetMakefile(), variable, nullptr);
     }
-    cmProp prop_cstr = nullptr;
     cmListFileBacktrace bt = status.GetMakefile().GetBacktrace();
     cmMessenger* messenger = status.GetMakefile().GetMessenger();
-    prop_cstr = target->GetComputedProperty(propertyName, messenger, bt);
-    if (!prop_cstr) {
-      prop_cstr = target->GetProperty(propertyName);
+    cmProp prop = target->GetComputedProperty(propertyName, messenger, bt);
+    if (!prop) {
+      prop = target->GetProperty(propertyName);
     }
     return StoreResult(infoType, status.GetMakefile(), variable,
-                       prop_cstr ? prop_cstr->c_str() : nullptr);
+                       cmToCStr(prop));
   }
   status.SetError(cmStrCat("could not find TARGET ", name,
                            ".  Perhaps it has not yet been created."));
@@ -391,7 +391,7 @@ bool HandleSourceMode(cmExecutionStatus& status, const std::string& name,
   if (cmSourceFile* sf =
         directory_makefile.GetOrCreateSource(source_file_absolute_path)) {
     return StoreResult(infoType, status.GetMakefile(), variable,
-                       sf->GetPropertyForUser(propertyName));
+                       cmToCStr(sf->GetPropertyForUser(propertyName)));
   }
   status.SetError(
     cmStrCat("given SOURCE name that could not be found or created: ",
index 5395bc8..5301b66 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmProperty.h"
 #include "cmSetPropertyCommand.h"
 #include "cmSourceFile.h"
 
@@ -34,7 +35,7 @@ bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args,
 
   std::vector<cmMakefile*> source_file_directory_makefiles;
   bool file_scopes_handled =
-    SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
+    SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
       status, source_file_directory_option_enabled,
       source_file_target_option_enabled, source_file_directories,
       source_file_target_directories, source_file_directory_makefiles);
@@ -57,14 +58,14 @@ bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args,
   }
 
   if (sf) {
-    const char* prop = nullptr;
+    cmProp prop = nullptr;
     if (!args[property_arg_index].empty()) {
       prop = sf->GetPropertyForUser(args[property_arg_index]);
     }
     if (prop) {
       // Set the value on the original Makefile scope, not the scope of the
       // requested directory.
-      status.GetMakefile().AddDefinition(var, prop);
+      status.GetMakefile().AddDefinition(var, *prop);
       return true;
     }
   }
index a8f8f57..ed5bff5 100644 (file)
@@ -62,7 +62,7 @@ void cmGhsMultiTargetGenerator::Generate()
       // Get the name of the executable to generate.
       this->TargetNameReal =
         this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
-      if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
+      if (this->cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
         this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
       } else {
         this->TagType = GhsMultiGpj::PROGRAM;
@@ -356,7 +356,7 @@ void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
     } else {
       fout << fname << "\n    :outputName=\"" << fname << ".rule\"\n";
     }
-    for (auto& byp : ccg.GetByproducts()) {
+    for (const auto& byp : ccg.GetByproducts()) {
       fout << "    :extraOutputFile=\"" << byp << "\"\n";
     }
   }
@@ -528,7 +528,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
     }
   }
 
-  for (auto& n : groupNames) {
+  for (const auto& n : groupNames) {
     groupFilesList[i] = n;
     i += 1;
   }
@@ -631,7 +631,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
       }
     } else {
       std::vector<cmSourceFile const*> customCommands;
-      if (ComputeCustomCommandOrder(customCommands)) {
+      if (this->ComputeCustomCommandOrder(customCommands)) {
         std::string message = "The custom commands for target [" +
           this->GeneratorTarget->GetName() + "] had a cycle.\n";
         cmSystemTools::Error(message);
@@ -691,14 +691,14 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
    * the outputs is manually deleted.
    */
   bool specifyExtra = true;
-  for (auto& out : ccg.GetOutputs()) {
+  for (const auto& out : ccg.GetOutputs()) {
     fout << fname << '\n';
     fout << "    :outputName=\"" << out << "\"\n";
     if (specifyExtra) {
-      for (auto& byp : ccg.GetByproducts()) {
+      for (const auto& byp : ccg.GetByproducts()) {
         fout << "    :extraOutputFile=\"" << byp << "\"\n";
       }
-      for (auto& dep : ccg.GetDepends()) {
+      for (const auto& dep : ccg.GetDepends()) {
         fout << "    :depends=\"" << dep << "\"\n";
       }
       specifyExtra = false;
@@ -721,18 +721,15 @@ void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
 
 bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
 {
-  cmProp p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
-  if (p) {
+  if (cmProp p = this->GeneratorTarget->GetProperty("ghs_integrity_app")) {
     return cmIsOn(*p);
   }
   std::vector<cmSourceFile*> sources;
   this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
-  for (const cmSourceFile* sf : sources) {
-    if ("int" == sf->GetExtension()) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(sources.begin(), sources.end(),
+                     [](cmSourceFile const* sf) -> bool {
+                       return "int" == sf->GetExtension();
+                     });
 }
 
 bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
@@ -746,7 +743,7 @@ bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
   this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
 
   for (cmSourceFile const* si : customCommands) {
-    bool r = VisitCustomCommand(temp, perm, order, si);
+    bool r = this->VisitCustomCommand(temp, perm, order, si);
     if (r) {
       return r;
     }
@@ -762,10 +759,10 @@ bool cmGhsMultiTargetGenerator::VisitCustomCommand(
   if (perm.find(si) == perm.end()) {
     /* set temporary mark; check if revisit*/
     if (temp.insert(si).second) {
-      for (auto& di : si->GetCustomCommand()->GetDepends()) {
-        cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator()
-                                   ->GetMakefile()
-                                   ->GetSourceFileWithOutput(di);
+      for (const auto& di : si->GetCustomCommand()->GetDepends()) {
+        cmSourceFile const* sf =
+          this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput(
+            di);
         /* if sf exists then visit */
         if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
           return true;
index 06943e7..996fcff 100644 (file)
@@ -26,6 +26,15 @@ cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator(cmake* cm)
   this->DefineWindowsNULL = true;
   this->PassMakeflags = true;
   this->UnixCD = false;
+
+  /*
+   * Borland Make does not support long line depend rule, as we have tested
+   * generate one source file includes 40000 header files, and generate
+   * depend.make in one line(use line continued tag), and error occured:
+   * ** Fatal CMakeFiles\main.dir\depend.make 1224: Rule line too long **
+   * we disable long line dependencies rule generation for Borland make
+   */
+  this->ToolSupportsLongLineDependencies = false;
 }
 
 void cmGlobalBorlandMakefileGenerator::EnableLanguage(
index fc40d63..ab76260 100644 (file)
@@ -1229,7 +1229,7 @@ void cmGlobalGenerator::Configure()
     this->CMakeInstance->GetHomeOutputDirectory());
 
   auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot);
-  auto dirMf = dirMfu.get();
+  auto* dirMf = dirMfu.get();
   this->Makefiles.push_back(std::move(dirMfu));
   dirMf->SetRecursionDepth(this->RecursionDepth);
   this->IndexMakefile(dirMf);
@@ -1627,8 +1627,8 @@ void cmGlobalGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
   }
   auto entry = insertion.first;
 
-  auto& deps = this->GetTargetDirectDepends(gt);
-  for (auto& d : deps) {
+  const auto& deps = this->GetTargetDirectDepends(gt);
+  for (const auto& d : deps) {
     this->ComputeTargetOrder(d, index);
   }
 
@@ -1811,6 +1811,7 @@ void cmGlobalGenerator::ClearGeneratorMembers()
 
   this->AliasTargets.clear();
   this->ExportSets.clear();
+  this->InstallComponents.clear();
   this->TargetDependencies.clear();
   this->TargetSearchIndex.clear();
   this->GeneratorTargetSearchIndex.clear();
@@ -1821,6 +1822,7 @@ void cmGlobalGenerator::ClearGeneratorMembers()
   this->RuleHashes.clear();
   this->DirectoryContentMap.clear();
   this->BinaryDirectories.clear();
+  this->GeneratedFiles.clear();
 }
 
 void cmGlobalGenerator::ComputeTargetObjectDirectory(
@@ -2146,6 +2148,16 @@ void cmGlobalGenerator::AddInstallComponent(const std::string& component)
   }
 }
 
+void cmGlobalGenerator::MarkAsGeneratedFile(const std::string& filepath)
+{
+  this->GeneratedFiles.insert(filepath);
+}
+
+bool cmGlobalGenerator::IsGeneratedFile(const std::string& filepath)
+{
+  return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end();
+}
+
 void cmGlobalGenerator::EnableInstallTarget()
 {
   this->InstallTargetEnabled = true;
@@ -2608,7 +2620,7 @@ void cmGlobalGenerator::AddGlobalTarget_Test(
 }
 
 void cmGlobalGenerator::AddGlobalTarget_EditCache(
-  std::vector<GlobalTargetInfo>& targets)
+  std::vector<GlobalTargetInfo>& targets) const
 {
   const char* editCacheTargetName = this->GetEditCacheTargetName();
   if (!editCacheTargetName) {
@@ -2642,7 +2654,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache(
 }
 
 void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
-  std::vector<GlobalTargetInfo>& targets)
+  std::vector<GlobalTargetInfo>& targets) const
 {
   const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName();
   if (!rebuildCacheTargetName) {
@@ -2765,7 +2777,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
   }
 }
 
-std::string cmGlobalGenerator::GetPredefinedTargetsFolder()
+std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
 {
   cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
     "PREDEFINED_TARGETS_FOLDER");
@@ -2917,7 +2929,7 @@ void cmGlobalGenerator::GetTargetSets(
   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
 {
   // loop over all local generators
-  for (auto generator : generators) {
+  for (auto* generator : generators) {
     // check to make sure generator is not excluded
     if (this->IsExcluded(root, generator)) {
       continue;
index c106258..590de26 100644 (file)
 #include <set>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
+#include <cm/optional>
 #include <cmext/algorithm>
 
 #include "cm_codecvt.hxx"
@@ -26,6 +28,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
+#include "cmTransformDepfile.h"
 
 #if !defined(CMAKE_BOOTSTRAP)
 #  include <cm3p/json/value.h>
@@ -66,17 +69,17 @@ struct GeneratedMakeCommand
   void Add(T&&... args)
   {
     // iterate the args and append each one
-    AppendStrs(PrimaryCommand, std::forward<T>(args)...);
+    AppendStrs(this->PrimaryCommand, std::forward<T>(args)...);
   }
 
   // Add each value in the iterators as a separate element to the vector
   void Add(std::vector<std::string>::const_iterator start,
            std::vector<std::string>::const_iterator end)
   {
-    cm::append(PrimaryCommand, start, end);
+    cm::append(this->PrimaryCommand, start, end);
   }
 
-  std::string Printable() const { return cmJoin(PrimaryCommand, " "); }
+  std::string Printable() const { return cmJoin(this->PrimaryCommand, " "); }
 
   std::vector<std::string> PrimaryCommand;
   bool RequiresOutputForward = false;
@@ -288,6 +291,11 @@ public:
 
   void AddInstallComponent(const std::string& component);
 
+  /** Mark the (absolute path to a) file as generated.  */
+  void MarkAsGeneratedFile(const std::string& filepath);
+  /** Determine if the absolute filepath belongs to a generated file.  */
+  bool IsGeneratedFile(const std::string& filepath);
+
   const std::set<std::string>* GetInstallComponents() const
   {
     return &this->InstallComponents;
@@ -430,6 +438,8 @@ public:
 
   virtual bool IsVisualStudio() const { return false; }
 
+  virtual bool IsNinja() const { return false; }
+
   /** Return true if we know the exact location of object files.
       If false, store the reason in the given string.
       This is meaningful only after EnableLanguage has been called.  */
@@ -452,6 +462,10 @@ public:
   virtual bool ShouldStripResourcePath(cmMakefile*) const;
 
   virtual bool SupportsCustomCommandDepfile() const { return false; }
+  virtual cm::optional<cmDepfileFormat> DepfileFormat() const
+  {
+    return cm::nullopt;
+  }
 
   std::string GetSharedLibFlagsForLanguage(std::string const& lang) const;
 
@@ -489,7 +503,7 @@ public:
     cmSourceFile* sf) const;
 
 #if !defined(CMAKE_BOOTSTRAP)
-  cmFileLockPool& GetFileLockPool() { return FileLockPool; }
+  cmFileLockPool& GetFileLockPool() { return this->FileLockPool; }
 #endif
 
   bool GetConfigureDoneCMP0026() const
@@ -568,8 +582,9 @@ protected:
   void AddGlobalTarget_Package(std::vector<GlobalTargetInfo>& targets);
   void AddGlobalTarget_PackageSource(std::vector<GlobalTargetInfo>& targets);
   void AddGlobalTarget_Test(std::vector<GlobalTargetInfo>& targets);
-  void AddGlobalTarget_EditCache(std::vector<GlobalTargetInfo>& targets);
-  void AddGlobalTarget_RebuildCache(std::vector<GlobalTargetInfo>& targets);
+  void AddGlobalTarget_EditCache(std::vector<GlobalTargetInfo>& targets) const;
+  void AddGlobalTarget_RebuildCache(
+    std::vector<GlobalTargetInfo>& targets) const;
   void AddGlobalTarget_Install(std::vector<GlobalTargetInfo>& targets);
   cmTarget CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf);
 
@@ -595,7 +610,7 @@ protected:
 
   cmGeneratorTarget* FindGeneratorTargetImpl(std::string const& name) const;
 
-  std::string GetPredefinedTargetsFolder();
+  std::string GetPredefinedTargetsFolder() const;
 
   enum class FindMakeProgramStage
   {
@@ -726,6 +741,8 @@ private:
 
   std::map<std::string, std::string> RealPaths;
 
+  std::unordered_set<std::string> GeneratedFiles;
+
 #if !defined(CMAKE_BOOTSTRAP)
   // Pool of file locks
   cmFileLockPool FileLockPool;
index c08c9cf..172cf3f 100644 (file)
@@ -366,7 +366,7 @@ void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
         target->GetType() == cmStateEnums::MODULE_LIBRARY ||
         target->GetType() == cmStateEnums::SHARED_LIBRARY ||
         (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
-         target->GetName() != GetInstallTargetName())) {
+         target->GetName() != this->GetInstallTargetName())) {
       continue;
     }
     fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
@@ -415,7 +415,7 @@ void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
         target->GetType() == cmStateEnums::MODULE_LIBRARY ||
         target->GetType() == cmStateEnums::SHARED_LIBRARY ||
         (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
-         target->GetName() != GetInstallTargetName())) {
+         target->GetName() != this->GetInstallTargetName())) {
       continue;
     }
 
@@ -427,13 +427,13 @@ void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
     this->WriteFileHeader(fbld);
     GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
     std::vector<cmGeneratorTarget const*> build;
-    if (ComputeTargetBuildOrder(target, build)) {
+    if (this->ComputeTargetBuildOrder(target, build)) {
       cmSystemTools::Error(
         cmStrCat("The inter-target dependency graph for target [",
                  target->GetName(), "] had a cycle.\n"));
     } else {
       for (auto& tgt : build) {
-        WriteProjectLine(fbld, tgt, root, rootBinaryDir);
+        this->WriteProjectLine(fbld, tgt, root, rootBinaryDir);
       }
     }
     fbld.Close();
@@ -471,12 +471,12 @@ void cmGlobalGhsMultiGenerator::WriteAllTarget(
     if (!t->IsInBuildSystem()) {
       continue;
     }
-    if (!IsExcluded(t->GetLocalGenerator(), t)) {
+    if (!this->IsExcluded(t->GetLocalGenerator(), t)) {
       defaultTargets.push_back(t);
     }
   }
   std::vector<cmGeneratorTarget const*> build;
-  if (ComputeTargetBuildOrder(defaultTargets, build)) {
+  if (this->ComputeTargetBuildOrder(defaultTargets, build)) {
     std::string message = "The inter-target dependency graph for project [" +
       root->GetProjectName() + "] had a cycle.\n";
     cmSystemTools::Error(message);
@@ -694,7 +694,7 @@ bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
   cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build)
 {
   std::vector<cmGeneratorTarget const*> t{ tgt };
-  return ComputeTargetBuildOrder(t, build);
+  return this->ComputeTargetBuildOrder(t, build);
 }
 
 bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
@@ -704,8 +704,8 @@ bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
   std::set<cmGeneratorTarget const*> temp;
   std::set<cmGeneratorTarget const*> perm;
 
-  for (auto ti : tgt) {
-    bool r = VisitTarget(temp, perm, build, ti);
+  for (const auto* const ti : tgt) {
+    bool r = this->VisitTarget(temp, perm, build, ti);
     if (r) {
       return r;
     }
@@ -726,7 +726,7 @@ bool cmGlobalGhsMultiGenerator::VisitTarget(
        * in the same order */
       OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti),
                                            "");
-      for (auto& di : sortedTargets) {
+      for (auto const& di : sortedTargets) {
         if (this->VisitTarget(temp, perm, order, di)) {
           return true;
         }
index c4bec23..36f583f 100644 (file)
@@ -21,6 +21,8 @@ cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator(cmake* cm)
   this->PassMakeflags = true;
   this->UnixCD = false;
   this->MakeSilentFlag = "/nologo";
+  // nmake breaks on '!' in long-line dependencies
+  this->ToolSupportsLongLineDependencies = false;
 }
 
 void cmGlobalNMakeMakefileGenerator::EnableLanguage(
index e10c76e..c502fb8 100644 (file)
@@ -34,6 +34,7 @@
 #include "cmOutputConverter.h"
 #include "cmProperty.h"
 #include "cmRange.h"
+#include "cmScanDepFormat.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
@@ -55,6 +56,52 @@ std::string const cmGlobalNinjaGenerator::SHELL_NOOP = "cd .";
 std::string const cmGlobalNinjaGenerator::SHELL_NOOP = ":";
 #endif
 
+bool operator==(
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+  return lhs.Target == rhs.Target && lhs.Config == rhs.Config &&
+    lhs.GenexOutput == rhs.GenexOutput;
+}
+
+bool operator!=(
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+  return !(lhs == rhs);
+}
+
+bool operator<(
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+  return lhs.Target < rhs.Target ||
+    (lhs.Target == rhs.Target &&
+     (lhs.Config < rhs.Config ||
+      (lhs.Config == rhs.Config && lhs.GenexOutput < rhs.GenexOutput)));
+}
+
+bool operator>(
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+  return rhs < lhs;
+}
+
+bool operator<=(
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+  return !(lhs > rhs);
+}
+
+bool operator>=(
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+  const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+  return rhs <= lhs;
+}
+
 void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count)
 {
   for (int i = 0; i < count; ++i) {
@@ -135,7 +182,7 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path)
   else
     std::replace(result.begin(), result.end(), '/', '\\');
 #endif
-  result = EncodeLiteral(result);
+  result = this->EncodeLiteral(result);
   cmSystemTools::ReplaceString(result, " ", "$ ");
   cmSystemTools::ReplaceString(result, ":", "$:");
   return result;
@@ -167,7 +214,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
   {
     // Write explicit outputs
     for (std::string const& output : build.Outputs) {
-      buildStr += cmStrCat(' ', EncodePath(output));
+      buildStr += cmStrCat(' ', this->EncodePath(output));
       if (this->ComputingUnknownDependencies) {
         this->CombinedBuildOutputs.insert(output);
       }
@@ -176,7 +223,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
     if (!build.ImplicitOuts.empty()) {
       buildStr += " |";
       for (std::string const& implicitOut : build.ImplicitOuts) {
-        buildStr += cmStrCat(' ', EncodePath(implicitOut));
+        buildStr += cmStrCat(' ', this->EncodePath(implicitOut));
       }
     }
     buildStr += ':';
@@ -191,14 +238,14 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
 
     // Write explicit dependencies.
     for (std::string const& explicitDep : build.ExplicitDeps) {
-      arguments += cmStrCat(' ', EncodePath(explicitDep));
+      arguments += cmStrCat(' ', this->EncodePath(explicitDep));
     }
 
     // Write implicit dependencies.
     if (!build.ImplicitDeps.empty()) {
       arguments += " |";
       for (std::string const& implicitDep : build.ImplicitDeps) {
-        arguments += cmStrCat(' ', EncodePath(implicitDep));
+        arguments += cmStrCat(' ', this->EncodePath(implicitDep));
       }
     }
 
@@ -206,7 +253,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
     if (!build.OrderOnlyDeps.empty()) {
       arguments += " ||";
       for (std::string const& orderOnlyDep : build.OrderOnlyDeps) {
-        arguments += cmStrCat(' ', EncodePath(orderOnlyDep));
+        arguments += cmStrCat(' ', this->EncodePath(orderOnlyDep));
       }
     }
 
@@ -284,11 +331,11 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
 #endif
       vars["COMMAND"] = std::move(cmd);
     }
-    vars["DESC"] = EncodeLiteral(description);
+    vars["DESC"] = this->EncodeLiteral(description);
     if (restat) {
       vars["restat"] = "1";
     }
-    if (uses_terminal && SupportsConsolePool()) {
+    if (uses_terminal && this->SupportsConsolePool()) {
       vars["pool"] = "console";
     } else if (!job_pool.empty()) {
       vars["pool"] = job_pool;
@@ -315,7 +362,7 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
 void cmGlobalNinjaGenerator::AddMacOSXContentRule()
 {
   cmNinjaRule rule("COPY_OSX_CONTENT");
-  rule.Command = cmStrCat(CMakeCmd(), " -E copy $in $out");
+  rule.Command = cmStrCat(this->CMakeCmd(), " -E copy $in $out");
   rule.Description = "Copying OS X Content $out";
   rule.Comment = "Rule for copying OS X bundle content file.";
   this->AddRule(rule);
@@ -508,6 +555,7 @@ void cmGlobalNinjaGenerator::Generate()
   this->TargetAll = this->NinjaOutputPath("all");
   this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt");
   this->DisableCleandead = false;
+  this->DiagnosedCxxModuleSupport = false;
 
   this->PolicyCMP0058 =
     this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus(
@@ -709,6 +757,37 @@ bool cmGlobalNinjaGenerator::CheckLanguages(
   return true;
 }
 
+bool cmGlobalNinjaGenerator::CheckCxxModuleSupport()
+{
+  bool const diagnose = !this->DiagnosedCxxModuleSupport &&
+    !this->CMakeInstance->GetIsInTryCompile();
+  if (diagnose) {
+    this->DiagnosedCxxModuleSupport = true;
+    this->GetCMakeInstance()->IssueMessage(
+      MessageType::AUTHOR_WARNING,
+      "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP "
+      "is experimental.  It is meant only for compiler developers to try.");
+  }
+  if (this->NinjaSupportsDyndeps) {
+    return true;
+  }
+  if (diagnose) {
+    std::ostringstream e;
+    /* clang-format off */
+    e <<
+      "The Ninja generator does not support C++20 modules "
+      "using Ninja version \n"
+      "  " << this->NinjaVersion << "\n"
+      "due to lack of required features.  "
+      "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required."
+      ;
+    /* clang-format on */
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    cmSystemTools::SetFatalErrorOccured();
+  }
+  return false;
+}
+
 bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const
 {
   if (this->NinjaSupportsDyndeps) {
@@ -720,7 +799,8 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const
   e <<
     "The Ninja generator does not support Fortran using Ninja version\n"
     "  " << this->NinjaVersion << "\n"
-    "due to lack of required features.  Ninja 1.10 or higher is required."
+    "due to lack of required features.  "
+    "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required."
     ;
   /* clang-format on */
   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
@@ -739,7 +819,9 @@ bool cmGlobalNinjaGenerator::CheckISPC(cmMakefile* mf) const
   e <<
     "The Ninja generator does not support ISPC using Ninja version\n"
     "  " << this->NinjaVersion << "\n"
-    "due to lack of required features.  Ninja 1.10 or higher is required."
+    "due to lack of required features.  "
+    "Ninja " << RequiredNinjaVersionForMultipleOutputs() <<
+    " or higher is required."
     ;
   /* clang-format on */
   mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
@@ -986,8 +1068,8 @@ static void EnsureTrailingSlash(std::string& path)
 std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath(
   const std::string& path) const
 {
-  auto const f = ConvertToNinjaPathCache.find(path);
-  if (f != ConvertToNinjaPathCache.end()) {
+  auto const f = this->ConvertToNinjaPathCache.find(path);
+  if (f != this->ConvertToNinjaPathCache.end()) {
     return f->second;
   }
 
@@ -999,7 +1081,7 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath(
 #ifdef _WIN32
   std::replace(convPath.begin(), convPath.end(), '/', '\\');
 #endif
-  return ConvertToNinjaPathCache.emplace(path, std::move(convPath))
+  return this->ConvertToNinjaPathCache.emplace(path, std::move(convPath))
     .first->second;
 }
 
@@ -1057,7 +1139,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
   }
 }
 
-void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
+void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) const
 {
   os << "# CMAKE generated file: DO NOT EDIT!\n"
      << "# Generated by \"" << this->GetName() << "\""
@@ -1071,12 +1153,13 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
     cmNinjaDeps orderOnlyDeps;
     std::copy(asd.second.begin(), asd.second.end(),
               std::back_inserter(orderOnlyDeps));
-    WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
-                            "Assume dependencies for generated source file.",
-                            /*depfile*/ "", /*job_pool*/ "",
-                            /*uses_terminal*/ false,
-                            /*restat*/ true, cmNinjaDeps(1, asd.first), "",
-                            cmNinjaDeps(), orderOnlyDeps);
+    this->WriteCustomCommandBuild(
+      /*command=*/"", /*description=*/"",
+      "Assume dependencies for generated source file.",
+      /*depfile*/ "", /*job_pool*/ "",
+      /*uses_terminal*/ false,
+      /*restat*/ true, cmNinjaDeps(1, asd.first), "", cmNinjaDeps(),
+      orderOnlyDeps);
   }
 }
 
@@ -1088,7 +1171,7 @@ std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget(
 
 void cmGlobalNinjaGenerator::AppendTargetOutputs(
   cmGeneratorTarget const* target, cmNinjaDeps& outputs,
-  const std::string& config, cmNinjaTargetDepends depends)
+  const std::string& config, cmNinjaTargetDepends depends) const
 {
   // for frameworks, we want the real name, not smple name
   // frameworks always appear versioned, and the build.ninja
@@ -1101,7 +1184,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs(
     case cmStateEnums::STATIC_LIBRARY:
     case cmStateEnums::MODULE_LIBRARY: {
       if (depends == DependOnTargetOrdering) {
-        outputs.push_back(OrderDependsTargetForTarget(target, config));
+        outputs.push_back(this->OrderDependsTargetForTarget(target, config));
         break;
       }
     }
@@ -1113,7 +1196,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs(
     }
     case cmStateEnums::OBJECT_LIBRARY: {
       if (depends == DependOnTargetOrdering) {
-        outputs.push_back(OrderDependsTargetForTarget(target, config));
+        outputs.push_back(this->OrderDependsTargetForTarget(target, config));
         break;
       }
     }
@@ -1194,23 +1277,30 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
 
 void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
   cmGeneratorTarget const* target, cmNinjaDeps& outputs,
-  const std::string& config)
+  const std::string& config, const std::string& fileConfig, bool genexOutput)
 {
   cmNinjaOuts outs;
-  this->AppendTargetDependsClosure(target, outs, config, true);
+  this->AppendTargetDependsClosure(target, outs, config, fileConfig,
+                                   genexOutput, true);
   cm::append(outputs, outs);
 }
 
 void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
   cmGeneratorTarget const* target, cmNinjaOuts& outputs,
-  const std::string& config, bool omit_self)
+  const std::string& config, const std::string& fileConfig, bool genexOutput,
+  bool omit_self)
 {
 
   // try to locate the target in the cache
-  auto find = this->Configs[config].TargetDependsClosures.lower_bound(target);
+  ByConfig::TargetDependsClosureKey key{
+    target,
+    config,
+    genexOutput,
+  };
+  auto find = this->Configs[fileConfig].TargetDependsClosures.lower_bound(key);
 
-  if (find == this->Configs[config].TargetDependsClosures.end() ||
-      find->first != target) {
+  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
@@ -1220,18 +1310,27 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
     cmNinjaOuts this_outs; // this will be the new cache entry
 
     for (auto const& dep_target : this->GetTargetDirectDepends(target)) {
-      if (!dep_target->IsInBuildSystem() ||
-          (target->GetType() != cmStateEnums::UTILITY &&
-           dep_target->GetType() != cmStateEnums::UTILITY &&
-           this->EnableCrossConfigBuild() && !dep_target.IsCross())) {
+      if (!dep_target->IsInBuildSystem()) {
+        continue;
+      }
+
+      if (!this->IsSingleConfigUtility(target) &&
+          !this->IsSingleConfigUtility(dep_target) &&
+          this->EnableCrossConfigBuild() && !dep_target.IsCross() &&
+          !genexOutput) {
         continue;
       }
 
-      // Collect the dependent targets for _this_ target
-      this->AppendTargetDependsClosure(dep_target, this_outs, config, false);
+      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);
+      }
     }
-    find = this->Configs[config].TargetDependsClosures.emplace_hint(
-      find, target, std::move(this_outs));
+    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
@@ -1414,7 +1513,7 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
       build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config);
       configDeps.emplace_back(build.Outputs.front());
       for (DirectoryTarget::Target const& t : dt.Targets) {
-        if (!IsExcludedFromAllInConfig(t, config)) {
+        if (!this->IsExcludedFromAllInConfig(t, config)) {
           this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config,
                                     DependOnTargetArtifact);
         }
@@ -1627,7 +1726,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
   {
     cmNinjaRule rule("RERUN_CMAKE");
     rule.Command =
-      cmStrCat(CMakeCmd(), " --regenerate-during-build -S",
+      cmStrCat(this->CMakeCmd(), " --regenerate-during-build -S",
                lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
                                          cmOutputConverter::SHELL),
                " -B",
@@ -1652,7 +1751,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
 
   // Use 'console' pool to get non buffered output of the CMake re-run call
   // Available since Ninja 1.5
-  if (SupportsConsolePool()) {
+  if (this->SupportsConsolePool()) {
     reBuild.Variables["pool"] = "console";
   }
 
@@ -1661,7 +1760,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
     {
       cmNinjaRule rule("VERIFY_GLOBS");
       rule.Command =
-        cmStrCat(CMakeCmd(), " -P ",
+        cmStrCat(this->CMakeCmd(), " -P ",
                  lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
                                            cmOutputConverter::SHELL));
       rule.Description = "Re-checking globbed directories...";
@@ -1722,8 +1821,8 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
     build.Comment = "A missing CMake input file is not an error.";
     std::set_difference(std::make_move_iterator(reBuild.ImplicitDeps.begin()),
                         std::make_move_iterator(reBuild.ImplicitDeps.end()),
-                        CustomCommandOutputs.begin(),
-                        CustomCommandOutputs.end(),
+                        this->CustomCommandOutputs.begin(),
+                        this->CustomCommandOutputs.end(),
                         std::back_inserter(build.Outputs));
     this->WriteBuild(os, build);
   }
@@ -1807,7 +1906,8 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
         fout << "  file(REMOVE_RECURSE\n";
         for (std::string const& acf : it->second.AdditionalCleanFiles) {
           fout << "  "
-               << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf))
+               << cmOutputConverter::EscapeForCMake(
+                    this->ConvertToNinjaPath(acf))
                << '\n';
         }
         fout << "  )\n";
@@ -1822,7 +1922,7 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
   {
     cmNinjaRule rule("CLEAN_ADDITIONAL");
     rule.Command = cmStrCat(
-      CMakeCmd(), " -DCONFIG=$CONFIG -P ",
+      this->CMakeCmd(), " -DCONFIG=$CONFIG -P ",
       lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel),
                                  cmOutputConverter::SHELL));
     rule.Description = "Cleaning additional files...";
@@ -1839,13 +1939,13 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
       build.Outputs.front() = this->BuildAlias(
         this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), config);
       build.Variables["CONFIG"] = config;
-      WriteBuild(os, build);
+      this->WriteBuild(os, build);
     }
     if (this->IsMultiConfig()) {
       build.Outputs.front() =
         this->NinjaOutputPath(this->GetAdditionalCleanTargetName());
       build.Variables["CONFIG"] = "";
-      WriteBuild(os, build);
+      this->WriteBuild(os, build);
     }
   }
   // Return success
@@ -1855,13 +1955,13 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
 void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
 {
   // -- Additional clean target
-  bool additionalFiles = WriteTargetCleanAdditional(os);
+  bool additionalFiles = this->WriteTargetCleanAdditional(os);
 
   // -- Default clean target
   // Write rule
   {
     cmNinjaRule rule("CLEAN");
-    rule.Command = cmStrCat(NinjaCmd(), " $FILE_ARG -t clean $TARGETS");
+    rule.Command = cmStrCat(this->NinjaCmd(), " $FILE_ARG -t clean $TARGETS");
     rule.Description = "Cleaning all built files...";
     rule.Comment = "Rule for cleaning all built files.";
     WriteRule(*this->RulesFileStream, rule);
@@ -1962,13 +2062,13 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
     build.Outputs.emplace_back(
       this->ConvertToNinjaPath(GetByproductsForCleanTargetName()));
     build.ExplicitDeps = this->ByproductsForCleanTarget;
-    WriteBuild(os, build);
+    this->WriteBuild(os, build);
 
     for (auto const& config : configs) {
       build.Outputs.front() = this->BuildAlias(
         this->ConvertToNinjaPath(GetByproductsForCleanTargetName()), config);
       build.ExplicitDeps = this->Configs[config].ByproductsForCleanTarget;
-      WriteBuild(os, build);
+      this->WriteBuild(os, build);
     }
   }
 }
@@ -1977,7 +2077,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
 {
   {
     cmNinjaRule rule("HELP");
-    rule.Command = cmStrCat(NinjaCmd(), " -t targets");
+    rule.Command = cmStrCat(this->NinjaCmd(), " -t targets");
     rule.Description = "All primary targets available:";
     rule.Comment = "Rule for printing all primary targets available.";
     WriteRule(*this->RulesFileStream, rule);
@@ -1986,7 +2086,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
     cmNinjaBuild build("HELP");
     build.Comment = "Print all primary targets available.";
     build.Outputs.push_back(this->NinjaOutputPath("help"));
-    WriteBuild(os, build);
+    this->WriteBuild(os, build);
   }
 }
 
@@ -2017,6 +2117,8 @@ void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix(
   cmStripSuffixIfExists(path, this->OutputPathPrefix);
 }
 
+#if !defined(CMAKE_BOOTSTRAP)
+
 /*
 
 We use the following approach to support Fortran.  Each target already
@@ -2096,16 +2198,6 @@ Compilation of source files within a target is split into the following steps:
    (because the latter consumes the module).
 */
 
-struct cmSourceInfo
-{
-  // Set of provided and required modules.
-  std::set<std::string> Provides;
-  std::set<std::string> Requires;
-
-  // Set of files included in the translation unit.
-  std::set<std::string> Includes;
-};
-
 static std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
   std::string const& arg_tdi, std::string const& arg_pp);
 
@@ -2113,6 +2205,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
                               std::vector<std::string>::const_iterator argEnd)
 {
   std::string arg_tdi;
+  std::string arg_src;
   std::string arg_pp;
   std::string arg_dep;
   std::string arg_obj;
@@ -2121,6 +2214,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
   for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
     if (cmHasLiteralPrefix(arg, "--tdi=")) {
       arg_tdi = arg.substr(6);
+    } else if (cmHasLiteralPrefix(arg, "--src=")) {
+      arg_src = arg.substr(6);
     } else if (cmHasLiteralPrefix(arg, "--pp=")) {
       arg_pp = arg.substr(5);
     } else if (cmHasLiteralPrefix(arg, "--dep=")) {
@@ -2161,6 +2256,9 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
     cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang=");
     return 1;
   }
+  if (arg_src.empty()) {
+    arg_src = cmStrCat("<", arg_obj, " input file>");
+  }
 
   std::unique_ptr<cmSourceInfo> info;
   if (arg_lang == "Fortran") {
@@ -2177,6 +2275,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
     return 1;
   }
 
+  info->PrimaryOutput = arg_obj;
+
   {
     cmGeneratedFileStream depfile(arg_dep);
     depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":";
@@ -2186,24 +2286,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
     depfile << "\n";
   }
 
-  Json::Value ddi(Json::objectValue);
-  ddi["object"] = arg_obj;
-
-  Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue;
-  for (std::string const& provide : info->Provides) {
-    ddi_provides.append(provide);
-  }
-  Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue;
-  for (std::string const& r : info->Requires) {
-    // Require modules not provided in the same source.
-    if (!info->Provides.count(r)) {
-      ddi_requires.append(r);
-    }
-  }
-
-  cmGeneratedFileStream ddif(arg_ddi);
-  ddif << ddi;
-  if (!ddif) {
+  if (!cmScanDepFormat_P1689_Write(arg_ddi, arg_src, *info)) {
     cmSystemTools::Error(
       cmStrCat("-E cmake_ninja_depends failed to write ", arg_ddi));
     return 1;
@@ -2261,26 +2344,35 @@ std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
   }
 
   auto info = cm::make_unique<cmSourceInfo>();
-  info->Provides = finfo.Provides;
-  info->Requires = finfo.Requires;
-  info->Includes = finfo.Includes;
+  for (std::string const& provide : finfo.Provides) {
+    cmSourceReqInfo src_info;
+    src_info.LogicalName = provide;
+    src_info.CompiledModulePath = provide;
+    info->Provides.emplace_back(src_info);
+  }
+  for (std::string const& require : finfo.Requires) {
+    // Require modules not provided in the same source.
+    if (finfo.Provides.count(require)) {
+      continue;
+    }
+    cmSourceReqInfo src_info;
+    src_info.LogicalName = require;
+    src_info.CompiledModulePath = require;
+    info->Requires.emplace_back(src_info);
+  }
+  for (std::string const& include : finfo.Includes) {
+    info->Includes.push_back(include);
+  }
   return info;
 }
 
-struct cmDyndepObjectInfo
-{
-  std::string Object;
-  std::vector<std::string> Provides;
-  std::vector<std::string> Requires;
-};
-
 bool cmGlobalNinjaGenerator::WriteDyndepFile(
   std::string const& dir_top_src, std::string const& dir_top_bld,
   std::string const& dir_cur_src, std::string const& dir_cur_bld,
   std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
   std::string const& module_dir,
   std::vector<std::string> const& linked_target_dirs,
-  std::string const& arg_lang)
+  std::string const& arg_lang, std::string const& arg_modmapfmt)
 {
   // Setup path conversions.
   {
@@ -2295,34 +2387,14 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
     this->LocalGenerators.push_back(std::move(lgd));
   }
 
-  std::vector<cmDyndepObjectInfo> objects;
+  std::vector<cmSourceInfo> objects;
   for (std::string const& arg_ddi : arg_ddis) {
-    // Load the ddi file and compute the module file paths it provides.
-    Json::Value ddio;
-    Json::Value const& ddi = ddio;
-    cmsys::ifstream ddif(arg_ddi.c_str(), std::ios::in | std::ios::binary);
-    Json::Reader reader;
-    if (!reader.parse(ddif, ddio, false)) {
-      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
-                                    arg_ddi,
-                                    reader.getFormattedErrorMessages()));
+    cmSourceInfo info;
+    if (!cmScanDepFormat_P1689_Parse(arg_ddi, &info)) {
+      cmSystemTools::Error(
+        cmStrCat("-E cmake_ninja_dyndep failed to parse ddi file ", arg_ddi));
       return false;
     }
-
-    cmDyndepObjectInfo info;
-    info.Object = ddi["object"].asString();
-    Json::Value const& ddi_provides = ddi["provides"];
-    if (ddi_provides.isArray()) {
-      for (auto const& ddi_provide : ddi_provides) {
-        info.Provides.push_back(ddi_provide.asString());
-      }
-    }
-    Json::Value const& ddi_requires = ddi["requires"];
-    if (ddi_requires.isArray()) {
-      for (auto const& ddi_require : ddi_requires) {
-        info.Requires.push_back(ddi_require.asString());
-      }
-    }
     objects.push_back(std::move(info));
   }
 
@@ -2353,11 +2425,12 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
   // We do this after loading the modules provided by linked targets
   // in case we have one of the same name that must be preferred.
   Json::Value tm = Json::objectValue;
-  for (cmDyndepObjectInfo const& object : objects) {
-    for (std::string const& p : object.Provides) {
-      std::string const mod = cmStrCat(module_dir, p);
-      mod_files[p] = mod;
-      tm[p] = mod;
+  for (cmSourceInfo const& object : objects) {
+    for (auto const& p : object.Provides) {
+      std::string const mod = cmStrCat(
+        module_dir, cmSystemTools::GetFilenameName(p.CompiledModulePath));
+      mod_files[p.LogicalName] = mod;
+      tm[p.LogicalName] = mod;
     }
   }
 
@@ -2367,15 +2440,16 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
   {
     cmNinjaBuild build("dyndep");
     build.Outputs.emplace_back("");
-    for (cmDyndepObjectInfo const& object : objects) {
-      build.Outputs[0] = object.Object;
+    for (cmSourceInfo const& object : objects) {
+      build.Outputs[0] = this->ConvertToNinjaPath(object.PrimaryOutput);
       build.ImplicitOuts.clear();
-      for (std::string const& p : object.Provides) {
-        build.ImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p]));
+      for (auto const& p : object.Provides) {
+        build.ImplicitOuts.push_back(
+          this->ConvertToNinjaPath(mod_files[p.LogicalName]));
       }
       build.ImplicitDeps.clear();
-      for (std::string const& r : object.Requires) {
-        auto mit = mod_files.find(r);
+      for (auto const& r : object.Requires) {
+        auto mit = mod_files.find(r.LogicalName);
         if (mit != mod_files.end()) {
           build.ImplicitDeps.push_back(this->ConvertToNinjaPath(mit->second));
         }
@@ -2385,6 +2459,48 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
         build.Variables.emplace("restat", "1");
       }
 
+      if (arg_modmapfmt.empty()) {
+        // nothing to do.
+      } else {
+        std::stringstream mm;
+        if (arg_modmapfmt == "gcc") {
+          // Documented in GCC's documentation. The format is a series of lines
+          // with a module name and the associated filename separated by
+          // spaces. The first line may use `$root` as the module name to
+          // specify a "repository root". That is used to anchor any relative
+          // paths present in the file (CMake should never generate any).
+
+          // Write the root directory to use for module paths.
+          mm << "$root .\n";
+
+          for (auto const& l : object.Provides) {
+            auto m = mod_files.find(l.LogicalName);
+            if (m != mod_files.end()) {
+              mm << l.LogicalName << " " << this->ConvertToNinjaPath(m->second)
+                 << "\n";
+            }
+          }
+          for (auto const& r : object.Requires) {
+            auto m = mod_files.find(r.LogicalName);
+            if (m != mod_files.end()) {
+              mm << r.LogicalName << " " << this->ConvertToNinjaPath(m->second)
+                 << "\n";
+            }
+          }
+        } else {
+          cmSystemTools::Error(
+            cmStrCat("-E cmake_ninja_dyndep does not understand the ",
+                     arg_modmapfmt, " module map format"));
+          return false;
+        }
+
+        // XXX(modmap): If changing this path construction, change
+        // `cmNinjaTargetGenerator::WriteObjectBuildStatements` to generate the
+        // corresponding file path.
+        cmGeneratedFileStream mmf(cmStrCat(object.PrimaryOutput, ".modmap"));
+        mmf << mm.str();
+      }
+
       this->WriteBuild(ddf, build);
     }
   }
@@ -2399,11 +2515,6 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
   return true;
 }
 
-bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const
-{
-  return !this->CrossConfigs.empty();
-}
-
 int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
                              std::vector<std::string>::const_iterator argEnd)
 {
@@ -2413,6 +2524,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
   std::string arg_dd;
   std::string arg_lang;
   std::string arg_tdi;
+  std::string arg_modmapfmt;
   std::vector<std::string> arg_ddis;
   for (std::string const& arg : arg_full) {
     if (cmHasLiteralPrefix(arg, "--tdi=")) {
@@ -2421,6 +2533,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
       arg_lang = arg.substr(7);
     } else if (cmHasLiteralPrefix(arg, "--dd=")) {
       arg_dd = arg.substr(5);
+    } else if (cmHasLiteralPrefix(arg, "--modmapfmt=")) {
+      arg_modmapfmt = arg.substr(12);
     } else if (!cmHasLiteralPrefix(arg, "--") &&
                cmHasLiteralSuffix(arg, ".ddi")) {
       arg_ddis.push_back(arg);
@@ -2479,12 +2593,19 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
   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)) {
+        module_dir, linked_target_dirs, arg_lang, arg_modmapfmt)) {
     return 1;
   }
   return 0;
 }
 
+#endif
+
+bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const
+{
+  return !this->CrossConfigs.empty();
+}
+
 void cmGlobalNinjaGenerator::AppendDirectoryForConfig(
   const std::string& prefix, const std::string& config,
   const std::string& suffix, std::string& dir)
@@ -2502,6 +2623,13 @@ std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs(
   return result;
 }
 
+bool cmGlobalNinjaGenerator::IsSingleConfigUtility(
+  cmGeneratorTarget const* target) const
+{
+  return target->GetType() == cmStateEnums::UTILITY &&
+    !this->PerConfigUtilityTargets.count(target->GetName());
+}
+
 const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE =
   "CMakeFiles/common.ninja";
 const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja";
@@ -2548,33 +2676,35 @@ bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams()
     << "# This file contains build statements common to all "
        "configurations.\n\n";
 
-  for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs(
-         cmMakefile::IncludeEmptyConfig)) {
-    // Open impl file.
-    if (!this->OpenFileStream(this->ImplFileStreams[config],
-                              GetNinjaImplFilename(config))) {
-      return false;
-    }
+  auto const& configs =
+    this->Makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+  return std::all_of(
+    configs.begin(), configs.end(), [this](std::string const& config) -> bool {
+      // Open impl file.
+      if (!this->OpenFileStream(this->ImplFileStreams[config],
+                                GetNinjaImplFilename(config))) {
+        return false;
+      }
 
-    // Write a comment about this file.
-    *this->ImplFileStreams[config]
-      << "# This file contains build statements specific to the \"" << config
-      << "\"\n# configuration.\n\n";
+      // Write a comment about this file.
+      *this->ImplFileStreams[config]
+        << "# This file contains build statements specific to the \"" << config
+        << "\"\n# configuration.\n\n";
 
-    // Open config file.
-    if (!this->OpenFileStream(this->ConfigFileStreams[config],
-                              GetNinjaConfigFilename(config))) {
-      return false;
-    }
+      // Open config file.
+      if (!this->OpenFileStream(this->ConfigFileStreams[config],
+                                GetNinjaConfigFilename(config))) {
+        return false;
+      }
 
-    // Write a comment about this file.
-    *this->ConfigFileStreams[config]
-      << "# This file contains aliases specific to the \"" << config
-      << "\"\n# configuration.\n\n"
-      << "include " << GetNinjaImplFilename(config) << "\n\n";
-  }
+      // Write a comment about this file.
+      *this->ConfigFileStreams[config]
+        << "# This file contains aliases specific to the \"" << config
+        << "\"\n# configuration.\n\n"
+        << "include " << GetNinjaImplFilename(config) << "\n\n";
 
-  return true;
+      return true;
+    });
 }
 
 void cmGlobalNinjaMultiGenerator::CloseBuildFileStreams()
@@ -2652,30 +2782,17 @@ void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs(
 
 bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables()
 {
-  this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_BUILD_TYPE");
-  this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_CROSS_CONFIGS");
-  this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_CONFIGS");
-  return this->ReadCacheEntriesForBuild(*this->Makefiles.front()->GetState());
-}
-
-std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const
-{
-  return "";
-}
-
-bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
-  const cmState& state)
-{
   std::vector<std::string> configsVec;
-  cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CONFIGURATION_TYPES"),
-               configsVec);
+  cmExpandList(
+    this->Makefiles.front()->GetSafeDefinition("CMAKE_CONFIGURATION_TYPES"),
+    configsVec);
   if (configsVec.empty()) {
     configsVec.emplace_back();
   }
   std::set<std::string> configs(configsVec.cbegin(), configsVec.cend());
 
   this->DefaultFileConfig =
-    state.GetSafeCacheEntryValue("CMAKE_DEFAULT_BUILD_TYPE");
+    this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_BUILD_TYPE");
   if (this->DefaultFileConfig.empty()) {
     this->DefaultFileConfig = configsVec.front();
   }
@@ -2690,8 +2807,9 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
   }
 
   std::vector<std::string> crossConfigsVec;
-  cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CROSS_CONFIGS"),
-               crossConfigsVec);
+  cmExpandList(
+    this->Makefiles.front()->GetSafeDefinition("CMAKE_CROSS_CONFIGS"),
+    crossConfigsVec);
   auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec);
   if (!crossConfigs) {
     std::ostringstream msg;
@@ -2704,7 +2822,7 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
   this->CrossConfigs = *crossConfigs;
 
   auto defaultConfigsString =
-    state.GetSafeCacheEntryValue("CMAKE_DEFAULT_CONFIGS");
+    this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_CONFIGS");
   if (defaultConfigsString.empty()) {
     defaultConfigsString = this->DefaultFileConfig;
   }
@@ -2738,6 +2856,11 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
   return true;
 }
 
+std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const
+{
+  return "";
+}
+
 std::string cmGlobalNinjaMultiGenerator::OrderDependsTargetForTarget(
   cmGeneratorTarget const* target, const std::string& config) const
 {
index b668773..0c919ef 100644 (file)
@@ -24,6 +24,7 @@
 #include "cmNinjaTypes.h"
 #include "cmPolicies.h"
 #include "cmStringAlgorithms.h"
+#include "cmTransformDepfile.h"
 
 class cmCustomCommand;
 class cmGeneratorTarget;
@@ -31,7 +32,6 @@ class cmLinkLineComputer;
 class cmLocalGenerator;
 class cmMakefile;
 class cmOutputConverter;
-class cmState;
 class cmStateDirectory;
 class cmake;
 struct cmDocumentationEntry;
@@ -150,9 +150,8 @@ public:
   static void WriteDefault(std::ostream& os, const cmNinjaDeps& targets,
                            const std::string& comment = "");
 
-  bool IsGCCOnWindows() const { return UsingGCCOnWindows; }
+  bool IsGCCOnWindows() const { return this->UsingGCCOnWindows; }
 
-public:
   cmGlobalNinjaGenerator(cmake* cm);
 
   static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
@@ -171,6 +170,8 @@ public:
 
   static std::string GetActualName() { return "Ninja"; }
 
+  bool IsNinja() const override { return true; }
+
   /** Get encoding used by generator for ninja files */
   codecvt::Encoding GetMakefileEncoding() const override;
 
@@ -211,6 +212,10 @@ public:
   const char* GetCleanTargetName() const override { return "clean"; }
 
   bool SupportsCustomCommandDepfile() const override { return true; }
+  cm::optional<cmDepfileFormat> DepfileFormat() const override
+  {
+    return cmDepfileFormat::GccDepfile;
+  }
 
   virtual cmGeneratedFileStream* GetImplFileStream(
     const std::string& /*config*/) const
@@ -248,7 +253,7 @@ public:
       : GG(gg)
     {
     }
-    std::string operator()(std::string const& path)
+    std::string operator()(std::string const& path) const
     {
       return this->GG->ConvertToNinjaPath(path);
     }
@@ -319,17 +324,21 @@ public:
 
   void AppendTargetOutputs(cmGeneratorTarget const* target,
                            cmNinjaDeps& outputs, const std::string& config,
-                           cmNinjaTargetDepends depends);
+                           cmNinjaTargetDepends depends) const;
   void AppendTargetDepends(cmGeneratorTarget const* target,
                            cmNinjaDeps& outputs, const std::string& config,
                            const std::string& fileConfig,
                            cmNinjaTargetDepends depends);
   void AppendTargetDependsClosure(cmGeneratorTarget const* target,
                                   cmNinjaDeps& outputs,
-                                  const std::string& config);
+                                  const std::string& config,
+                                  const std::string& fileConfig,
+                                  bool genexOutput);
   void AppendTargetDependsClosure(cmGeneratorTarget const* target,
                                   cmNinjaOuts& outputs,
-                                  const std::string& config, bool omit_self);
+                                  const std::string& config,
+                                  const std::string& fileConfig,
+                                  bool genexOutput, bool omit_self);
 
   void AppendDirectoryForConfig(const std::string& prefix,
                                 const std::string& config,
@@ -346,7 +355,10 @@ public:
     outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
   }
 
-  int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
+  int GetRuleCmdLength(const std::string& name)
+  {
+    return this->RuleCmdLength[name];
+  }
 
   void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target,
                       const std::string& config);
@@ -385,15 +397,13 @@ public:
   bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
   void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
 
-  bool WriteDyndepFile(std::string const& dir_top_src,
-                       std::string const& dir_top_bld,
-                       std::string const& dir_cur_src,
-                       std::string const& dir_cur_bld,
-                       std::string const& arg_dd,
-                       std::vector<std::string> const& arg_ddis,
-                       std::string const& module_dir,
-                       std::vector<std::string> const& linked_target_dirs,
-                       std::string const& arg_lang);
+  bool WriteDyndepFile(
+    std::string const& dir_top_src, std::string const& dir_top_bld,
+    std::string const& dir_cur_src, std::string const& dir_cur_bld,
+    std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
+    std::string const& module_dir,
+    std::vector<std::string> const& linked_target_dirs,
+    std::string const& arg_lang, std::string const& arg_modmapfmt);
 
   virtual std::string BuildAlias(const std::string& alias,
                                  const std::string& /*config*/) const
@@ -425,6 +435,20 @@ public:
     return this->DefaultConfigs;
   }
 
+  const std::set<std::string>& GetPerConfigUtilityTargets() const
+  {
+    return this->PerConfigUtilityTargets;
+  }
+
+  void AddPerConfigUtilityTarget(const std::string& name)
+  {
+    this->PerConfigUtilityTargets.insert(name);
+  }
+
+  bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
+
+  bool CheckCxxModuleSupport();
+
 protected:
   void Generate() override;
 
@@ -462,7 +486,7 @@ private:
   void CleanMetaData();
 
   /// Write the common disclaimer text at the top of each build file.
-  void WriteDisclaimer(std::ostream& os);
+  void WriteDisclaimer(std::ostream& os) const;
 
   void WriteAssumedSourceDependencies();
 
@@ -518,6 +542,9 @@ private:
   /// The mapping from source file to assumed dependencies.
   std::map<std::string, std::set<std::string>> AssumedSourceDependencies;
 
+  /// Utility targets which have per-config outputs
+  std::set<std::string> PerConfigUtilityTargets;
+
   struct TargetAlias
   {
     cmGeneratorTarget* GeneratorTarget;
@@ -542,7 +569,8 @@ private:
   bool NinjaSupportsMultipleOutputs = false;
   bool NinjaSupportsMetadataOnRegeneration = false;
 
-private:
+  bool DiagnosedCxxModuleSupport = false;
+
   void InitOutputPathPrefix();
 
   std::string OutputPathPrefix;
@@ -557,7 +585,14 @@ private:
     /// The set of custom commands we have seen.
     std::set<cmCustomCommand const*> CustomCommands;
 
-    std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures;
+    struct TargetDependsClosureKey
+    {
+      cmGeneratorTarget const* Target;
+      std::string Config;
+      bool GenexOutput;
+    };
+
+    std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures;
 
     TargetAliasMap TargetAliases;
 
@@ -566,6 +601,19 @@ private:
   std::map<std::string, ByConfig> Configs;
 
   cmNinjaDeps ByproductsForCleanTarget;
+
+  friend bool operator==(const ByConfig::TargetDependsClosureKey& lhs,
+                         const ByConfig::TargetDependsClosureKey& rhs);
+  friend bool operator!=(const ByConfig::TargetDependsClosureKey& lhs,
+                         const ByConfig::TargetDependsClosureKey& rhs);
+  friend bool operator<(const ByConfig::TargetDependsClosureKey& lhs,
+                        const ByConfig::TargetDependsClosureKey& rhs);
+  friend bool operator>(const ByConfig::TargetDependsClosureKey& lhs,
+                        const ByConfig::TargetDependsClosureKey& rhs);
+  friend bool operator<=(const ByConfig::TargetDependsClosureKey& lhs,
+                         const ByConfig::TargetDependsClosureKey& rhs);
+  friend bool operator>=(const ByConfig::TargetDependsClosureKey& lhs,
+                         const ByConfig::TargetDependsClosureKey& rhs);
 };
 
 class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator
@@ -651,8 +699,6 @@ public:
 
   std::string GetDefaultBuildConfig() const override;
 
-  bool ReadCacheEntriesForBuild(const cmState& state) override;
-
   bool SupportsDefaultBuildType() const override { return true; }
   bool SupportsCrossConfigs() const override { return true; }
   bool SupportsDefaultConfigs() const override { return true; }
index 2c934e1..97384cd 100644 (file)
@@ -44,6 +44,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm)
 #endif
 
   this->IncludeDirective = "include";
+  this->LineContinueDirective = "\\\n";
   this->DefineWindowsNULL = false;
   this->PassMakeflags = false;
   this->UnixCD = true;
@@ -589,10 +590,16 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   }
   makeCommand.Add(this->SelectMakeProgram(makeProgram));
 
+  // Explicitly tell the make tool to use the Makefile written by
+  // cmLocalUnixMakefileGenerator3::WriteLocalMakefile
+  makeCommand.Add("-f");
+  makeCommand.Add("Makefile");
+
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.Add("-j");
-    if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.Add(std::to_string(jobs));
+    if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+      makeCommand.Add("-j");
+    } else {
+      makeCommand.Add("-j" + std::to_string(jobs));
     }
   }
 
@@ -831,7 +838,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
     for (const auto& gt : lg->GetGeneratorTargets()) {
       cmLocalGenerator* tlg = gt->GetLocalGenerator();
 
-      if (!gt->IsInBuildSystem() || IsExcluded(lg.get(), gt.get())) {
+      if (!gt->IsInBuildSystem() || this->IsExcluded(lg.get(), gt.get())) {
         continue;
       }
 
index 77d0827..7c950cc 100644 (file)
@@ -93,6 +93,12 @@ public:
    */
   static bool SupportsPlatform() { return false; }
 
+  /**
+   * Utilized to determine if this generator
+   * supports DEPFILE option.
+   */
+  bool SupportsCustomCommandDepfile() const override { return true; }
+
   /** Get the documentation entry for this generator.  */
   static void GetDocumentation(cmDocumentationEntry& entry);
 
@@ -127,6 +133,18 @@ public:
   void WriteConvenienceRules(std::ostream& ruleFileStream,
                              std::set<std::string>& emitted);
 
+  // Make tool supports dependency files generated by compiler
+  bool SupportsCompilerDependencies() const
+  {
+    return this->ToolSupportsCompilerDependencies;
+  }
+
+  // Make tool supports long line dependencies
+  bool SupportsLongLineDependencies() const
+  {
+    return this->ToolSupportsLongLineDependencies;
+  }
+
   /** Get the command to use for a target that has no rule.  This is
       used for multiple output dependencies and for cmake_force.  */
   std::string GetEmptyRuleHackCommand() { return this->EmptyRuleHackCommand; }
@@ -170,6 +188,7 @@ public:
   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
 
   std::string IncludeDirective;
+  std::string LineContinueDirective;
   bool DefineWindowsNULL;
   bool PassMakeflags;
   bool UnixCD;
@@ -218,6 +237,14 @@ protected:
 
   bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; }
 
+  // Specify if the make tool is able to consume dependency files
+  // generated by the compiler
+  bool ToolSupportsCompilerDependencies = true;
+
+  // some Make generator, such as Borland not support long line dependencies,
+  // we add SupportsLongLineDependencies to predicate.
+  bool ToolSupportsLongLineDependencies = true;
+
   // Some make programs (Borland) do not keep a rule if there are no
   // dependencies or commands.  This is a problem for creating rules
   // that might not do anything but might have other dependencies
index 6267205..75cd714 100644 (file)
@@ -380,9 +380,10 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
       std::string project = target->GetName();
       std::string location = *expath;
 
-      cmProp p = target->GetProperty("VS_PROJECT_TYPE");
-      this->WriteExternalProject(fout, project, location, cmToCStr(p),
-                                 target->GetUtilities());
+      this->WriteExternalProject(
+        fout, project, location,
+        cmToCStr(target->GetProperty("VS_PROJECT_TYPE")),
+        target->GetUtilities());
       written = true;
     } else {
       cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME");
index fcdfc50..b19212e 100644 (file)
@@ -108,9 +108,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
   std::vector<std::string> no_byproducts;
   std::vector<std::string> no_depends;
   cmCustomCommandLines no_commands;
-  cmTarget* tgt = lg.AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
-                                       no_working_directory, no_byproducts,
-                                       no_depends, no_commands);
+  cmTarget* tgt = lg.AddUtilityCommand(
+    CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, no_working_directory,
+    no_byproducts, no_depends, no_commands, cmPolicies::NEW);
 
   auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg);
   auto gt = ptr.get();
@@ -160,10 +160,11 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
       std::vector<std::string> byproducts;
       byproducts.push_back(cm->GetGlobVerifyStamp());
 
-      lg.AddCustomCommandToTarget(
-        CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts, no_depends,
-        verifyCommandLines, cmCustomCommandType::PRE_BUILD,
-        "Checking File Globs", no_working_directory, stdPipesUTF8);
+      lg.AddCustomCommandToTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts,
+                                  no_depends, verifyCommandLines,
+                                  cmCustomCommandType::PRE_BUILD,
+                                  "Checking File Globs", no_working_directory,
+                                  cmPolicies::NEW, stdPipesUTF8);
 
       // Ensure ZERO_CHECK always runs in Visual Studio using MSBuild,
       // otherwise the prebuild command will not be run.
@@ -195,8 +196,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
     if (cmSourceFile* file = lg.AddCustomCommandToOutput(
           stamps, no_byproducts, listFiles, no_main_dependency,
           no_implicit_depends, commandLines, "Checking Build System",
-          no_working_directory, true, false, false, false, "", "",
-          stdPipesUTF8)) {
+          no_working_directory, cmPolicies::NEW, true, false, false, false, "",
+          "", stdPipesUTF8)) {
       gt->AddSource(file->ResolveFullPath());
     } else {
       cmSystemTools::Error("Error adding rule for " + stamps[0]);
index 001d876..c23ee94 100644 (file)
@@ -200,7 +200,7 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets()
       // considered always out of date.
       cmTarget* allBuild = gen[0]->AddUtilityCommand(
         "ALL_BUILD", true, no_working_dir, no_byproducts, no_depends,
-        no_commands, false, "Build all projects");
+        no_commands, cmPolicies::NEW, false, "Build all projects");
 
       gen[0]->AddGeneratorTarget(
         cm::make_unique<cmGeneratorTarget>(allBuild, gen[0]));
index fb518a2..9a9a465 100644 (file)
@@ -205,6 +205,7 @@ public:
     platforms.emplace_back("Win32");
     platforms.emplace_back("ARM");
     platforms.emplace_back("ARM64");
+    platforms.emplace_back("ARM64EC");
     return platforms;
   }
 
index d6a7afa..3e2d92d 100644 (file)
@@ -25,6 +25,7 @@ cmGlobalWatcomWMakeGenerator::cmGlobalWatcomWMakeGenerator(cmake* cm)
 #endif
   cm->GetState()->SetWatcomWMake(true);
   this->IncludeDirective = "!include";
+  this->LineContinueDirective = "&\n";
   this->DefineWindowsNULL = true;
   this->UnixCD = false;
   this->MakeSilentFlag = "-h";
@@ -37,7 +38,6 @@ void cmGlobalWatcomWMakeGenerator::EnableLanguage(
   mf->AddDefinition("WATCOM", "1");
   mf->AddDefinition("CMAKE_QUOTE_INCLUDE_PATHS", "1");
   mf->AddDefinition("CMAKE_MANGLE_OBJECT_FILE_NAMES", "1");
-  mf->AddDefinition("CMAKE_MAKE_LINE_CONTINUE", "&");
   mf->AddDefinition("CMAKE_MAKE_SYMBOLIC_RULE", ".SYMBOLIC");
   mf->AddDefinition("CMAKE_GENERATOR_CC", "wcl386");
   mf->AddDefinition("CMAKE_GENERATOR_CXX", "wcl386");
index 5b44851..d6cc423 100644 (file)
 struct cmLinkImplementation;
 
 #if !defined(CMAKE_BOOTSTRAP) && defined(__APPLE__)
-#  define HAVE_APPLICATION_SERVICES
-#  include <ApplicationServices/ApplicationServices.h>
+#  include <CoreFoundation/CoreFoundation.h>
+#  if !TARGET_OS_IPHONE
+#    define HAVE_APPLICATION_SERVICES
+#    include <ApplicationServices/ApplicationServices.h>
+#  endif
 #endif
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -504,16 +507,15 @@ cmGlobalXCodeGenerator::GenerateBuildCommand(
     }
   }
 
-  if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+  if ((this->XcodeBuildSystem >= BuildSystem::Twelve) ||
+      (jobs != cmake::NO_BUILD_PARALLEL_LEVEL)) {
     makeCommand.Add("-parallelizeTargets");
   }
   makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
 
-  if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.Add("-jobs");
-    if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.Add(std::to_string(jobs));
-    }
+  if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
+      (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
+    makeCommand.Add("-jobs", std::to_string(jobs));
   }
 
   if (this->XcodeVersion >= 70) {
@@ -618,7 +620,8 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
   // Add ALL_BUILD
   cmTarget* allbuild = root->AddUtilityCommand(
     "ALL_BUILD", true, no_working_directory, no_byproducts, no_depends,
-    cmMakeSingleCommandLine({ "echo", "Build all projects" }));
+    cmMakeSingleCommandLine({ "echo", "Build all projects" }),
+    cmPolicies::NEW);
 
   root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root));
 
@@ -644,10 +647,10 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
     std::string file =
       this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile);
     cmSystemTools::ReplaceString(file, "\\ ", " ");
-    cmTarget* check =
-      root->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true,
-                              no_working_directory, no_byproducts, no_depends,
-                              cmMakeSingleCommandLine({ "make", "-f", file }));
+    cmTarget* check = root->AddUtilityCommand(
+      CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_working_directory,
+      no_byproducts, no_depends,
+      cmMakeSingleCommandLine({ "make", "-f", file }), cmPolicies::NEW);
 
     root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root));
   }
@@ -676,8 +679,9 @@ void cmGlobalXCodeGenerator::AddExtraTargets(
         gen->AddCustomCommandToTarget(
           target->GetName(), no_byproducts, no_depends,
           legacyDependHelperCommandLines, cmCustomCommandType::POST_BUILD,
-          "Depend check for xcode", legacyDependHelperDir.c_str(), true, false,
-          "", "", false, cmObjectLibraryCommands::Accept);
+          "Depend check for xcode", legacyDependHelperDir.c_str(),
+          cmPolicies::NEW, true, false, "", "", false,
+          cmObjectLibraryCommands::Accept);
       }
 
       if (!this->IsExcluded(gens[0], target.get())) {
@@ -775,7 +779,9 @@ void cmGlobalXCodeGenerator::ClearXCodeObjects()
   this->TargetGroup.clear();
   this->FileRefs.clear();
   this->ExternalLibRefs.clear();
+  this->EmbeddedLibRefs.clear();
   this->FileRefToBuildFileMap.clear();
+  this->FileRefToEmbedBuildFileMap.clear();
   this->CommandsVisited.clear();
 }
 
@@ -941,6 +947,11 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
     default:
       break;
   }
+
+  // Explicitly add the explicit language flag before any other flag
+  // so user flags can override it.
+  gtgt->AddExplicitLanguageFlags(flags, *sf);
+
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
   if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
     lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
@@ -1202,7 +1213,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
     }
   }
   // Make a copy so that we can override it later
-  std::string path = fullpath;
+  std::string path = cmSystemTools::CollapseFullPath(fullpath);
   // Compute the extension without leading '.'.
   std::string ext = cmSystemTools::GetFilenameLastExtension(path);
   if (!ext.empty()) {
@@ -1382,7 +1393,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
 
   // organize the sources
   std::vector<cmSourceFile*> commonSourceFiles;
-  if (!gtgt->GetConfigCommonSourceFiles(commonSourceFiles)) {
+  if (!gtgt->GetConfigCommonSourceFilesForXcode(commonSourceFiles)) {
     return false;
   }
 
@@ -1647,6 +1658,14 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt)
     }
   }
 
+  // Allow empty source file list for iOS Sticker packs
+  if (const char* productType = GetTargetProductType(gtgt)) {
+    if (strcmp(productType,
+               "com.apple.product-type.app-extension.messages-sticker-pack") ==
+        0)
+      return;
+  }
+
   // Add an empty source file to the target that compiles with the
   // linker language.  This should convince Xcode to choose the proper
   // language.
@@ -1738,7 +1757,7 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
                                                      gtgt, postbuild);
   } else {
     std::vector<cmSourceFile*> classes;
-    if (!gtgt->GetConfigCommonSourceFiles(classes)) {
+    if (!gtgt->GetConfigCommonSourceFilesForXcode(classes)) {
       return;
     }
     // add all the sources
@@ -1798,6 +1817,10 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
   if (frameworkBuildPhase) {
     buildPhases->AddObject(frameworkBuildPhase);
   }
+
+  // When this build phase is present, it must be last. More build phases may
+  // be added later for embedding things and they will insert themselves just
+  // before this last build phase.
   if (postBuildPhase) {
     buildPhases->AddObject(postBuildPhase);
   }
@@ -1807,7 +1830,7 @@ void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases(
   cmXCodeObject* buildPhases, cmGeneratorTarget const* gt)
 {
   std::vector<cmSourceFile*> sources;
-  if (!gt->GetConfigCommonSourceFiles(sources)) {
+  if (!gt->GetConfigCommonSourceFilesForXcode(sources)) {
     return;
   }
   auto& visited = this->CommandsVisited[gt];
@@ -2953,7 +2976,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
   if (gtgt->GetType() != cmStateEnums::GLOBAL_TARGET &&
       gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
     std::vector<cmSourceFile*> sources;
-    if (!gtgt->GetConfigCommonSourceFiles(sources)) {
+    if (!gtgt->GetConfigCommonSourceFilesForXcode(sources)) {
       return nullptr;
     }
 
@@ -3228,36 +3251,43 @@ void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
     if (!attr) {
       settings->AddAttribute(attribute, value);
     } else {
-      if (value->GetType() != cmXCodeObject::OBJECT_LIST &&
-          value->GetType() != cmXCodeObject::STRING) {
-        cmSystemTools::Error("Unsupported value type for appending: " +
-                             std::string(attribute));
-        return;
-      }
-      if (attr->GetType() == cmXCodeObject::OBJECT_LIST) {
-        if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
-          for (auto* obj : value->GetObjectList()) {
-            attr->AddObject(obj);
-          }
-        } else {
-          attr->AddObject(value);
-        }
-      } else if (attr->GetType() == cmXCodeObject::STRING) {
-        if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
-          // Add old value as a list item to new object list
-          // and replace the attribute with the new list
-          value->PrependObject(attr);
-          settings->AddAttribute(attribute, value);
-        } else {
-          std::string newValue =
-            cmStrCat(attr->GetString(), ' ', value->GetString());
-          attr->SetString(newValue);
-        }
-      } else {
-        cmSystemTools::Error("Unsupported attribute type for appending: " +
-                             std::string(attribute));
+      this->AppendBuildSettingAttribute(settings, attribute, attr, value);
+    }
+  }
+}
+
+void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
+  cmXCodeObject* settings, const char* attribute, cmXCodeObject* attr,
+  cmXCodeObject* value)
+{
+  if (value->GetType() != cmXCodeObject::OBJECT_LIST &&
+      value->GetType() != cmXCodeObject::STRING) {
+    cmSystemTools::Error("Unsupported value type for appending: " +
+                         std::string(attribute));
+    return;
+  }
+  if (attr->GetType() == cmXCodeObject::OBJECT_LIST) {
+    if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
+      for (auto* obj : value->GetObjectList()) {
+        attr->AddObject(obj);
       }
+    } else {
+      attr->AddObject(value);
+    }
+  } else if (attr->GetType() == cmXCodeObject::STRING) {
+    if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
+      // Add old value as a list item to new object list
+      // and replace the attribute with the new list
+      value->PrependObject(attr);
+      settings->AddAttribute(attribute, value);
+    } else {
+      std::string newValue =
+        cmStrCat(attr->GetString(), ' ', value->GetString());
+      attr->SetString(newValue);
     }
+  } else {
+    cmSystemTools::Error("Unsupported attribute type for appending: " +
+                         std::string(attribute));
   }
 }
 
@@ -3280,6 +3310,24 @@ void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
   }
 }
 
+void cmGlobalXCodeGenerator::InheritBuildSettingAttribute(
+  cmXCodeObject* target, const char* attribute)
+{
+  cmXCodeObject* configurationList =
+    target->GetAttribute("buildConfigurationList")->GetObject();
+  cmXCodeObject* buildConfigs =
+    configurationList->GetAttribute("buildConfigurations");
+  for (auto obj : buildConfigs->GetObjectList()) {
+    cmXCodeObject* settings = obj->GetAttribute("buildSettings");
+    if (cmXCodeObject* attr = settings->GetAttribute(attribute)) {
+      BuildObjectListOrString inherited(this, true);
+      inherited.Add("$(inherited)");
+      this->AppendBuildSettingAttribute(settings, attribute, attr,
+                                        inherited.CreateList());
+    }
+  }
+}
+
 void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
 {
   cmGeneratorTarget* gt = target->GetTarget();
@@ -3596,11 +3644,11 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
       for (auto& libDir : linkSearchPaths) {
         libSearchPaths.Add(this->XCodeEscapePath(libDir));
       }
-      // Add paths defined in project-wide build settings
-      libSearchPaths.Add("$(inherited)");
-      this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
-                                        libSearchPaths.CreateList(),
-                                        configName);
+      if (!libSearchPaths.IsEmpty()) {
+        this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
+                                          libSearchPaths.CreateList(),
+                                          configName);
+      }
     }
 
     // add framework search paths
@@ -3611,11 +3659,11 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
       for (auto& fwDir : frameworkSearchPaths) {
         fwSearchPaths.Add(this->XCodeEscapePath(fwDir));
       }
-      // Add paths defined in project-wide build settings
-      fwSearchPaths.Add("$(inherited)");
-      this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
-                                        fwSearchPaths.CreateList(),
-                                        configName);
+      if (!fwSearchPaths.IsEmpty()) {
+        this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
+                                          fwSearchPaths.CreateList(),
+                                          configName);
+      }
     }
 
     // now add the left-over link libraries
@@ -3679,6 +3727,130 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
   }
 }
 
+void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target)
+{
+  cmGeneratorTarget* gt = target->GetTarget();
+  if (!gt) {
+    cmSystemTools::Error("Error no target on xobject\n");
+    return;
+  }
+  if (!gt->IsInBuildSystem()) {
+    return;
+  }
+  bool isFrameworkTarget = gt->IsFrameworkOnApple();
+  bool isBundleTarget = gt->GetPropertyAsBool("MACOSX_BUNDLE");
+  bool isCFBundleTarget = gt->IsCFBundleOnApple();
+  if (!(isFrameworkTarget || isBundleTarget || isCFBundleTarget)) {
+    return;
+  }
+  cmProp files = gt->GetProperty("XCODE_EMBED_FRAMEWORKS");
+  if (!files) {
+    return;
+  }
+
+  // Create an "Embedded Frameworks" build phase
+  auto* copyFilesBuildPhase =
+    this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
+  std::string copyFilesBuildPhaseName = "Embed Frameworks";
+  std::string destinationFrameworks = "10";
+  copyFilesBuildPhase->SetComment(copyFilesBuildPhaseName);
+  copyFilesBuildPhase->AddAttribute("buildActionMask",
+                                    this->CreateString("2147483647"));
+  copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
+                                    this->CreateString(destinationFrameworks));
+  copyFilesBuildPhase->AddAttribute(
+    "name", this->CreateString(copyFilesBuildPhaseName));
+  if (cmProp fwEmbedPath = gt->GetProperty("XCODE_EMBED_FRAMEWORKS_PATH")) {
+    copyFilesBuildPhase->AddAttribute("dstPath",
+                                      this->CreateString(*fwEmbedPath));
+  } else {
+    copyFilesBuildPhase->AddAttribute("dstPath", this->CreateString(""));
+  }
+  copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+                                    this->CreateString("0"));
+  cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+  // Collect all embedded frameworks and add them to build phase
+  std::vector<std::string> relFiles = cmExpandedList(*files);
+  for (std::string const& relFile : relFiles) {
+    cmXCodeObject* buildFile{ nullptr };
+    std::string filePath = relFile;
+    auto* genTarget = FindGeneratorTarget(relFile);
+    if (genTarget) {
+      // This is a target - get it's product path reference
+      auto* xcTarget = FindXCodeTarget(genTarget);
+      if (!xcTarget) {
+        cmSystemTools::Error("Can not find a target for " +
+                             genTarget->GetName());
+        continue;
+      }
+      // Add the target output file as a build reference for other targets
+      // to link against
+      auto* fileRefObject = xcTarget->GetAttribute("productReference");
+      if (!fileRefObject) {
+        cmSystemTools::Error("Target " + genTarget->GetName() +
+                             " is missing product reference");
+        continue;
+      }
+      auto it = FileRefToEmbedBuildFileMap.find(fileRefObject);
+      if (it == FileRefToEmbedBuildFileMap.end()) {
+        buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+        buildFile->AddAttribute("fileRef", fileRefObject);
+        FileRefToEmbedBuildFileMap[fileRefObject] = buildFile;
+      } else {
+        buildFile = it->second;
+      }
+    } else if (cmSystemTools::IsPathToFramework(relFile)) {
+      // This is a regular string path - create file reference
+      auto it = EmbeddedLibRefs.find(relFile);
+      if (it == EmbeddedLibRefs.end()) {
+        cmXCodeObject* fileRef =
+          this->CreateXCodeFileReferenceFromPath(relFile, gt, "", nullptr);
+        if (fileRef) {
+          buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+          buildFile->SetComment(fileRef->GetComment());
+          buildFile->AddAttribute("fileRef",
+                                  this->CreateObjectReference(fileRef));
+        }
+        if (!buildFile) {
+          cmSystemTools::Error("Can't create build file for " + relFile);
+          continue;
+        }
+        this->EmbeddedLibRefs.emplace(filePath, buildFile);
+      } else {
+        buildFile = it->second;
+      }
+    }
+    if (!buildFile) {
+      cmSystemTools::Error("Can't find a build file for " + relFile);
+      continue;
+    }
+    // Set build file configuration
+    cmXCodeObject* settings =
+      this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+    cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+    const auto& rmHeadersProp =
+      gt->GetSafeProperty("XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY");
+    if (cmIsOn(rmHeadersProp)) {
+      attrs->AddObject(this->CreateString("RemoveHeadersOnCopy"));
+    }
+    const auto& codeSignProp =
+      gt->GetSafeProperty("XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY");
+    if (cmIsOn(codeSignProp)) {
+      attrs->AddObject(this->CreateString("CodeSignOnCopy"));
+    }
+    settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs);
+    buildFile->AddAttributeIfNotEmpty("settings", settings);
+    if (!buildFiles->HasObject(buildFile)) {
+      buildFiles->AddObject(buildFile);
+    }
+  }
+  copyFilesBuildPhase->AddAttribute("files", buildFiles);
+  auto* buildPhases = target->GetAttribute("buildPhases");
+  // Insert embed build phase right before the post-build command
+  buildPhases->InsertObject(buildPhases->GetObjectCount() - 1,
+                            copyFilesBuildPhase);
+}
+
 bool cmGlobalXCodeGenerator::CreateGroups(
   std::vector<cmLocalGenerator*>& generators)
 {
@@ -4057,7 +4229,16 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
   // loop over all targets and add link and depend info
   for (auto t : targets) {
     this->AddDependAndLinkInformation(t);
+    this->AddEmbeddedFrameworks(t);
+    // Inherit project-wide values for any target-specific search paths.
+    this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS");
+    this->InheritBuildSettingAttribute(t, "SYSTEM_HEADER_SEARCH_PATHS");
+    this->InheritBuildSettingAttribute(t, "FRAMEWORK_SEARCH_PATHS");
+    this->InheritBuildSettingAttribute(t, "SYSTEM_FRAMEWORK_SEARCH_PATHS");
+    this->InheritBuildSettingAttribute(t, "LIBRARY_SEARCH_PATHS");
+    this->InheritBuildSettingAttribute(t, "LD_RUNPATH_SEARCH_PATHS");
   }
+
   if (this->XcodeBuildSystem == BuildSystem::One) {
     this->CreateXCodeDependHackMakefile(targets);
   }
index 8ff6846..1ab56e2 100644 (file)
@@ -186,11 +186,17 @@ private:
                                 cmGeneratorTarget* gtgt);
   void AppendOrAddBuildSetting(cmXCodeObject* settings, const char* attr,
                                cmXCodeObject* value);
+  void AppendBuildSettingAttribute(cmXCodeObject* settings,
+                                   const char* attribute, cmXCodeObject* attr,
+                                   cmXCodeObject* value);
   void AppendBuildSettingAttribute(cmXCodeObject* target, const char* attr,
                                    cmXCodeObject* value,
                                    const std::string& configName);
+  void InheritBuildSettingAttribute(cmXCodeObject* target,
+                                    const char* attribute);
   cmXCodeObject* CreateUtilityTarget(cmGeneratorTarget* gtgt);
   void AddDependAndLinkInformation(cmXCodeObject* target);
+  void AddEmbeddedFrameworks(cmXCodeObject* target);
   void AddPositionIndependentLinkAttribute(cmGeneratorTarget* target,
                                            cmXCodeObject* buildSettings,
                                            const std::string& configName);
@@ -329,8 +335,10 @@ private:
   std::map<std::string, cmXCodeObject*> TargetGroup;
   std::map<std::string, cmXCodeObject*> FileRefs;
   std::map<std::string, cmXCodeObject*> ExternalLibRefs;
+  std::map<std::string, cmXCodeObject*> EmbeddedLibRefs;
   std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap;
   std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap;
+  std::map<cmXCodeObject*, cmXCodeObject*> FileRefToEmbedBuildFileMap;
   std::vector<std::string> Architectures;
   std::string ObjectDirArchDefault;
   std::string ObjectDirArch;
index cf4ba93..122bda5 100644 (file)
@@ -131,8 +131,8 @@ cmGraphVizWriter::~cmGraphVizWriter()
 
 void cmGraphVizWriter::VisitGraph(std::string const&)
 {
-  this->WriteHeader(GlobalFileStream, this->GraphName);
-  this->WriteLegend(GlobalFileStream);
+  this->WriteHeader(this->GlobalFileStream, this->GraphName);
+  this->WriteLegend(this->GlobalFileStream);
 }
 
 void cmGraphVizWriter::OnItem(cmLinkItem const& item)
@@ -141,8 +141,9 @@ void cmGraphVizWriter::OnItem(cmLinkItem const& item)
     return;
   }
 
-  NodeNames[item.AsStr()] = cmStrCat(GraphNodePrefix, NextNodeId);
-  ++NextNodeId;
+  this->NodeNames[item.AsStr()] =
+    cmStrCat(this->GraphNodePrefix, this->NextNodeId);
+  ++this->NextNodeId;
 
   this->WriteNode(this->GlobalFileStream, item);
 }
@@ -191,12 +192,13 @@ void cmGraphVizWriter::VisitLink(cmLinkItem const& depender,
   this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType);
 
   if (this->GeneratePerTarget) {
-    PerTargetConnections[depender].emplace_back(depender, dependee, scopeType);
+    this->PerTargetConnections[depender].emplace_back(depender, dependee,
+                                                      scopeType);
   }
 
   if (this->GenerateDependers) {
-    TargetDependersConnections[dependee].emplace_back(dependee, depender,
-                                                      scopeType);
+    this->TargetDependersConnections[dependee].emplace_back(dependee, depender,
+                                                            scopeType);
   }
 }
 
@@ -228,7 +230,7 @@ void cmGraphVizWriter::ReadSettings(
 
   std::cout << "Reading GraphViz options file: " << inFileName << std::endl;
 
-#define __set_if_set(var, cmakeDefinition)                                    \
+#define set_if_set(var, cmakeDefinition)                                      \
   do {                                                                        \
     cmProp value = mf.GetDefinition(cmakeDefinition);                         \
     if (value) {                                                              \
@@ -236,11 +238,11 @@ void cmGraphVizWriter::ReadSettings(
     }                                                                         \
   } while (false)
 
-  __set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME");
-  __set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER");
-  __set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX");
+  set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME");
+  set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER");
+  set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX");
 
-#define __set_bool_if_set(var, cmakeDefinition)                               \
+#define set_bool_if_set(var, cmakeDefinition)                                 \
   do {                                                                        \
     cmProp value = mf.GetDefinition(cmakeDefinition);                         \
     if (value) {                                                              \
@@ -248,20 +250,20 @@ void cmGraphVizWriter::ReadSettings(
     }                                                                         \
   } while (false)
 
-  __set_bool_if_set(this->GenerateForExecutables, "GRAPHVIZ_EXECUTABLES");
-  __set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS");
-  __set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS");
-  __set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS");
-  __set_bool_if_set(this->GenerateForInterfaceLibs, "GRAPHVIZ_INTERFACE_LIBS");
-  __set_bool_if_set(this->GenerateForObjectLibs, "GRAPHVIZ_OBJECT_LIBS");
-  __set_bool_if_set(this->GenerateForUnknownLibs, "GRAPHVIZ_UNKNOWN_LIBS");
-  __set_bool_if_set(this->GenerateForCustomTargets, "GRAPHVIZ_CUSTOM_TARGETS");
-  __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
-  __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
-  __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
+  set_bool_if_set(this->GenerateForExecutables, "GRAPHVIZ_EXECUTABLES");
+  set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS");
+  set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS");
+  set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS");
+  set_bool_if_set(this->GenerateForInterfaceLibs, "GRAPHVIZ_INTERFACE_LIBS");
+  set_bool_if_set(this->GenerateForObjectLibs, "GRAPHVIZ_OBJECT_LIBS");
+  set_bool_if_set(this->GenerateForUnknownLibs, "GRAPHVIZ_UNKNOWN_LIBS");
+  set_bool_if_set(this->GenerateForCustomTargets, "GRAPHVIZ_CUSTOM_TARGETS");
+  set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
+  set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
+  set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
 
   std::string ignoreTargetsRegexes;
-  __set_if_set(ignoreTargetsRegexes, "GRAPHVIZ_IGNORE_TARGETS");
+  set_if_set(ignoreTargetsRegexes, "GRAPHVIZ_IGNORE_TARGETS");
 
   this->TargetsToIgnoreRegex.clear();
   if (!ignoreTargetsRegexes.empty()) {
@@ -280,7 +282,7 @@ void cmGraphVizWriter::ReadSettings(
 
 void cmGraphVizWriter::Write()
 {
-  auto gg = this->GlobalGenerator;
+  const auto* gg = this->GlobalGenerator;
 
   this->VisitGraph(gg->GetName());
 
@@ -301,18 +303,18 @@ void cmGraphVizWriter::Write()
   }
 
   // write global data and collect all connection data for per target graphs
-  for (auto const gt : sortedGeneratorTargets) {
+  for (const auto* const gt : sortedGeneratorTargets) {
     auto item = cmLinkItem(gt, false, gt->GetBacktrace());
     this->VisitItem(item);
   }
 
   if (this->GeneratePerTarget) {
-    WritePerTargetConnections<DependeesDir>(PerTargetConnections);
+    this->WritePerTargetConnections<DependeesDir>(this->PerTargetConnections);
   }
 
   if (this->GenerateDependers) {
-    WritePerTargetConnections<DependersDir>(TargetDependersConnections,
-                                            ".dependers");
+    this->WritePerTargetConnections<DependersDir>(
+      this->TargetDependersConnections, ".dependers");
   }
 }
 
@@ -336,7 +338,8 @@ void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap,
     bool const visited = visitedItems.find(dstItem) != visitedItems.cend();
     if (!visited) {
       visitedItems.insert(dstItem);
-      FindAllConnections(connectionMap, dstItem, extendedCons, visitedItems);
+      this->FindAllConnections(connectionMap, dstItem, extendedCons,
+                               visitedItems);
     }
   }
 }
@@ -346,7 +349,8 @@ void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap,
                                           Connections& extendedCons)
 {
   std::set<cmLinkItem> visitedItems = { rootItem };
-  FindAllConnections(connectionMap, rootItem, extendedCons, visitedItems);
+  this->FindAllConnections(connectionMap, rootItem, extendedCons,
+                           visitedItems);
 }
 
 template <typename DirFunc>
@@ -358,7 +362,7 @@ void cmGraphVizWriter::WritePerTargetConnections(
   for (auto const& conPerTarget : connections) {
     const cmLinkItem& rootItem = conPerTarget.first;
     Connections& extendedCons = extendedConnections[conPerTarget.first];
-    FindAllConnections(connections, rootItem, extendedCons);
+    this->FindAllConnections(connections, rootItem, extendedCons);
   }
 
   for (auto const& conPerTarget : extendedConnections) {
@@ -451,7 +455,7 @@ void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs,
   auto const& itemName = item.AsStr();
   auto const& nodeName = this->NodeNames[itemName];
 
-  auto const itemNameWithAliases = ItemNameWithAliases(itemName);
+  auto const itemNameWithAliases = this->ItemNameWithAliases(itemName);
   auto const escapedLabel = EscapeForDotFile(itemNameWithAliases);
 
   fs << "    \"" << nodeName << "\" [ label = \"" << escapedLabel
index ae801bb..ce1f030 100644 (file)
@@ -21,6 +21,7 @@ bool cmIncludeCommand(std::vector<std::string> const& args,
   static std::map<std::string, cmPolicies::PolicyID> DeprecatedModules;
   if (DeprecatedModules.empty()) {
     DeprecatedModules["Documentation"] = cmPolicies::CMP0106;
+    DeprecatedModules["WriteCompilerDetectionHeader"] = cmPolicies::CMP0120;
   }
 
   if (args.empty() || args.size() > 4) {
@@ -146,11 +147,24 @@ bool cmIncludeCommand(std::vector<std::string> const& args,
 
   std::string listFile = cmSystemTools::CollapseFullPath(
     fname, status.GetMakefile().GetCurrentSourceDirectory());
-  if (optional && !cmSystemTools::FileExists(listFile)) {
+
+  const bool fileDoesnotExist = !cmSystemTools::FileExists(listFile);
+  const bool fileIsDirectory = cmSystemTools::FileIsDirectory(listFile);
+  if (fileDoesnotExist || fileIsDirectory) {
     if (!resultVarName.empty()) {
       status.GetMakefile().AddDefinition(resultVarName, "NOTFOUND");
     }
-    return true;
+    if (optional) {
+      return true;
+    }
+    if (fileDoesnotExist) {
+      status.SetError(cmStrCat("could not find requested file:\n  ", fname));
+      return false;
+    }
+    if (fileIsDirectory) {
+      status.SetError(cmStrCat("requested file is a directory:\n  ", fname));
+      return false;
+    }
   }
 
   bool readit =
@@ -163,9 +177,7 @@ bool cmIncludeCommand(std::vector<std::string> const& args,
   }
 
   if (!optional && !readit && !cmSystemTools::GetFatalErrorOccured()) {
-    std::string m = cmStrCat("could not find load file:\n"
-                             "  ",
-                             fname);
+    std::string m = cmStrCat("could not load requested file:\n  ", fname);
     status.SetError(m);
     return false;
   }
index ff08ee4..7788db3 100644 (file)
@@ -57,28 +57,38 @@ public:
   bool MakeFilesFullPath(const char* modeName,
                          const std::vector<std::string>& relFiles,
                          std::vector<std::string>& absFiles);
-  bool CheckCMP0006(bool& failure);
+  bool CheckCMP0006(bool& failure) const;
 
   std::string GetDestination(const cmInstallCommandArguments* args,
                              const std::string& varName,
-                             const std::string& guess);
-  std::string GetRuntimeDestination(const cmInstallCommandArguments* args);
-  std::string GetSbinDestination(const cmInstallCommandArguments* args);
-  std::string GetArchiveDestination(const cmInstallCommandArguments* args);
-  std::string GetLibraryDestination(const cmInstallCommandArguments* args);
-  std::string GetIncludeDestination(const cmInstallCommandArguments* args);
-  std::string GetSysconfDestination(const cmInstallCommandArguments* args);
-  std::string GetSharedStateDestination(const cmInstallCommandArguments* args);
-  std::string GetLocalStateDestination(const cmInstallCommandArguments* args);
-  std::string GetRunStateDestination(const cmInstallCommandArguments* args);
-  std::string GetDataRootDestination(const cmInstallCommandArguments* args);
-  std::string GetDataDestination(const cmInstallCommandArguments* args);
-  std::string GetInfoDestination(const cmInstallCommandArguments* args);
-  std::string GetLocaleDestination(const cmInstallCommandArguments* args);
-  std::string GetManDestination(const cmInstallCommandArguments* args);
-  std::string GetDocDestination(const cmInstallCommandArguments* args);
+                             const std::string& guess) const;
+  std::string GetRuntimeDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetSbinDestination(const cmInstallCommandArguments* args) const;
+  std::string GetArchiveDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetLibraryDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetIncludeDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetSysconfDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetSharedStateDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetLocalStateDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetRunStateDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetDataRootDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetDataDestination(const cmInstallCommandArguments* args) const;
+  std::string GetInfoDestination(const cmInstallCommandArguments* args) const;
+  std::string GetLocaleDestination(
+    const cmInstallCommandArguments* args) const;
+  std::string GetManDestination(const cmInstallCommandArguments* args) const;
+  std::string GetDocDestination(const cmInstallCommandArguments* args) const;
   std::string GetDestinationForType(const cmInstallCommandArguments* args,
-                                    const std::string& type);
+                                    const std::string& type) const;
 
   cmExecutionStatus& Status;
   cmMakefile* Makefile;
@@ -123,7 +133,8 @@ std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
   return cm::make_unique<cmInstallFilesGenerator>(
     absFiles, destination, programs, args.GetPermissions(),
     args.GetConfigurations(), args.GetComponent(), message,
-    args.GetExcludeFromAll(), args.GetRename(), args.GetOptional());
+    args.GetExcludeFromAll(), args.GetRename(), args.GetOptional(),
+    mf->GetBacktrace());
 }
 
 std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
@@ -196,14 +207,16 @@ bool HandleScriptMode(std::vector<std::string> const& args,
         return false;
       }
       helper.Makefile->AddInstallGenerator(
-        cm::make_unique<cmInstallScriptGenerator>(script, false, component,
-                                                  exclude_from_all));
+        cm::make_unique<cmInstallScriptGenerator>(
+          script, false, component, exclude_from_all,
+          helper.Makefile->GetBacktrace()));
     } else if (doing_code) {
       doing_code = false;
       std::string const& code = arg;
       helper.Makefile->AddInstallGenerator(
-        cm::make_unique<cmInstallScriptGenerator>(code, true, component,
-                                                  exclude_from_all));
+        cm::make_unique<cmInstallScriptGenerator>(
+          code, true, component, exclude_from_all,
+          helper.Makefile->GetBacktrace()));
     }
   }
 
@@ -1243,7 +1256,8 @@ bool HandleDirectoryMode(std::vector<std::string> const& args,
   helper.Makefile->AddInstallGenerator(
     cm::make_unique<cmInstallDirectoryGenerator>(
       dirs, *destination, permissions_file, permissions_dir, configurations,
-      component, message, exclude_from_all, literal_args, optional));
+      component, message, exclude_from_all, literal_args, optional,
+      helper.Makefile->GetBacktrace()));
 
   // Tell the global generator about any installation component names
   // specified.
@@ -1335,7 +1349,8 @@ bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
     cm::make_unique<cmInstallExportGenerator>(
       &exportSet, ica.GetDestination(), ica.GetPermissions(),
       ica.GetConfigurations(), ica.GetComponent(), message,
-      ica.GetExcludeFromAll(), fname, name_space, exportOld, true));
+      ica.GetExcludeFromAll(), fname, name_space, exportOld, true,
+      helper.Makefile->GetBacktrace()));
 
   return true;
 #else
@@ -1448,7 +1463,8 @@ bool HandleExportMode(std::vector<std::string> const& args,
     cm::make_unique<cmInstallExportGenerator>(
       &exportSet, ica.GetDestination(), ica.GetPermissions(),
       ica.GetConfigurations(), ica.GetComponent(), message,
-      ica.GetExcludeFromAll(), fname, name_space, exportOld, false));
+      ica.GetExcludeFromAll(), fname, name_space, exportOld, false,
+      helper.Makefile->GetBacktrace()));
 
   return true;
 }
@@ -1477,7 +1493,7 @@ bool Helper::MakeFilesFullPath(const char* modeName,
   return true;
 }
 
-bool Helper::CheckCMP0006(bool& failure)
+bool Helper::CheckCMP0006(bool& failure) const
 {
   switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0006)) {
     case cmPolicies::WARN:
@@ -1504,7 +1520,7 @@ bool Helper::CheckCMP0006(bool& failure)
 
 std::string Helper::GetDestination(const cmInstallCommandArguments* args,
                                    const std::string& varName,
-                                   const std::string& guess)
+                                   const std::string& guess) const
 {
   if (args && !args->GetDestination().empty()) {
     return args->GetDestination();
@@ -1517,54 +1533,55 @@ std::string Helper::GetDestination(const cmInstallCommandArguments* args,
 }
 
 std::string Helper::GetRuntimeDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_BINDIR", "bin");
 }
 
-std::string Helper::GetSbinDestination(const cmInstallCommandArguments* args)
+std::string Helper::GetSbinDestination(
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_SBINDIR", "sbin");
 }
 
 std::string Helper::GetArchiveDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
 }
 
 std::string Helper::GetLibraryDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib");
 }
 
 std::string Helper::GetIncludeDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_INCLUDEDIR", "include");
 }
 
 std::string Helper::GetSysconfDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_SYSCONFDIR", "etc");
 }
 
 std::string Helper::GetSharedStateDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_SHAREDSTATEDIR", "com");
 }
 
 std::string Helper::GetLocalStateDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_LOCALSTATEDIR", "var");
 }
 
 std::string Helper::GetRunStateDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_RUNSTATEDIR",
                               this->GetLocalStateDestination(nullptr) +
@@ -1572,44 +1589,49 @@ std::string Helper::GetRunStateDestination(
 }
 
 std::string Helper::GetDataRootDestination(
-  const cmInstallCommandArguments* args)
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_DATAROOTDIR", "share");
 }
 
-std::string Helper::GetDataDestination(const cmInstallCommandArguments* args)
+std::string Helper::GetDataDestination(
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_DATADIR",
                               this->GetDataRootDestination(nullptr));
 }
 
-std::string Helper::GetInfoDestination(const cmInstallCommandArguments* args)
+std::string Helper::GetInfoDestination(
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_INFODIR",
                               this->GetDataRootDestination(nullptr) + "/info");
 }
 
-std::string Helper::GetLocaleDestination(const cmInstallCommandArguments* args)
+std::string Helper::GetLocaleDestination(
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_LOCALEDIR",
                               this->GetDataRootDestination(nullptr) +
                                 "/locale");
 }
 
-std::string Helper::GetManDestination(const cmInstallCommandArguments* args)
+std::string Helper::GetManDestination(
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_MANDIR",
                               this->GetDataRootDestination(nullptr) + "/man");
 }
 
-std::string Helper::GetDocDestination(const cmInstallCommandArguments* args)
+std::string Helper::GetDocDestination(
+  const cmInstallCommandArguments* args) const
 {
   return this->GetDestination(args, "CMAKE_INSTALL_DOCDIR",
                               this->GetDataRootDestination(nullptr) + "/doc");
 }
 
 std::string Helper::GetDestinationForType(
-  const cmInstallCommandArguments* args, const std::string& type)
+  const cmInstallCommandArguments* args, const std::string& type) const
 {
   if (args && !args->GetDestination().empty()) {
     return args->GetDestination();
index a034689..cc3df2a 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallCommandArguments.h"
 
+#include <algorithm>
 #include <utility>
 
 #include <cmext/string_view>
@@ -176,13 +177,11 @@ bool cmInstallCommandArguments::Finalize()
 bool cmInstallCommandArguments::CheckPermissions()
 {
   this->PermissionsString.clear();
-  for (std::string const& perm : this->Permissions) {
-    if (!cmInstallCommandArguments::CheckPermissions(
-          perm, this->PermissionsString)) {
-      return false;
-    }
-  }
-  return true;
+  return std::all_of(this->Permissions.begin(), this->Permissions.end(),
+                     [this](std::string const& perm) -> bool {
+                       return cmInstallCommandArguments::CheckPermissions(
+                         perm, this->PermissionsString);
+                     });
 }
 
 bool cmInstallCommandArguments::CheckPermissions(
index 175e7cf..4eb5f69 100644 (file)
@@ -16,9 +16,9 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
   std::string file_permissions, std::string dir_permissions,
   std::vector<std::string> const& configurations, std::string const& component,
   MessageLevel message, bool exclude_from_all, std::string literal_args,
-  bool optional)
+  bool optional, cmListFileBacktrace backtrace)
   : cmInstallGenerator(dest, configurations, component, message,
-                       exclude_from_all)
+                       exclude_from_all, std::move(backtrace))
   , LocalGenerator(nullptr)
   , Directories(dirs)
   , FilePermissions(std::move(file_permissions))
@@ -27,7 +27,7 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
   , Optional(optional)
 {
   // We need per-config actions if destination have generator expressions.
-  if (cmGeneratorExpression::Find(Destination) != std::string::npos) {
+  if (cmGeneratorExpression::Find(this->Destination) != std::string::npos) {
     this->ActionsPerConfig = true;
   }
 
@@ -50,6 +50,22 @@ bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
   return true;
 }
 
+std::vector<std::string> cmInstallDirectoryGenerator::GetDirectories(
+  std::string const& config) const
+{
+  std::vector<std::string> directories;
+  if (this->ActionsPerConfig) {
+    for (std::string const& f : this->Directories) {
+      cmExpandList(
+        cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config),
+        directories);
+    }
+  } else {
+    directories = this->Directories;
+  }
+  return directories;
+}
+
 void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
                                                         Indent indent)
 {
@@ -63,11 +79,7 @@ void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
 void cmInstallDirectoryGenerator::GenerateScriptForConfig(
   std::ostream& os, const std::string& config, Indent indent)
 {
-  std::vector<std::string> dirs;
-  for (std::string const& d : this->Directories) {
-    cmExpandList(
-      cmGeneratorExpression::Evaluate(d, this->LocalGenerator, config), dirs);
-  }
+  std::vector<std::string> dirs = this->GetDirectories(config);
 
   // Make sure all dirs have absolute paths.
   cmMakefile const& mf = *this->LocalGenerator->GetMakefile();
index af310f3..0f91a59 100644 (file)
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
 #include "cmScriptGenerator.h"
 
 class cmLocalGenerator;
@@ -19,19 +20,20 @@ class cmLocalGenerator;
 class cmInstallDirectoryGenerator : public cmInstallGenerator
 {
 public:
-  cmInstallDirectoryGenerator(std::vector<std::string> const& dirs,
-                              std::string const& dest,
-                              std::string file_permissions,
-                              std::string dir_permissions,
-                              std::vector<std::string> const& configurations,
-                              std::string const& component,
-                              MessageLevel message, bool exclude_from_all,
-                              std::string literal_args, bool optional = false);
+  cmInstallDirectoryGenerator(
+    std::vector<std::string> const& dirs, std::string const& dest,
+    std::string file_permissions, std::string dir_permissions,
+    std::vector<std::string> const& configurations,
+    std::string const& component, MessageLevel message, bool exclude_from_all,
+    std::string literal_args, bool optional, cmListFileBacktrace backtrace);
   ~cmInstallDirectoryGenerator() override;
 
   bool Compute(cmLocalGenerator* lg) override;
 
   std::string GetDestination(std::string const& config) const;
+  std::vector<std::string> GetDirectories(std::string const& config) const;
+
+  bool GetOptional() const { return this->Optional; }
 
 protected:
   void GenerateScriptActions(std::ostream& os, Indent indent) override;
index 6e3508c..fdc3f8c 100644 (file)
@@ -23,9 +23,10 @@ cmInstallExportGenerator::cmInstallExportGenerator(
   cmExportSet* exportSet, std::string const& destination,
   std::string file_permissions, std::vector<std::string> const& configurations,
   std::string const& component, MessageLevel message, bool exclude_from_all,
-  std::string filename, std::string name_space, bool exportOld, bool android)
+  std::string filename, std::string name_space, bool exportOld, bool android,
+  cmListFileBacktrace backtrace)
   : cmInstallGenerator(destination, configurations, component, message,
-                       exclude_from_all)
+                       exclude_from_all, std::move(backtrace))
   , ExportSet(exportSet)
   , FilePermissions(std::move(file_permissions))
   , FileName(std::move(filename))
@@ -122,10 +123,10 @@ size_t cmInstallExportGenerator::GetMaxConfigLength() const
 void cmInstallExportGenerator::GenerateScript(std::ostream& os)
 {
   // Skip empty sets.
-  if (ExportSet->GetTargetExports().empty()) {
+  if (this->ExportSet->GetTargetExports().empty()) {
     std::ostringstream e;
-    e << "INSTALL(EXPORT) given unknown export \"" << ExportSet->GetName()
-      << "\"";
+    e << "INSTALL(EXPORT) given unknown export \""
+      << this->ExportSet->GetName() << "\"";
     cmSystemTools::Error(e.str());
     return;
   }
index dd8624b..efeae86 100644 (file)
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
 #include "cmScriptGenerator.h"
 
 class cmExportInstallFileGenerator;
@@ -29,7 +30,7 @@ public:
                            std::string const& component, MessageLevel message,
                            bool exclude_from_all, std::string filename,
                            std::string name_space, bool exportOld,
-                           bool android);
+                           bool android, cmListFileBacktrace backtrace);
   cmInstallExportGenerator(const cmInstallExportGenerator&) = delete;
   ~cmInstallExportGenerator() override;
 
@@ -44,8 +45,11 @@ public:
 
   const std::string& GetNamespace() const { return this->Namespace; }
 
+  std::string const& GetMainImportFile() const { return this->MainImportFile; }
+
   std::string const& GetDestination() const { return this->Destination; }
   std::string GetDestinationFile() const;
+  std::string GetFileName() const { return this->FileName; }
 
 protected:
   void GenerateScript(std::ostream& os) override;
index 3c59f01..e65cb24 100644 (file)
@@ -125,7 +125,7 @@ static void CreateInstallGenerator(cmMakefile& makefile,
     cmInstallGenerator::SelectMessageLevel(&makefile);
   makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
     files, destination, false, no_permissions, no_configurations, no_component,
-    message, no_exclude_from_all, no_rename));
+    message, no_exclude_from_all, no_rename, false, makefile.GetBacktrace()));
 }
 
 /**
index ad2f84e..556c938 100644 (file)
@@ -15,9 +15,9 @@ cmInstallFilesGenerator::cmInstallFilesGenerator(
   bool programs, std::string file_permissions,
   std::vector<std::string> const& configurations, std::string const& component,
   MessageLevel message, bool exclude_from_all, std::string rename,
-  bool optional)
+  bool optional, cmListFileBacktrace backtrace)
   : cmInstallGenerator(dest, configurations, component, message,
-                       exclude_from_all)
+                       exclude_from_all, std::move(backtrace))
   , LocalGenerator(nullptr)
   , Files(files)
   , FilePermissions(std::move(file_permissions))
@@ -25,8 +25,12 @@ cmInstallFilesGenerator::cmInstallFilesGenerator(
   , Programs(programs)
   , Optional(optional)
 {
-  // We need per-config actions if the destination has generator expressions.
-  if (cmGeneratorExpression::Find(Destination) != std::string::npos) {
+  // We need per-config actions if the destination and rename have generator
+  // expressions.
+  if (cmGeneratorExpression::Find(this->Destination) != std::string::npos) {
+    this->ActionsPerConfig = true;
+  }
+  if (cmGeneratorExpression::Find(this->Rename) != std::string::npos) {
     this->ActionsPerConfig = true;
   }
 
@@ -56,6 +60,28 @@ std::string cmInstallFilesGenerator::GetDestination(
                                          this->LocalGenerator, config);
 }
 
+std::string cmInstallFilesGenerator::GetRename(std::string const& config) const
+{
+  return cmGeneratorExpression::Evaluate(this->Rename, this->LocalGenerator,
+                                         config);
+}
+
+std::vector<std::string> cmInstallFilesGenerator::GetFiles(
+  std::string const& config) const
+{
+  std::vector<std::string> files;
+  if (this->ActionsPerConfig) {
+    for (std::string const& f : this->Files) {
+      cmExpandList(
+        cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config),
+        files);
+    }
+  } else {
+    files = this->Files;
+  }
+  return files;
+}
+
 void cmInstallFilesGenerator::AddFilesInstallRule(
   std::ostream& os, std::string const& config, Indent indent,
   std::vector<std::string> const& files)
@@ -66,7 +92,7 @@ void cmInstallFilesGenerator::AddFilesInstallRule(
     os, this->GetDestination(config),
     (this->Programs ? cmInstallType_PROGRAMS : cmInstallType_FILES), files,
     this->Optional, this->FilePermissions.c_str(), no_dir_permissions,
-    this->Rename.c_str(), nullptr, indent);
+    this->GetRename(config).c_str(), nullptr, indent);
 }
 
 void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
@@ -82,10 +108,6 @@ void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
 void cmInstallFilesGenerator::GenerateScriptForConfig(
   std::ostream& os, const std::string& config, Indent indent)
 {
-  std::vector<std::string> files;
-  for (std::string const& f : this->Files) {
-    cmExpandList(
-      cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config), files);
-  }
+  std::vector<std::string> files = this->GetFiles(config);
   this->AddFilesInstallRule(os, config, indent, files);
 }
index b5a1ef4..af7f113 100644 (file)
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
 #include "cmScriptGenerator.h"
 
 class cmLocalGenerator;
@@ -25,12 +26,15 @@ public:
                           std::vector<std::string> const& configurations,
                           std::string const& component, MessageLevel message,
                           bool exclude_from_all, std::string rename,
-                          bool optional = false);
+                          bool optional, cmListFileBacktrace backtrace);
   ~cmInstallFilesGenerator() override;
 
   bool Compute(cmLocalGenerator* lg) override;
 
   std::string GetDestination(std::string const& config) const;
+  std::string GetRename(std::string const& config) const;
+  std::vector<std::string> GetFiles(std::string const& config) const;
+  bool GetOptional() const { return this->Optional; }
 
 protected:
   void GenerateScriptActions(std::ostream& os, Indent indent) override;
index 0665895..98e3766 100644 (file)
 
 cmInstallGenerator::cmInstallGenerator(
   std::string destination, std::vector<std::string> const& configurations,
-  std::string component, MessageLevel message, bool exclude_from_all)
+  std::string component, MessageLevel message, bool exclude_from_all,
+  cmListFileBacktrace backtrace)
   : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations)
   , Destination(std::move(destination))
   , Component(std::move(component))
   , Message(message)
   , ExcludeFromAll(exclude_from_all)
+  , Backtrace(std::move(backtrace))
 {
 }
 
index ee55ee9..6cd9ff9 100644 (file)
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "cmInstallType.h"
+#include "cmListFileCache.h"
 #include "cmScriptGenerator.h"
 
 class cmLocalGenerator;
@@ -32,7 +33,7 @@ public:
   cmInstallGenerator(std::string destination,
                      std::vector<std::string> const& configurations,
                      std::string component, MessageLevel message,
-                     bool exclude_from_all);
+                     bool exclude_from_all, cmListFileBacktrace backtrace);
   ~cmInstallGenerator() override;
 
   cmInstallGenerator(cmInstallGenerator const&) = delete;
@@ -61,6 +62,12 @@ public:
 
   virtual bool Compute(cmLocalGenerator*) { return true; }
 
+  std::string const& GetComponent() const { return this->Component; }
+
+  bool GetExcludeFromAll() const { return this->ExcludeFromAll; }
+
+  cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
+
 protected:
   void GenerateScript(std::ostream& os) override;
 
@@ -72,4 +79,5 @@ protected:
   std::string const Component;
   MessageLevel const Message;
   bool const ExcludeFromAll;
+  cmListFileBacktrace const Backtrace;
 };
index be07fd4..65b8d89 100644 (file)
@@ -99,7 +99,7 @@ static void FinalAction(cmMakefile& makefile, std::string const& dest,
     cmInstallGenerator::SelectMessageLevel(&makefile);
   makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
     files, destination, true, no_permissions, no_configurations, no_component,
-    message, no_exclude_from_all, no_rename));
+    message, no_exclude_from_all, no_rename, false, makefile.GetBacktrace()));
 }
 
 /**
index 7cdf3b4..bb38990 100644 (file)
 
 cmInstallScriptGenerator::cmInstallScriptGenerator(
   std::string script, bool code, std::string const& component,
-  bool exclude_from_all)
+  bool exclude_from_all, cmListFileBacktrace backtrace)
   : cmInstallGenerator("", std::vector<std::string>(), component,
-                       MessageDefault, exclude_from_all)
+                       MessageDefault, exclude_from_all, std::move(backtrace))
   , Script(std::move(script))
   , Code(code)
   , AllowGenex(false)
 {
   // We need per-config actions if the script has generator expressions.
-  if (cmGeneratorExpression::Find(Script) != std::string::npos) {
+  if (cmGeneratorExpression::Find(this->Script) != std::string::npos) {
     this->ActionsPerConfig = true;
   }
 }
@@ -53,9 +53,21 @@ bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
   return true;
 }
 
-void cmInstallScriptGenerator::AddScriptInstallRule(std::ostream& os,
-                                                    Indent indent,
-                                                    std::string const& script)
+std::string cmInstallScriptGenerator::GetScript(
+  std::string const& config) const
+{
+  std::string script;
+  if (this->AllowGenex && this->ActionsPerConfig) {
+    script = cmGeneratorExpression::Evaluate(this->Script,
+                                             this->LocalGenerator, config);
+  } else {
+    script = this->Script;
+  }
+  return script;
+}
+
+void cmInstallScriptGenerator::AddScriptInstallRule(
+  std::ostream& os, Indent indent, std::string const& script) const
 {
   if (this->Code) {
     os << indent << script << "\n";
@@ -77,11 +89,5 @@ void cmInstallScriptGenerator::GenerateScriptActions(std::ostream& os,
 void cmInstallScriptGenerator::GenerateScriptForConfig(
   std::ostream& os, const std::string& config, Indent indent)
 {
-  if (this->AllowGenex) {
-    this->AddScriptInstallRule(os, indent,
-                               cmGeneratorExpression::Evaluate(
-                                 this->Script, this->LocalGenerator, config));
-  } else {
-    this->AddScriptInstallRule(os, indent, this->Script);
-  }
+  this->AddScriptInstallRule(os, indent, this->GetScript(config));
 }
index 338d866..6274f1c 100644 (file)
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
 #include "cmScriptGenerator.h"
 
 class cmLocalGenerator;
@@ -18,19 +19,24 @@ class cmLocalGenerator;
 class cmInstallScriptGenerator : public cmInstallGenerator
 {
 public:
-  cmInstallScriptGenerator(std::string script, bool code,
-                           std::string const& component,
-                           bool exclude_from_all);
+  cmInstallScriptGenerator(
+    std::string script, bool code, std::string const& component,
+    bool exclude_from_all,
+    cmListFileBacktrace backtrace = cmListFileBacktrace());
   ~cmInstallScriptGenerator() override;
 
   bool Compute(cmLocalGenerator* lg) override;
 
+  bool IsCode() const { return this->Code; }
+
+  std::string GetScript(std::string const& config) const;
+
 protected:
   void GenerateScriptActions(std::ostream& os, Indent indent) override;
   void GenerateScriptForConfig(std::ostream& os, const std::string& config,
                                Indent indent) override;
   void AddScriptInstallRule(std::ostream& os, Indent indent,
-                            std::string const& script);
+                            std::string const& script) const;
 
   std::string const Script;
   bool const Code;
index 12bc92b..76806e5 100644 (file)
 #include "cmSystemTools.h"
 
 cmInstallSubdirectoryGenerator::cmInstallSubdirectoryGenerator(
-  cmMakefile* makefile, std::string binaryDirectory, bool excludeFromAll)
+  cmMakefile* makefile, std::string binaryDirectory, bool excludeFromAll,
+  cmListFileBacktrace backtrace)
   : cmInstallGenerator("", std::vector<std::string>(), "", MessageDefault,
-                       excludeFromAll)
+                       excludeFromAll, std::move(backtrace))
   , Makefile(makefile)
   , BinaryDirectory(std::move(binaryDirectory))
 {
index 3e46d6b..614cef9 100644 (file)
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
 
 class cmLocalGenerator;
 class cmMakefile;
@@ -20,7 +21,8 @@ class cmInstallSubdirectoryGenerator : public cmInstallGenerator
 public:
   cmInstallSubdirectoryGenerator(cmMakefile* makefile,
                                  std::string binaryDirectory,
-                                 bool excludeFromAll);
+                                 bool excludeFromAll,
+                                 cmListFileBacktrace backtrace);
   ~cmInstallSubdirectoryGenerator() override;
 
   bool HaveInstall() override;
index b3da202..bef785d 100644 (file)
 #include "cmTarget.h"
 #include "cmake.h"
 
+namespace {
+std::string computeInstallObjectDir(cmGeneratorTarget* gt,
+                                    std::string const& config)
+{
+  std::string objectDir = "objects";
+  if (!config.empty()) {
+    objectDir += "-";
+    objectDir += config;
+  }
+  objectDir += "/";
+  objectDir += gt->GetName();
+  return objectDir;
+}
+}
+
 cmInstallTargetGenerator::cmInstallTargetGenerator(
   std::string targetName, std::string const& dest, bool implib,
   std::string file_permissions, std::vector<std::string> const& configurations,
   std::string const& component, MessageLevel message, bool exclude_from_all,
   bool optional, cmListFileBacktrace backtrace)
   : cmInstallGenerator(dest, configurations, component, message,
-                       exclude_from_all)
+                       exclude_from_all, std::move(backtrace))
   , TargetName(std::move(targetName))
   , Target(nullptr)
   , FilePermissions(std::move(file_permissions))
   , ImportLibrary(implib)
   , Optional(optional)
-  , Backtrace(std::move(backtrace))
 {
   this->ActionsPerConfig = true;
   this->NamelinkMode = NamelinkModeNone;
@@ -48,20 +62,69 @@ cmInstallTargetGenerator::~cmInstallTargetGenerator() = default;
 void cmInstallTargetGenerator::GenerateScriptForConfig(
   std::ostream& os, const std::string& config, Indent indent)
 {
+  // Compute the list of files to install for this target.
+  Files files = this->GetFiles(config);
+
+  // Skip this rule if no files are to be installed for the target.
+  if (files.From.empty()) {
+    return;
+  }
+
+  // Compute the effective install destination.
+  std::string dest = this->GetDestination(config);
+  if (!files.ToDir.empty()) {
+    dest = cmStrCat(dest, '/', files.ToDir);
+  }
+
+  // Tweak files located in the destination directory.
+  std::string toDir = cmStrCat(this->ConvertToAbsoluteDestination(dest), '/');
+
+  // Add pre-installation tweaks.
+  if (!files.NoTweak) {
+    this->AddTweak(os, indent, config, toDir, files.To,
+                   &cmInstallTargetGenerator::PreReplacementTweaks);
+  }
+
+  // Write code to install the target file.
+  const char* no_dir_permissions = nullptr;
+  const char* no_rename = nullptr;
+  bool optional = this->Optional || this->ImportLibrary;
+  std::string literal_args;
+  if (!files.FromDir.empty()) {
+    literal_args += " FILES_FROM_DIR \"" + files.FromDir + "\"";
+  }
+  if (files.UseSourcePermissions) {
+    literal_args += " USE_SOURCE_PERMISSIONS";
+  }
+  this->AddInstallRule(os, dest, files.Type, files.From, optional,
+                       this->FilePermissions.c_str(), no_dir_permissions,
+                       no_rename, literal_args.c_str(), indent);
+
+  // Add post-installation tweaks.
+  if (!files.NoTweak) {
+    this->AddTweak(os, indent, config, toDir, files.To,
+                   &cmInstallTargetGenerator::PostReplacementTweaks);
+  }
+}
+
+cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
+  std::string const& config) const
+{
+  Files files;
+
   cmStateEnums::TargetType targetType = this->Target->GetType();
-  cmInstallType type = cmInstallType();
   switch (targetType) {
     case cmStateEnums::EXECUTABLE:
-      type = cmInstallType_EXECUTABLE;
+      files.Type = cmInstallType_EXECUTABLE;
       break;
     case cmStateEnums::STATIC_LIBRARY:
-      type = cmInstallType_STATIC_LIBRARY;
+      files.Type = cmInstallType_STATIC_LIBRARY;
       break;
     case cmStateEnums::SHARED_LIBRARY:
-      type = cmInstallType_SHARED_LIBRARY;
+      files.Type = cmInstallType_SHARED_LIBRARY;
       break;
     case cmStateEnums::MODULE_LIBRARY:
-      type = cmInstallType_MODULE_LIBRARY;
+      files.Type = cmInstallType_MODULE_LIBRARY;
       break;
     case cmStateEnums::INTERFACE_LIBRARY:
       // Not reachable. We never create a cmInstallTargetGenerator for
@@ -70,9 +133,21 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
              "INTERFACE_LIBRARY targets have no installable outputs.");
       break;
 
-    case cmStateEnums::OBJECT_LIBRARY:
-      this->GenerateScriptForConfigObjectLibrary(os, config, indent);
-      return;
+    case cmStateEnums::OBJECT_LIBRARY: {
+      // Compute all the object files inside this target
+      std::vector<std::string> objects;
+      this->Target->GetTargetObjectNames(config, objects);
+
+      files.Type = cmInstallType_FILES;
+      files.NoTweak = true;
+      files.FromDir = this->Target->GetObjectDirectory(config);
+      files.ToDir = computeInstallObjectDir(this->Target, config);
+      for (std::string& obj : objects) {
+        files.From.emplace_back(obj);
+        files.To.emplace_back(std::move(obj));
+      }
+      return files;
+    }
 
     case cmStateEnums::UTILITY:
     case cmStateEnums::GLOBAL_TARGET:
@@ -80,7 +155,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
       this->Target->GetLocalGenerator()->IssueMessage(
         MessageType::INTERNAL_ERROR,
         "cmInstallTargetGenerator created with non-installable target.");
-      return;
+      return files;
   }
 
   // Compute the build tree directory from which to copy the target.
@@ -97,14 +172,6 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
       cmStrCat(this->Target->GetDirectory(config, artifact), '/');
   }
 
-  std::string toDir = cmStrCat(
-    this->ConvertToAbsoluteDestination(this->GetDestination(config)), '/');
-
-  // Compute the list of files to install for this target.
-  std::vector<std::string> filesFrom;
-  std::vector<std::string> filesTo;
-  std::string literal_args;
-
   if (targetType == cmStateEnums::EXECUTABLE) {
     // There is a bug in cmInstallCommand if this fails.
     assert(this->NamelinkMode == NamelinkModeNone);
@@ -113,21 +180,21 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
       this->Target->GetExecutableNames(config);
     if (this->ImportLibrary) {
       std::string from1 = fromDirConfig + targetNames.ImportLibrary;
-      std::string to1 = toDir + targetNames.ImportLibrary;
-      filesFrom.push_back(std::move(from1));
-      filesTo.push_back(std::move(to1));
+      std::string to1 = targetNames.ImportLibrary;
+      files.From.emplace_back(std::move(from1));
+      files.To.emplace_back(std::move(to1));
       std::string targetNameImportLib;
       if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
                                          targetNameImportLib)) {
-        filesFrom.push_back(fromDirConfig + targetNameImportLib);
-        filesTo.push_back(toDir + targetNameImportLib);
+        files.From.emplace_back(fromDirConfig + targetNameImportLib);
+        files.To.emplace_back(targetNameImportLib);
       }
 
       // An import library looks like a static library.
-      type = cmInstallType_STATIC_LIBRARY;
+      files.Type = cmInstallType_STATIC_LIBRARY;
     } else {
       std::string from1 = fromDirConfig + targetNames.Output;
-      std::string to1 = toDir + targetNames.Output;
+      std::string to1 = targetNames.Output;
 
       // Handle OSX Bundles.
       if (this->Target->IsAppBundleOnApple()) {
@@ -142,8 +209,8 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
         }
 
         // Install the whole app bundle directory.
-        type = cmInstallType_DIRECTORY;
-        literal_args += " USE_SOURCE_PERMISSIONS";
+        files.Type = cmInstallType_DIRECTORY;
+        files.UseSourcePermissions = true;
         from1 += ".";
         from1 += ext;
 
@@ -159,14 +226,14 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
         // Tweaks apply to the real file, so list it first.
         if (targetNames.Real != targetNames.Output) {
           std::string from2 = fromDirConfig + targetNames.Real;
-          std::string to2 = toDir += targetNames.Real;
-          filesFrom.push_back(std::move(from2));
-          filesTo.push_back(std::move(to2));
+          std::string to2 = targetNames.Real;
+          files.From.emplace_back(std::move(from2));
+          files.To.emplace_back(std::move(to2));
         }
       }
 
-      filesFrom.push_back(std::move(from1));
-      filesTo.push_back(std::move(to1));
+      files.From.emplace_back(std::move(from1));
+      files.To.emplace_back(std::move(to1));
     }
   } else {
     cmGeneratorTarget::Names targetNames =
@@ -176,18 +243,18 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
       assert(this->NamelinkMode == NamelinkModeNone);
 
       std::string from1 = fromDirConfig + targetNames.ImportLibrary;
-      std::string to1 = toDir + targetNames.ImportLibrary;
-      filesFrom.push_back(std::move(from1));
-      filesTo.push_back(std::move(to1));
+      std::string to1 = targetNames.ImportLibrary;
+      files.From.emplace_back(std::move(from1));
+      files.To.emplace_back(std::move(to1));
       std::string targetNameImportLib;
       if (this->Target->GetImplibGNUtoMS(config, targetNames.ImportLibrary,
                                          targetNameImportLib)) {
-        filesFrom.push_back(fromDirConfig + targetNameImportLib);
-        filesTo.push_back(toDir + targetNameImportLib);
+        files.From.emplace_back(fromDirConfig + targetNameImportLib);
+        files.To.emplace_back(targetNameImportLib);
       }
 
       // An import library looks like a static library.
-      type = cmInstallType_STATIC_LIBRARY;
+      files.Type = cmInstallType_STATIC_LIBRARY;
     } else if (this->Target->IsFrameworkOnApple()) {
       // FIXME: In principle we should be able to
       //   assert(this->NamelinkMode == NamelinkModeNone);
@@ -207,7 +274,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
           break;
         case NamelinkModeOnly:
           // Assume the NamelinkModeSkip instance will warn and install.
-          return;
+          return files;
         case NamelinkModeSkip: {
           std::string e = "Target '" + this->Target->GetName() +
             "' was changed to a FRAMEWORK sometime after install().  "
@@ -219,36 +286,36 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
       }
 
       // Install the whole framework directory.
-      type = cmInstallType_DIRECTORY;
-      literal_args += " USE_SOURCE_PERMISSIONS";
+      files.Type = cmInstallType_DIRECTORY;
+      files.UseSourcePermissions = true;
 
       std::string from1 = fromDirConfig + targetNames.Output;
       from1 = cmSystemTools::GetFilenamePath(from1);
 
       // Tweaks apply to the binary inside the bundle.
-      std::string to1 = toDir + targetNames.Real;
+      std::string to1 = targetNames.Real;
 
-      filesFrom.push_back(std::move(from1));
-      filesTo.push_back(std::move(to1));
+      files.From.emplace_back(std::move(from1));
+      files.To.emplace_back(std::move(to1));
     } else if (this->Target->IsCFBundleOnApple()) {
       // Install the whole app bundle directory.
-      type = cmInstallType_DIRECTORY;
-      literal_args += " USE_SOURCE_PERMISSIONS";
+      files.Type = cmInstallType_DIRECTORY;
+      files.UseSourcePermissions = true;
 
       std::string targetNameBase =
         targetNames.Output.substr(0, targetNames.Output.find('/'));
 
       std::string from1 = fromDirConfig + targetNameBase;
-      std::string to1 = toDir + targetNames.Output;
+      std::string to1 = targetNames.Output;
 
-      filesFrom.push_back(std::move(from1));
-      filesTo.push_back(std::move(to1));
+      files.From.emplace_back(std::move(from1));
+      files.To.emplace_back(std::move(to1));
     } else {
       bool haveNamelink = false;
 
       // Library link name.
       std::string fromName = fromDirConfig + targetNames.Output;
-      std::string toName = toDir + targetNames.Output;
+      std::string toName = targetNames.Output;
 
       // Library interface name.
       std::string fromSOName;
@@ -256,7 +323,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
       if (targetNames.SharedObject != targetNames.Output) {
         haveNamelink = true;
         fromSOName = fromDirConfig + targetNames.SharedObject;
-        toSOName = toDir + targetNames.SharedObject;
+        toSOName = targetNames.SharedObject;
       }
 
       // Library implementation name.
@@ -266,7 +333,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
           targetNames.Real != targetNames.SharedObject) {
         haveNamelink = true;
         fromRealName = fromDirConfig + targetNames.Real;
-        toRealName = toDir + targetNames.Real;
+        toRealName = targetNames.Real;
       }
 
       // Add the names based on the current namelink mode.
@@ -274,95 +341,42 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
         // With a namelink we need to check the mode.
         if (this->NamelinkMode == NamelinkModeOnly) {
           // Install the namelink only.
-          filesFrom.push_back(fromName);
-          filesTo.push_back(toName);
+          files.From.emplace_back(fromName);
+          files.To.emplace_back(toName);
         } else {
           // Install the real file if it has its own name.
           if (!fromRealName.empty()) {
-            filesFrom.push_back(fromRealName);
-            filesTo.push_back(toRealName);
+            files.From.emplace_back(fromRealName);
+            files.To.emplace_back(toRealName);
           }
 
           // Install the soname link if it has its own name.
           if (!fromSOName.empty()) {
-            filesFrom.push_back(fromSOName);
-            filesTo.push_back(toSOName);
+            files.From.emplace_back(fromSOName);
+            files.To.emplace_back(toSOName);
           }
 
           // Install the namelink if it is not to be skipped.
           if (this->NamelinkMode != NamelinkModeSkip) {
-            filesFrom.push_back(fromName);
-            filesTo.push_back(toName);
+            files.From.emplace_back(fromName);
+            files.To.emplace_back(toName);
           }
         }
       } else {
         // Without a namelink there will be only one file.  Install it
         // if this is not a namelink-only rule.
         if (this->NamelinkMode != NamelinkModeOnly) {
-          filesFrom.push_back(fromName);
-          filesTo.push_back(toName);
+          files.From.emplace_back(fromName);
+          files.To.emplace_back(toName);
         }
       }
     }
   }
 
   // If this fails the above code is buggy.
-  assert(filesFrom.size() == filesTo.size());
-
-  // Skip this rule if no files are to be installed for the target.
-  if (filesFrom.empty()) {
-    return;
-  }
-
-  // Add pre-installation tweaks.
-  this->AddTweak(os, indent, config, filesTo,
-                 &cmInstallTargetGenerator::PreReplacementTweaks);
-
-  // Write code to install the target file.
-  const char* no_dir_permissions = nullptr;
-  const char* no_rename = nullptr;
-  bool optional = this->Optional || this->ImportLibrary;
-  this->AddInstallRule(os, this->GetDestination(config), type, filesFrom,
-                       optional, this->FilePermissions.c_str(),
-                       no_dir_permissions, no_rename, literal_args.c_str(),
-                       indent);
-
-  // Add post-installation tweaks.
-  this->AddTweak(os, indent, config, filesTo,
-                 &cmInstallTargetGenerator::PostReplacementTweaks);
-}
+  assert(files.From.size() == files.To.size());
 
-static std::string computeInstallObjectDir(cmGeneratorTarget* gt,
-                                           std::string const& config)
-{
-  std::string objectDir = "objects";
-  if (!config.empty()) {
-    objectDir += "-";
-    objectDir += config;
-  }
-  objectDir += "/";
-  objectDir += gt->GetName();
-  return objectDir;
-}
-
-void cmInstallTargetGenerator::GenerateScriptForConfigObjectLibrary(
-  std::ostream& os, const std::string& config, Indent indent)
-{
-  // Compute all the object files inside this target
-  std::vector<std::string> objects;
-  this->Target->GetTargetObjectNames(config, objects);
-
-  std::string const dest = this->GetDestination(config) + "/" +
-    computeInstallObjectDir(this->Target, config);
-
-  std::string const obj_dir = this->Target->GetObjectDirectory(config);
-  std::string const literal_args = " FILES_FROM_DIR \"" + obj_dir + "\"";
-
-  const char* no_dir_permissions = nullptr;
-  const char* no_rename = nullptr;
-  this->AddInstallRule(os, dest, cmInstallType_FILES, objects, this->Optional,
-                       this->FilePermissions.c_str(), no_dir_permissions,
-                       no_rename, literal_args.c_str(), indent);
+  return files;
 }
 
 void cmInstallTargetGenerator::GetInstallObjectNames(
@@ -464,12 +478,14 @@ void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
 
 void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
                                         const std::string& config,
+                                        std::string const& dir,
                                         std::vector<std::string> const& files,
                                         TweakMethod tweak)
 {
   if (files.size() == 1) {
     // Tweak a single file.
-    this->AddTweak(os, indent, config, this->GetDestDirPath(files[0]), tweak);
+    this->AddTweak(os, indent, config,
+                   this->GetDestDirPath(cmStrCat(dir, files[0])), tweak);
   } else {
     // Generate a foreach loop to tweak multiple files.
     std::ostringstream tw;
@@ -479,7 +495,8 @@ void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
       Indent indent2 = indent.Next().Next();
       os << indent << "foreach(file\n";
       for (std::string const& f : files) {
-        os << indent2 << "\"" << this->GetDestDirPath(f) << "\"\n";
+        os << indent2 << "\"" << this->GetDestDirPath(cmStrCat(dir, f))
+           << "\"\n";
       }
       os << indent2 << ")\n";
       os << tws;
index a53a75a..8c5d444 100644 (file)
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "cmInstallGenerator.h"
+#include "cmInstallType.h"
 #include "cmListFileCache.h"
 #include "cmScriptGenerator.h"
 
@@ -65,21 +66,41 @@ public:
 
   std::string GetDestination(std::string const& config) const;
 
-  cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
+  struct Files
+  {
+    // Names or paths of files to be read from the source or build tree.
+    // The paths may be computed as [FromDir/] + From[i].
+    std::vector<std::string> From;
+
+    // Corresponding names of files to be written in the install directory.
+    // The paths may be computed as Destination/ + [ToDir/] + To[i].
+    std::vector<std::string> To;
+
+    // Prefix for all files in From.
+    std::string FromDir;
+
+    // Prefix for all files in To.
+    std::string ToDir;
+
+    bool NoTweak = false;
+    bool UseSourcePermissions = false;
+    cmInstallType Type = cmInstallType();
+  };
+  Files GetFiles(std::string const& config) const;
+
+  bool GetOptional() const { return this->Optional; }
 
 protected:
   void GenerateScriptForConfig(std::ostream& os, const std::string& config,
                                Indent indent) override;
-  void GenerateScriptForConfigObjectLibrary(std::ostream& os,
-                                            const std::string& config,
-                                            Indent indent);
   using TweakMethod = void (cmInstallTargetGenerator::*)(std::ostream&, Indent,
                                                          const std::string&,
                                                          const std::string&);
   void AddTweak(std::ostream& os, Indent indent, const std::string& config,
                 std::string const& file, TweakMethod tweak);
   void AddTweak(std::ostream& os, Indent indent, const std::string& config,
-                std::vector<std::string> const& files, TweakMethod tweak);
+                std::string const& dir, std::vector<std::string> const& files,
+                TweakMethod tweak);
   std::string GetDestDirPath(std::string const& file);
   void PreReplacementTweaks(std::ostream& os, Indent indent,
                             const std::string& config,
@@ -111,5 +132,4 @@ protected:
   NamelinkModeType NamelinkMode;
   bool const ImportLibrary;
   bool const Optional;
-  cmListFileBacktrace const Backtrace;
 };
diff --git a/Source/cmJsonObjectDictionary.h b/Source/cmJsonObjectDictionary.h
deleted file mode 100644 (file)
index 8a2b529..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include <string>
-
-// Vocabulary:
-
-static const std::string kARTIFACTS_KEY = "artifacts";
-static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
-static const std::string kCOMPILE_FLAGS_KEY = "compileFlags";
-static const std::string kCONFIGURATIONS_KEY = "configurations";
-static const std::string kDEFINES_KEY = "defines";
-static const std::string kFILE_GROUPS_KEY = "fileGroups";
-static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath";
-static const std::string kFULL_NAME_KEY = "fullName";
-static const std::string kINCLUDE_PATH_KEY = "includePath";
-static const std::string kIS_CMAKE_KEY = "isCMake";
-static const std::string kIS_GENERATED_KEY = "isGenerated";
-static const std::string kIS_SYSTEM_KEY = "isSystem";
-static const std::string kIS_TEMPORARY_KEY = "isTemporary";
-static const std::string kKEY_KEY = "key";
-static const std::string kLANGUAGE_KEY = "language";
-static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage";
-static const std::string kLINK_FLAGS_KEY = "linkFlags";
-static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags";
-static const std::string kLINK_LIBRARIES_KEY = "linkLibraries";
-static const std::string kLINK_PATH_KEY = "linkPath";
-static const std::string kNAME_KEY = "name";
-static const std::string kPATH_KEY = "path";
-static const std::string kPROJECTS_KEY = "projects";
-static const std::string kPROPERTIES_KEY = "properties";
-static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
-static const std::string kSOURCES_KEY = "sources";
-static const std::string kSYSROOT_KEY = "sysroot";
-static const std::string kTARGETS_KEY = "targets";
-static const std::string kTYPE_KEY = "type";
-static const std::string kVALUE_KEY = "value";
-static const std::string kHAS_INSTALL_RULE = "hasInstallRule";
-static const std::string kINSTALL_PATHS = "installPaths";
-static const std::string kCTEST_NAME = "ctestName";
-static const std::string kCTEST_COMMAND = "ctestCommand";
-static const std::string kCTEST_INFO = "ctestInfo";
-static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion";
-static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided";
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
deleted file mode 100644 (file)
index 3a7ae0c..0000000
+++ /dev/null
@@ -1,692 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmJsonObjects.h" // IWYU pragma: keep
-
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <functional>
-#include <limits>
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include <cmext/algorithm>
-
-#include "cmGeneratorExpression.h"
-#include "cmGeneratorTarget.h"
-#include "cmGlobalGenerator.h"
-#include "cmInstallGenerator.h"
-#include "cmInstallSubdirectoryGenerator.h"
-#include "cmInstallTargetGenerator.h"
-#include "cmJsonObjectDictionary.h"
-#include "cmJsonObjects.h"
-#include "cmLinkLineComputer.h"
-#include "cmLocalGenerator.h"
-#include "cmMakefile.h"
-#include "cmProperty.h"
-#include "cmPropertyMap.h"
-#include "cmSourceFile.h"
-#include "cmState.h"
-#include "cmStateDirectory.h"
-#include "cmStateSnapshot.h"
-#include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
-#include "cmSystemTools.h"
-#include "cmTarget.h"
-#include "cmTest.h"
-#include "cmake.h"
-
-namespace {
-
-std::vector<std::string> getConfigurations(const cmake* cm)
-{
-  std::vector<std::string> configurations;
-  const auto& makefiles = cm->GetGlobalGenerator()->GetMakefiles();
-  if (makefiles.empty()) {
-    return configurations;
-  }
-
-  return makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
-}
-
-bool hasString(const Json::Value& v, const std::string& s)
-{
-  return !v.isNull() &&
-    std::any_of(v.begin(), v.end(),
-                [s](const Json::Value& i) { return i.asString() == s; });
-}
-
-template <class T>
-Json::Value fromStringList(const T& in)
-{
-  Json::Value result = Json::arrayValue;
-  for (std::string const& i : in) {
-    result.append(i);
-  }
-  return result;
-}
-
-} // namespace
-
-void cmGetCMakeInputs(const cmGlobalGenerator* gg,
-                      const std::string& sourceDir,
-                      const std::string& buildDir,
-                      std::vector<std::string>* internalFiles,
-                      std::vector<std::string>* explicitFiles,
-                      std::vector<std::string>* tmpFiles)
-{
-  const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/';
-  auto const& makefiles = gg->GetMakefiles();
-  for (const auto& mf : makefiles) {
-    for (std::string const& lf : mf->GetListFiles()) {
-
-      const std::string startOfFile = lf.substr(0, cmakeRootDir.size());
-      const bool isInternal = (startOfFile == cmakeRootDir);
-      const bool isTemporary =
-        !isInternal && (cmHasPrefix(lf, buildDir + '/'));
-
-      std::string toAdd = lf;
-      if (!sourceDir.empty()) {
-        const std::string& relative =
-          cmSystemTools::RelativePath(sourceDir, lf);
-        if (toAdd.size() > relative.size()) {
-          toAdd = relative;
-        }
-      }
-
-      if (isInternal) {
-        if (internalFiles) {
-          internalFiles->push_back(std::move(toAdd));
-        }
-      } else {
-        if (isTemporary) {
-          if (tmpFiles) {
-            tmpFiles->push_back(std::move(toAdd));
-          }
-        } else {
-          if (explicitFiles) {
-            explicitFiles->push_back(std::move(toAdd));
-          }
-        }
-      }
-    }
-  }
-}
-
-Json::Value cmDumpCMakeInputs(const cmake* cm)
-{
-  const cmGlobalGenerator* gg = cm->GetGlobalGenerator();
-  const std::string& buildDir = cm->GetHomeOutputDirectory();
-  const std::string& sourceDir = cm->GetHomeDirectory();
-
-  std::vector<std::string> internalFiles;
-  std::vector<std::string> explicitFiles;
-  std::vector<std::string> tmpFiles;
-  cmGetCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles,
-                   &tmpFiles);
-
-  Json::Value array = Json::arrayValue;
-
-  Json::Value tmp = Json::objectValue;
-  tmp[kIS_CMAKE_KEY] = true;
-  tmp[kIS_TEMPORARY_KEY] = false;
-  tmp[kSOURCES_KEY] = fromStringList(internalFiles);
-  array.append(tmp);
-
-  tmp = Json::objectValue;
-  tmp[kIS_CMAKE_KEY] = false;
-  tmp[kIS_TEMPORARY_KEY] = false;
-  tmp[kSOURCES_KEY] = fromStringList(explicitFiles);
-  array.append(tmp);
-
-  tmp = Json::objectValue;
-  tmp[kIS_CMAKE_KEY] = false;
-  tmp[kIS_TEMPORARY_KEY] = true;
-  tmp[kSOURCES_KEY] = fromStringList(tmpFiles);
-  array.append(tmp);
-
-  return array;
-}
-
-class LanguageData
-{
-public:
-  bool operator==(const LanguageData& other) const;
-
-  void SetDefines(const std::set<std::string>& defines);
-
-  bool IsGenerated = false;
-  std::string Language;
-  std::string Flags;
-  std::vector<std::string> Defines;
-  std::vector<std::pair<std::string, bool>> IncludePathList;
-};
-
-bool LanguageData::operator==(const LanguageData& other) const
-{
-  return Language == other.Language && Defines == other.Defines &&
-    Flags == other.Flags && IncludePathList == other.IncludePathList &&
-    IsGenerated == other.IsGenerated;
-}
-
-void LanguageData::SetDefines(const std::set<std::string>& defines)
-{
-  std::vector<std::string> result;
-  result.reserve(defines.size());
-  for (std::string const& i : defines) {
-    result.push_back(i);
-  }
-  std::sort(result.begin(), result.end());
-  Defines = std::move(result);
-}
-
-namespace std {
-
-template <>
-struct hash<LanguageData>
-{
-  std::size_t operator()(const LanguageData& in) const
-  {
-    using std::hash;
-    size_t result =
-      hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags);
-    for (auto const& i : in.IncludePathList) {
-      result = result ^
-        (hash<std::string>()(i.first) ^
-         (i.second ? std::numeric_limits<size_t>::max() : 0));
-    }
-    for (auto const& i : in.Defines) {
-      result = result ^ hash<std::string>()(i);
-    }
-    result =
-      result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0);
-    return result;
-  }
-};
-
-} // namespace std
-
-static Json::Value DumpSourceFileGroup(const LanguageData& data,
-                                       const std::vector<std::string>& files,
-                                       const std::string& baseDir)
-{
-  Json::Value result = Json::objectValue;
-
-  if (!data.Language.empty()) {
-    result[kLANGUAGE_KEY] = data.Language;
-    if (!data.Flags.empty()) {
-      result[kCOMPILE_FLAGS_KEY] = data.Flags;
-    }
-    if (!data.IncludePathList.empty()) {
-      Json::Value includes = Json::arrayValue;
-      for (auto const& i : data.IncludePathList) {
-        Json::Value tmp = Json::objectValue;
-        tmp[kPATH_KEY] = i.first;
-        if (i.second) {
-          tmp[kIS_SYSTEM_KEY] = i.second;
-        }
-        includes.append(tmp);
-      }
-      result[kINCLUDE_PATH_KEY] = includes;
-    }
-    if (!data.Defines.empty()) {
-      result[kDEFINES_KEY] = fromStringList(data.Defines);
-    }
-  }
-
-  result[kIS_GENERATED_KEY] = data.IsGenerated;
-
-  Json::Value sourcesValue = Json::arrayValue;
-  for (auto const& i : files) {
-    const std::string relPath = cmSystemTools::RelativePath(baseDir, i);
-    sourcesValue.append(relPath.size() < i.size() ? relPath : i);
-  }
-
-  result[kSOURCES_KEY] = sourcesValue;
-  return result;
-}
-
-static Json::Value DumpSourceFilesList(
-  cmGeneratorTarget* target, const std::string& config,
-  const std::map<std::string, LanguageData>& languageDataMap)
-{
-  // Collect sourcefile groups:
-
-  std::vector<cmSourceFile*> files;
-  target->GetSourceFiles(files, config);
-
-  std::unordered_map<LanguageData, std::vector<std::string>> fileGroups;
-  for (cmSourceFile* file : files) {
-    LanguageData fileData;
-    fileData.Language = file->GetOrDetermineLanguage();
-    if (!fileData.Language.empty()) {
-      const LanguageData& ld = languageDataMap.at(fileData.Language);
-      cmLocalGenerator* lg = target->GetLocalGenerator();
-      cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
-                                                        fileData.Language);
-
-      std::string compileFlags = ld.Flags;
-      const std::string COMPILE_FLAGS("COMPILE_FLAGS");
-      if (cmProp cflags = file->GetProperty(COMPILE_FLAGS)) {
-        lg->AppendFlags(compileFlags,
-                        genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
-      }
-      const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
-      if (cmProp coptions = file->GetProperty(COMPILE_OPTIONS)) {
-        lg->AppendCompileOptions(
-          compileFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
-      }
-      fileData.Flags = compileFlags;
-
-      // Add include directories from source file properties.
-      std::vector<std::string> includes;
-
-      const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
-      if (cmProp cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) {
-        const std::string& evaluatedIncludes =
-          genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES);
-        lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file);
-
-        for (const auto& include : includes) {
-          fileData.IncludePathList.emplace_back(
-            include,
-            target->IsSystemIncludeDirectory(include, config,
-                                             fileData.Language));
-        }
-      }
-
-      fileData.IncludePathList.insert(fileData.IncludePathList.end(),
-                                      ld.IncludePathList.begin(),
-                                      ld.IncludePathList.end());
-
-      const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
-      std::set<std::string> defines;
-      if (cmProp defs = file->GetProperty(COMPILE_DEFINITIONS)) {
-        lg->AppendDefines(
-          defines, genexInterpreter.Evaluate(*defs, COMPILE_DEFINITIONS));
-      }
-
-      const std::string defPropName =
-        "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
-      if (cmProp config_defs = file->GetProperty(defPropName)) {
-        lg->AppendDefines(
-          defines,
-          genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
-      }
-
-      defines.insert(ld.Defines.begin(), ld.Defines.end());
-
-      fileData.SetDefines(defines);
-    }
-
-    fileData.IsGenerated = file->GetIsGenerated();
-    std::vector<std::string>& groupFileList = fileGroups[fileData];
-    groupFileList.push_back(file->ResolveFullPath());
-  }
-
-  const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory();
-  Json::Value result = Json::arrayValue;
-  for (auto const& it : fileGroups) {
-    Json::Value group = DumpSourceFileGroup(it.first, it.second, baseDir);
-    if (!group.isNull()) {
-      result.append(group);
-    }
-  }
-
-  return result;
-}
-
-static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo,
-                                 const std::string& config)
-{
-  Json::Value result = Json::objectValue;
-  result[kCTEST_NAME] = testInfo->GetName();
-
-  // Concat command entries together. After the first should be the arguments
-  // for the command
-  std::string command;
-  for (auto const& cmd : testInfo->GetCommand()) {
-    command.append(cmd);
-    command.append(" ");
-  }
-
-  // Remove any config specific variables from the output.
-  result[kCTEST_COMMAND] =
-    cmGeneratorExpression::Evaluate(command, lg, config);
-
-  // Build up the list of properties that may have been specified
-  Json::Value properties = Json::arrayValue;
-  for (auto& prop : testInfo->GetProperties().GetList()) {
-    Json::Value entry = Json::objectValue;
-    entry[kKEY_KEY] = prop.first;
-
-    // Remove config variables from the value too.
-    entry[kVALUE_KEY] =
-      cmGeneratorExpression::Evaluate(prop.second, lg, config);
-    properties.append(entry);
-  }
-  result[kPROPERTIES_KEY] = properties;
-
-  return result;
-}
-
-static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config,
-                              Json::Value* result)
-{
-  auto mf = lg->GetMakefile();
-  std::vector<cmTest*> tests;
-  mf->GetTests(config, tests);
-  for (auto test : tests) {
-    Json::Value tmp = DumpCTestInfo(lg, test, config);
-    if (!tmp.isNull()) {
-      result->append(tmp);
-    }
-  }
-}
-
-static Json::Value DumpCTestProjectList(const cmake* cm,
-                                        std::string const& config)
-{
-  Json::Value result = Json::arrayValue;
-
-  auto globalGen = cm->GetGlobalGenerator();
-
-  for (const auto& projectIt : globalGen->GetProjectMap()) {
-    Json::Value pObj = Json::objectValue;
-    pObj[kNAME_KEY] = projectIt.first;
-
-    Json::Value tests = Json::arrayValue;
-
-    // Gather tests for every generator
-    for (const auto& lg : projectIt.second) {
-      // Make sure they're generated.
-      lg->GenerateTestFiles();
-      DumpMakefileTests(lg, config, &tests);
-    }
-
-    pObj[kCTEST_INFO] = tests;
-
-    result.append(pObj);
-  }
-
-  return result;
-}
-
-static Json::Value DumpCTestConfiguration(const cmake* cm,
-                                          const std::string& config)
-{
-  Json::Value result = Json::objectValue;
-  result[kNAME_KEY] = config;
-
-  result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config);
-
-  return result;
-}
-
-static Json::Value DumpCTestConfigurationsList(const cmake* cm)
-{
-  Json::Value result = Json::arrayValue;
-
-  for (const std::string& c : getConfigurations(cm)) {
-    result.append(DumpCTestConfiguration(cm, c));
-  }
-
-  return result;
-}
-
-Json::Value cmDumpCTestInfo(const cmake* cm)
-{
-  Json::Value result = Json::objectValue;
-  result[kCONFIGURATIONS_KEY] = DumpCTestConfigurationsList(cm);
-  return result;
-}
-
-static Json::Value DumpTarget(cmGeneratorTarget* target,
-                              const std::string& config)
-{
-  cmLocalGenerator* lg = target->GetLocalGenerator();
-
-  const cmStateEnums::TargetType type = target->GetType();
-  const std::string typeName = cmState::GetTargetTypeName(type);
-
-  Json::Value ttl = Json::arrayValue;
-  ttl.append("EXECUTABLE");
-  ttl.append("STATIC_LIBRARY");
-  ttl.append("SHARED_LIBRARY");
-  ttl.append("MODULE_LIBRARY");
-  ttl.append("OBJECT_LIBRARY");
-  ttl.append("UTILITY");
-  ttl.append("INTERFACE_LIBRARY");
-
-  if (!hasString(ttl, typeName) || target->IsImported()) {
-    return Json::Value();
-  }
-
-  Json::Value result = Json::objectValue;
-  result[kNAME_KEY] = target->GetName();
-  result[kIS_GENERATOR_PROVIDED_KEY] =
-    target->Target->GetIsGeneratorProvided();
-  result[kTYPE_KEY] = typeName;
-  result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
-  result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
-
-  if (type == cmStateEnums::INTERFACE_LIBRARY) {
-    return result;
-  }
-
-  result[kFULL_NAME_KEY] = target->GetFullName(config);
-
-  if (target->Target->GetHaveInstallRule()) {
-    result[kHAS_INSTALL_RULE] = true;
-
-    Json::Value installPaths = Json::arrayValue;
-    for (const auto& installGenerator :
-         target->Makefile->GetInstallGenerators()) {
-      auto installTargetGenerator =
-        dynamic_cast<cmInstallTargetGenerator*>(installGenerator.get());
-      if (installTargetGenerator != nullptr &&
-          installTargetGenerator->GetTarget()->Target == target->Target) {
-        auto dest = installTargetGenerator->GetDestination(config);
-
-        std::string installPath;
-        if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) {
-          installPath = dest;
-        } else {
-          installPath = cmStrCat(
-            target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"), '/',
-            dest);
-        }
-
-        installPaths.append(installPath);
-      }
-    }
-
-    result[kINSTALL_PATHS] = installPaths;
-  }
-
-  if (target->HaveWellDefinedOutputFiles()) {
-    Json::Value artifacts = Json::arrayValue;
-    artifacts.append(
-      target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact));
-    if (target->HasImportLibrary(config)) {
-      artifacts.append(
-        target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
-    }
-    if (target->IsDLLPlatform()) {
-      const cmGeneratorTarget::OutputInfo* output =
-        target->GetOutputInfo(config);
-      if (output && !output->PdbDir.empty()) {
-        artifacts.append(output->PdbDir + '/' + target->GetPDBName(config));
-      }
-    }
-    result[kARTIFACTS_KEY] = artifacts;
-
-    result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config);
-
-    std::string linkLibs;
-    std::string linkFlags;
-    std::string linkLanguageFlags;
-    std::string frameworkPath;
-    std::string linkPath;
-    cmLinkLineComputer linkLineComputer(lg,
-                                        lg->GetStateSnapshot().GetDirectory());
-    lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags,
-                       linkFlags, frameworkPath, linkPath, target);
-
-    linkLibs = cmTrimWhitespace(linkLibs);
-    linkFlags = cmTrimWhitespace(linkFlags);
-    linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
-    frameworkPath = cmTrimWhitespace(frameworkPath);
-    linkPath = cmTrimWhitespace(linkPath);
-
-    if (!cmTrimWhitespace(linkLibs).empty()) {
-      result[kLINK_LIBRARIES_KEY] = linkLibs;
-    }
-    if (!cmTrimWhitespace(linkFlags).empty()) {
-      result[kLINK_FLAGS_KEY] = linkFlags;
-    }
-    if (!cmTrimWhitespace(linkLanguageFlags).empty()) {
-      result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags;
-    }
-    if (!frameworkPath.empty()) {
-      result[kFRAMEWORK_PATH_KEY] = frameworkPath;
-    }
-    if (!linkPath.empty()) {
-      result[kLINK_PATH_KEY] = linkPath;
-    }
-    const std::string sysroot =
-      lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT");
-    if (!sysroot.empty()) {
-      result[kSYSROOT_KEY] = sysroot;
-    }
-  }
-
-  std::set<std::string> languages;
-  target->GetLanguages(languages, config);
-  std::map<std::string, LanguageData> languageDataMap;
-
-  for (std::string const& lang : languages) {
-    LanguageData& ld = languageDataMap[lang];
-    ld.Language = lang;
-    lg->GetTargetCompileFlags(target, config, lang, ld.Flags);
-    std::set<std::string> defines;
-    lg->GetTargetDefines(target, config, lang, defines);
-    ld.SetDefines(defines);
-    std::vector<std::string> includePathList;
-    lg->GetIncludeDirectories(includePathList, target, lang, config);
-    for (std::string const& i : includePathList) {
-      ld.IncludePathList.emplace_back(
-        i, target->IsSystemIncludeDirectory(i, config, lang));
-    }
-  }
-
-  Json::Value sourceGroupsValue =
-    DumpSourceFilesList(target, config, languageDataMap);
-  if (!sourceGroupsValue.empty()) {
-    result[kFILE_GROUPS_KEY] = sourceGroupsValue;
-  }
-
-  return result;
-}
-
-static Json::Value DumpTargetsList(
-  const std::vector<cmLocalGenerator*>& generators, const std::string& config)
-{
-  Json::Value result = Json::arrayValue;
-
-  std::vector<cmGeneratorTarget*> targetList;
-  for (auto const& lgIt : generators) {
-    cm::append(targetList, lgIt->GetGeneratorTargets());
-  }
-  std::sort(targetList.begin(), targetList.end());
-
-  for (cmGeneratorTarget* target : targetList) {
-    Json::Value tmp = DumpTarget(target, config);
-    if (!tmp.isNull()) {
-      result.append(tmp);
-    }
-  }
-
-  return result;
-}
-
-static Json::Value DumpProjectList(const cmake* cm, std::string const& config)
-{
-  Json::Value result = Json::arrayValue;
-
-  auto globalGen = cm->GetGlobalGenerator();
-
-  for (auto const& projectIt : globalGen->GetProjectMap()) {
-    Json::Value pObj = Json::objectValue;
-    pObj[kNAME_KEY] = projectIt.first;
-
-    // All Projects must have at least one local generator
-    assert(!projectIt.second.empty());
-    const cmLocalGenerator* lg = projectIt.second.at(0);
-
-    // Project structure information:
-    const cmMakefile* mf = lg->GetMakefile();
-    auto minVersion = mf->GetSafeDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
-    pObj[kMINIMUM_CMAKE_VERSION] = minVersion;
-    pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory();
-    pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory();
-    pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config);
-
-    // For a project-level install rule it might be defined in any of its
-    // associated generators.
-    bool hasInstallRule = false;
-    for (const auto generator : projectIt.second) {
-      for (const auto& installGen :
-           generator->GetMakefile()->GetInstallGenerators()) {
-        if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(installGen.get())) {
-          hasInstallRule = true;
-          break;
-        }
-      }
-
-      if (hasInstallRule) {
-        break;
-      }
-    }
-
-    pObj[kHAS_INSTALL_RULE] = hasInstallRule;
-
-    result.append(pObj);
-  }
-
-  return result;
-}
-
-static Json::Value DumpConfiguration(const cmake* cm,
-                                     const std::string& config)
-{
-  Json::Value result = Json::objectValue;
-  result[kNAME_KEY] = config;
-
-  result[kPROJECTS_KEY] = DumpProjectList(cm, config);
-
-  return result;
-}
-
-static Json::Value DumpConfigurationsList(const cmake* cm)
-{
-  Json::Value result = Json::arrayValue;
-
-  for (std::string const& c : getConfigurations(cm)) {
-    result.append(DumpConfiguration(cm, c));
-  }
-
-  return result;
-}
-
-Json::Value cmDumpCodeModel(const cmake* cm)
-{
-  Json::Value result = Json::objectValue;
-  result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(cm);
-  return result;
-}
diff --git a/Source/cmJsonObjects.h b/Source/cmJsonObjects.h
deleted file mode 100644 (file)
index 80a4834..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <string>
-#include <vector>
-
-#include <cm3p/json/value.h>
-
-class cmake;
-class cmGlobalGenerator;
-
-extern void cmGetCMakeInputs(const cmGlobalGenerator* gg,
-                             const std::string& sourceDir,
-                             const std::string& buildDir,
-                             std::vector<std::string>* internalFiles,
-                             std::vector<std::string>* explicitFiles,
-                             std::vector<std::string>* tmpFiles);
-
-extern Json::Value cmDumpCodeModel(const cmake* cm);
-extern Json::Value cmDumpCTestInfo(const cmake* cm);
-extern Json::Value cmDumpCMakeInputs(const cmake* cm);
index dfdd3ff..7ad8690 100644 (file)
@@ -98,7 +98,8 @@ void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target,
                                              std::string const& config,
                                              DependencyMap& dependencies)
 {
-  auto implementationLibraries = target.GetLinkImplementationLibraries(config);
+  const auto* implementationLibraries =
+    target.GetLinkImplementationLibraries(config);
   if (implementationLibraries != nullptr) {
     for (auto const& lib : implementationLibraries->Libraries) {
       auto const& name = lib.AsStr();
@@ -106,7 +107,7 @@ void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target,
     }
   }
 
-  auto interfaceLibraries =
+  const auto* interfaceLibraries =
     target.GetLinkInterfaceLibraries(config, &target, true);
   if (interfaceLibraries != nullptr) {
     for (auto const& lib : interfaceLibraries->Libraries) {
index 5739fec..9cae926 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "cmLinkLineDeviceComputer.h"
 
+#include <algorithm>
 #include <set>
 #include <utility>
 
@@ -57,17 +58,15 @@ bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
   using ItemVector = cmComputeLinkInformation::ItemVector;
   ItemVector const& items = cli.GetItems();
   std::string config = cli.GetConfig();
-  for (auto const& item : items) {
-    if (item.Target &&
-        item.Target->GetType() == cmStateEnums::STATIC_LIBRARY) {
-      if ((!item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS")) &&
-          item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
+  return std::any_of(
+    items.begin(), items.end(),
+    [](cmComputeLinkInformation::Item const& item) -> bool {
+      return item.Target &&
+        item.Target->GetType() == cmStateEnums::STATIC_LIBRARY &&
         // this dependency requires us to device link it
-        return true;
-      }
-    }
-  }
-  return false;
+        !item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS") &&
+        item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION");
+    });
 }
 
 void cmLinkLineDeviceComputer::ComputeLinkLibraries(
index d70176d..616bf7e 100644 (file)
@@ -133,9 +133,9 @@ public:
     return iterator(const_cast<cmLinkedTree*>(this), 0);
   }
 
-  iterator Push(iterator it) { return Push_impl(it, T()); }
+  iterator Push(iterator it) { return this->Push_impl(it, T()); }
 
-  iterator Push(iterator it, T t) { return Push_impl(it, std::move(t)); }
+  iterator Push(iterator it, T t) { return this->Push_impl(it, std::move(t)); }
 
   bool IsLast(iterator it) { return it.Position == this->Data.size(); }
 
index a2c14bd..fdddb45 100644 (file)
@@ -422,9 +422,10 @@ bool HandleJoinCommand(std::vector<std::string> const& args,
 bool HandleRemoveItemCommand(std::vector<std::string> const& args,
                              cmExecutionStatus& status)
 {
-  if (args.size() < 3) {
-    status.SetError("sub-command REMOVE_ITEM requires two or more arguments.");
-    return false;
+  assert(args.size() >= 2);
+
+  if (args.size() == 2) {
+    return true;
   }
 
   const std::string& listName = args[1];
@@ -609,9 +610,9 @@ public:
 
   bool Validate(std::size_t count) override
   {
-    decltype(Indexes) indexes;
+    decltype(this->Indexes) indexes;
 
-    for (auto index : Indexes) {
+    for (auto index : this->Indexes) {
       indexes.push_back(this->NormalizeIndex(index, count));
     }
     this->Indexes = std::move(indexes);
@@ -750,7 +751,7 @@ bool HandleTransformCommand(std::vector<std::string> const& args,
     {
     }
 
-    operator const std::string&() const { return Name; }
+    operator const std::string&() const { return this->Name; }
 
     std::string Name;
     int Arity = 0;
@@ -1093,8 +1094,9 @@ protected:
 public:
   cmStringSorter(Compare compare, CaseSensitivity caseSensitivity,
                  Order desc = Order::ASCENDING)
-    : filters{ GetCompareFilter(compare), GetCaseFilter(caseSensitivity) }
-    , sortMethod(GetComparisonFunction(compare))
+    : filters{ this->GetCompareFilter(compare),
+               this->GetCaseFilter(caseSensitivity) }
+    , sortMethod(this->GetComparisonFunction(compare))
     , descending(desc == Order::DESCENDING)
   {
   }
@@ -1102,7 +1104,7 @@ public:
   std::string ApplyFilter(const std::string& argument)
   {
     std::string result = argument;
-    for (auto filter : filters) {
+    for (auto filter : this->filters) {
       if (filter != nullptr) {
         result = filter(result);
       }
@@ -1112,13 +1114,13 @@ public:
 
   bool operator()(const std::string& a, const std::string& b)
   {
-    std::string af = ApplyFilter(a);
-    std::string bf = ApplyFilter(b);
+    std::string af = this->ApplyFilter(a);
+    std::string bf = this->ApplyFilter(b);
     bool result;
-    if (descending) {
-      result = sortMethod(bf, af);
+    if (this->descending) {
+      result = this->sortMethod(bf, af);
     } else {
-      result = sortMethod(af, bf);
+      result = this->sortMethod(af, bf);
     }
     return result;
   }
@@ -1424,7 +1426,7 @@ public:
 
   bool operator()(const std::string& target)
   {
-    return regex.find(target) ^ includeMatches;
+    return this->regex.find(target) ^ this->includeMatches;
   }
 
 private:
index 70ef5af..1464a14 100644 (file)
@@ -30,6 +30,7 @@ struct cmListFileParser
   bool ParseFunction(const char* name, long line);
   bool AddArgument(cmListFileLexer_Token* token,
                    cmListFileArgument::Delimiter delim);
+  cm::optional<cmListFileContext> CheckNesting() const;
   cmListFile* ListFile;
   cmListFileBacktrace Backtrace;
   cmMessenger* Messenger;
@@ -104,7 +105,7 @@ bool cmListFileParser::ParseFile(const char* filename)
     return false;
   }
 
-  return Parse();
+  return this->Parse();
 }
 
 bool cmListFileParser::ParseString(const char* str,
@@ -117,7 +118,7 @@ bool cmListFileParser::ParseString(const char* str,
     return false;
   }
 
-  return Parse();
+  return this->Parse();
 }
 
 bool cmListFileParser::Parse()
@@ -158,6 +159,17 @@ bool cmListFileParser::Parse()
       return false;
     }
   }
+
+  // Check if all functions are nested properly.
+  if (auto badNesting = this->CheckNesting()) {
+    this->Messenger->IssueMessage(
+      MessageType::FATAL_ERROR,
+      "Flow control statements are not properly nested.",
+      this->Backtrace.Push(*badNesting));
+    cmSystemTools::SetFatalErrorOccured();
+    return false;
+  }
+
   return true;
 }
 
@@ -317,6 +329,112 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
   return true;
 }
 
+namespace {
+enum class NestingStateEnum
+{
+  If,
+  Else,
+  While,
+  Foreach,
+  Function,
+  Macro,
+};
+
+struct NestingState
+{
+  NestingStateEnum State;
+  cmListFileContext Context;
+};
+
+bool TopIs(std::vector<NestingState>& stack, NestingStateEnum state)
+{
+  return !stack.empty() && stack.back().State == state;
+}
+}
+
+cm::optional<cmListFileContext> cmListFileParser::CheckNesting() const
+{
+  std::vector<NestingState> stack;
+
+  for (auto const& func : this->ListFile->Functions) {
+    auto const& name = func.LowerCaseName();
+    if (name == "if") {
+      stack.push_back({
+        NestingStateEnum::If,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "elseif") {
+      if (!TopIs(stack, NestingStateEnum::If)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.back() = {
+        NestingStateEnum::If,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      };
+    } else if (name == "else") {
+      if (!TopIs(stack, NestingStateEnum::If)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.back() = {
+        NestingStateEnum::Else,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      };
+    } else if (name == "endif") {
+      if (!TopIs(stack, NestingStateEnum::If) &&
+          !TopIs(stack, NestingStateEnum::Else)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "while") {
+      stack.push_back({
+        NestingStateEnum::While,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endwhile") {
+      if (!TopIs(stack, NestingStateEnum::While)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "foreach") {
+      stack.push_back({
+        NestingStateEnum::Foreach,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endforeach") {
+      if (!TopIs(stack, NestingStateEnum::Foreach)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "function") {
+      stack.push_back({
+        NestingStateEnum::Function,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endfunction") {
+      if (!TopIs(stack, NestingStateEnum::Function)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    } else if (name == "macro") {
+      stack.push_back({
+        NestingStateEnum::Macro,
+        cmListFileContext::FromCommandContext(func, this->FileName),
+      });
+    } else if (name == "endmacro") {
+      if (!TopIs(stack, NestingStateEnum::Macro)) {
+        return cmListFileContext::FromCommandContext(func, this->FileName);
+      }
+      stack.pop_back();
+    }
+  }
+
+  if (!stack.empty()) {
+    return stack.back().Context;
+  }
+
+  return cm::nullopt;
+}
+
 // We hold either the bottom scope of a directory or a call/file context.
 // Discriminate these cases via the parent pointer.
 struct cmListFileBacktrace::Entry
index 727fc60..98cb4a7 100644 (file)
@@ -89,6 +89,14 @@ public:
   {
   }
 
+#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
+  cmListFileContext(const cmListFileContext& /*other*/) = default;
+  cmListFileContext(cmListFileContext&& /*other*/) = default;
+
+  cmListFileContext& operator=(const cmListFileContext& /*other*/) = default;
+  cmListFileContext& operator=(cmListFileContext&& /*other*/) = delete;
+#endif
+
   static cmListFileContext FromCommandContext(
     cmCommandContext const& lfcc, std::string const& fileName,
     cm::optional<std::string> deferId = {})
@@ -241,7 +249,7 @@ public:
   BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace())
     : Value(std::move(v))
   {
-    Backtraces.emplace_back(std::move(bt));
+    this->Backtraces.emplace_back(std::move(bt));
   }
   T Value;
   std::vector<cmListFileBacktrace> Backtraces;
index 5790e16..5a7b30f 100644 (file)
@@ -3,10 +3,12 @@
 
 #if !defined(_WIN32) && !defined(__sun)
 // POSIX APIs are needed
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _POSIX_C_SOURCE 200809L
 #endif
 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
 // For isascii
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _XOPEN_SOURCE 700
 #endif
 
 #include "cmCommand.h"
 #include "cmDynamicLoader.h"
 #include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
+// NOLINTNEXTLINE(bugprone-suspicious-include)
 #include "cmCPluginAPI.cxx"
 
 #ifdef __QNX__
 #  include <malloc.h> /* for malloc/free on QNX */
 #endif
 
-class cmListFileBacktrace;
-
 namespace {
 
 const char* LastName = nullptr;
@@ -256,10 +258,12 @@ bool cmLoadCommandCommand(std::vector<std::string> const& args,
   // if the symbol is found call it to set the name on the
   // function blocker
   if (initFunction) {
-    status.GetMakefile().GetState()->AddScriptedCommand(
+    return status.GetMakefile().GetState()->AddScriptedCommand(
       args[0],
-      cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction)));
-    return true;
+      BT<cmState::Command>(
+        cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction)),
+        status.GetMakefile().GetBacktrace()),
+      status.GetMakefile());
   }
   status.SetError("Attempt to load command failed. "
                   "No init function found.");
index b5580e7..73b6fbc 100644 (file)
@@ -3,6 +3,7 @@
 #include "cmLocalGenerator.h"
 
 #include <algorithm>
+#include <array>
 #include <cassert>
 #include <cstdio>
 #include <cstdlib>
 #include <cm/memory>
 #include <cm/string_view>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
@@ -279,7 +282,7 @@ static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs,
                    });
 }
 
-void cmLocalGenerator::TraceDependencies()
+void cmLocalGenerator::TraceDependencies() const
 {
   // Generate the rule files for each target.
   const auto& targets = this->GetGeneratorTargets();
@@ -825,16 +828,13 @@ cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
   return this->Makefile->GetStateSnapshot();
 }
 
-const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
-                                              const std::string& prop)
+cmProp cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
+                                         const std::string& prop)
 {
-  cmProp p;
   if (target) {
-    p = target->GetProperty(prop);
-  } else {
-    p = this->Makefile->GetProperty(prop);
+    return target->GetProperty(prop);
   }
-  return p ? p->c_str() : nullptr;
+  return this->Makefile->GetProperty(prop);
 }
 
 std::string cmLocalGenerator::ConvertToIncludeReference(
@@ -1056,8 +1056,9 @@ cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
   const std::string& target, const std::vector<std::string>& byproducts,
   const std::vector<std::string>& depends,
   const cmCustomCommandLines& commandLines, cmCustomCommandType type,
-  const char* comment, const char* workingDir, bool escapeOldStyle,
-  bool uses_terminal, const std::string& depfile, const std::string& job_pool,
+  const char* comment, const char* workingDir,
+  cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle, bool uses_terminal,
+  const std::string& depfile, const std::string& job_pool,
   bool command_expand_lists, cmObjectLibraryCommands objLibCommands,
   bool stdPipesUTF8)
 {
@@ -1070,7 +1071,8 @@ cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
   detail::AddCustomCommandToTarget(
     *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts,
     depends, commandLines, type, comment, workingDir, escapeOldStyle,
-    uses_terminal, depfile, job_pool, command_expand_lists, stdPipesUTF8);
+    uses_terminal, depfile, job_pool, command_expand_lists, stdPipesUTF8,
+    cmp0116);
 
   return t;
 }
@@ -1078,16 +1080,17 @@ cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
 cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
   const std::string& output, const std::vector<std::string>& depends,
   const std::string& main_dependency, const cmCustomCommandLines& commandLines,
-  const char* comment, const char* workingDir, bool replace,
-  bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
-  const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8)
+  const char* comment, const char* workingDir,
+  cmPolicies::PolicyStatus cmp0116, bool replace, bool escapeOldStyle,
+  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  const std::string& job_pool, bool stdPipesUTF8)
 {
   std::vector<std::string> no_byproducts;
   cmImplicitDependsList no_implicit_depends;
   return this->AddCustomCommandToOutput(
     { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
-    commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
-    command_expand_lists, depfile, job_pool, stdPipesUTF8);
+    commandLines, comment, workingDir, cmp0116, replace, escapeOldStyle,
+    uses_terminal, command_expand_lists, depfile, job_pool, stdPipesUTF8);
 }
 
 cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
@@ -1096,9 +1099,9 @@ cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
   const std::vector<std::string>& depends, const std::string& main_dependency,
   const cmImplicitDependsList& implicit_depends,
   const cmCustomCommandLines& commandLines, const char* comment,
-  const char* workingDir, bool replace, bool escapeOldStyle,
-  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
-  const std::string& job_pool, bool stdPipesUTF8)
+  const char* workingDir, cmPolicies::PolicyStatus cmp0116, bool replace,
+  bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+  const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8)
 {
   // Make sure there is at least one output.
   if (outputs.empty()) {
@@ -1110,16 +1113,16 @@ cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
     *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, outputs,
     byproducts, depends, main_dependency, implicit_depends, commandLines,
     comment, workingDir, replace, escapeOldStyle, uses_terminal,
-    command_expand_lists, depfile, job_pool, stdPipesUTF8);
+    command_expand_lists, depfile, job_pool, stdPipesUTF8, cmp0116);
 }
 
 cmTarget* cmLocalGenerator::AddUtilityCommand(
   const std::string& utilityName, bool excludeFromAll, const char* workingDir,
   const std::vector<std::string>& byproducts,
   const std::vector<std::string>& depends,
-  const cmCustomCommandLines& commandLines, bool escapeOldStyle,
-  const char* comment, bool uses_terminal, bool command_expand_lists,
-  const std::string& job_pool, bool stdPipesUTF8)
+  const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+  bool escapeOldStyle, const char* comment, bool uses_terminal,
+  bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8)
 {
   cmTarget* target =
     this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll);
@@ -1131,9 +1134,8 @@ cmTarget* cmLocalGenerator::AddUtilityCommand(
 
   detail::AddUtilityCommand(
     *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target,
-    this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends,
-    commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
-    job_pool, stdPipesUTF8);
+    workingDir, byproducts, depends, commandLines, escapeOldStyle, comment,
+    uses_terminal, command_expand_lists, job_pool, stdPipesUTF8, cmp0116);
 
   return target;
 }
@@ -1856,17 +1858,12 @@ bool cmLocalGenerator::AllAppleArchSysrootsAreTheSame(
     return false;
   }
 
-  for (std::string const& arch : archs) {
-    std::string const& archSysroot = this->AppleArchSysroots[arch];
-    if (cmIsOff(archSysroot)) {
-      continue;
-    }
-    if (archSysroot != sysroot) {
-      return false;
-    }
-  }
-
-  return true;
+  return std::all_of(archs.begin(), archs.end(),
+                     [this, &sysroot](std::string const& arch) -> bool {
+                       std::string const& archSysroot =
+                         this->AppleArchSysroots[arch];
+                       return cmIsOff(archSysroot) || archSysroot == sysroot;
+                     });
 }
 
 void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
@@ -2500,8 +2497,10 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
     target->GetSourceFiles(sources, config);
 
     const std::string configUpper = cmSystemTools::UpperCase(config);
+    static const std::array<std::string, 4> langs = { { "C", "CXX", "OBJC",
+                                                        "OBJCXX" } };
 
-    for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
+    for (const std::string& lang : langs) {
       auto langSources = std::count_if(
         sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
           return lang == sf->GetLanguage() &&
@@ -2554,7 +2553,7 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
         cmProp ReuseFrom =
           target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
 
-        auto pch_sf = this->Makefile->GetOrCreateSource(
+        auto* pch_sf = this->Makefile->GetOrCreateSource(
           pchSource, false, cmSourceFileLocationKind::Known);
 
         if (!this->GetGlobalGenerator()->IsXcode()) {
@@ -2571,7 +2570,7 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
                 "OBJECT_OUTPUTS",
                 cmStrCat("$<$<CONFIG:", config, ">:", pchFile, ">"));
             } else {
-              auto reuseTarget =
+              auto* reuseTarget =
                 this->GlobalGenerator->FindGeneratorTarget(*ReuseFrom);
 
               if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
@@ -2608,24 +2607,33 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
                 }
 
                 if (editAndContinueDebugInfo || msvc2008OrLess) {
-                  CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget,
-                                    { ".pdb", ".idb" });
+                  this->CopyPchCompilePdb(config, target, *ReuseFrom,
+                                          reuseTarget, { ".pdb", ".idb" });
                 } else if (enableDebuggingInformation) {
-                  CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget,
-                                    { ".pdb" });
+                  this->CopyPchCompilePdb(config, target, *ReuseFrom,
+                                          reuseTarget, { ".pdb" });
                 }
               }
 
-              if (reuseTarget->GetType() != cmStateEnums::OBJECT_LIBRARY) {
-                std::string pchSourceObj =
-                  reuseTarget->GetPchFileObject(config, lang, arch);
+              // Link to the pch object file
+              std::string pchSourceObj =
+                reuseTarget->GetPchFileObject(config, lang, arch);
 
-                // Link to the pch object file
+              if (target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+                std::string linkerProperty = "LINK_FLAGS_";
+                if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
+                  linkerProperty = "STATIC_LIBRARY_FLAGS_";
+                }
                 target->Target->AppendProperty(
-                  cmStrCat("LINK_FLAGS_", configUpper),
+                  cmStrCat(linkerProperty, configUpper),
                   cmStrCat(" ",
                            this->ConvertToOutputFormat(pchSourceObj, SHELL)),
                   true);
+              } else {
+                target->Target->AppendProperty(
+                  "INTERFACE_LINK_LIBRARIES",
+                  cmStrCat("$<$<CONFIG:", config,
+                           ">:$<LINK_ONLY:", pchSourceObj, ">>"));
               }
             }
           } else {
@@ -2634,15 +2642,17 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
 
           // Add pchHeader to source files, which will
           // be grouped as "Precompile Header File"
-          auto pchHeader_sf = this->Makefile->GetOrCreateSource(
-            pchHeader, true, cmSourceFileLocationKind::Known);
+          auto* pchHeader_sf = this->Makefile->GetOrCreateSource(
+            pchHeader, false, cmSourceFileLocationKind::Known);
           std::string err;
           pchHeader_sf->ResolveFullPath(&err);
-
-          // The pch file is generated, but mark it as not generated
-          // so that a clean operation will not remove it from disk
-          pchHeader_sf->SetProperty("GENERATED", "0");
-
+          if (!err.empty()) {
+            std::ostringstream msg;
+            msg << "Unable to resolve full path of PCH-header '" << pchHeader
+                << "' assigned to target " << target->GetName()
+                << ", although its path is supposed to be known!";
+            this->IssueMessage(MessageType::FATAL_ERROR, msg.str());
+          }
           target->AddSource(pchHeader);
         }
       }
@@ -2732,6 +2742,7 @@ void cmLocalGenerator::CopyPchCompilePdb(
   const std::vector<std::string> no_deps;
   const char* no_message = "";
   const char* no_current_dir = nullptr;
+  const cmPolicies::PolicyStatus cmp0116_new = cmPolicies::NEW;
   std::vector<std::string> no_byproducts;
 
   std::vector<std::string> outputs;
@@ -2741,14 +2752,15 @@ void cmLocalGenerator::CopyPchCompilePdb(
   if (this->GetGlobalGenerator()->IsVisualStudio()) {
     this->AddCustomCommandToTarget(
       target->GetName(), outputs, no_deps, commandLines,
-      cmCustomCommandType::PRE_BUILD, no_message, no_current_dir, true, false,
-      "", "", false, cmObjectLibraryCommands::Reject, stdPipesUTF8);
+      cmCustomCommandType::PRE_BUILD, no_message, no_current_dir, cmp0116_new,
+      true, false, "", "", false, cmObjectLibraryCommands::Accept,
+      stdPipesUTF8);
   } else {
     cmImplicitDependsList no_implicit_depends;
     cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
       outputs, no_byproducts, no_deps, no_main_dependency, no_implicit_depends,
-      commandLines, no_message, no_current_dir, false, true, false, false, "",
-      "", stdPipesUTF8);
+      commandLines, no_message, no_current_dir, cmp0116_new, false, true,
+      false, false, "", "", stdPipesUTF8);
 
     if (copy_rule) {
       target->AddSource(copy_rule->ResolveFullPath());
@@ -2767,12 +2779,34 @@ inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf,
   target->AddSourceFileToUnityBatch(sf->ResolveFullPath());
   sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str());
 }
+}
 
-inline void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file,
-                                      std::string const& sf_full_path,
-                                      cmProp beforeInclude,
-                                      cmProp afterInclude)
+void cmLocalGenerator::IncludeFileInUnitySources(
+  cmGeneratedFileStream& unity_file, std::string const& sf_full_path,
+  cmProp beforeInclude, cmProp afterInclude, cmProp uniqueIdName) const
 {
+  if (uniqueIdName && !uniqueIdName->empty()) {
+    std::string pathToHash;
+    auto PathEqOrSubDir = [](std::string const& a, std::string const& b) {
+      return (cmSystemTools::ComparePath(a, b) ||
+              cmSystemTools::IsSubDirectory(a, b));
+    };
+    const auto path = cmSystemTools::GetFilenamePath(sf_full_path);
+    if (PathEqOrSubDir(path, this->GetBinaryDirectory())) {
+      pathToHash = "BLD_" +
+        cmSystemTools::RelativePath(this->GetBinaryDirectory(), sf_full_path);
+    } else if (PathEqOrSubDir(path, this->GetSourceDirectory())) {
+      pathToHash = "SRC_" +
+        cmSystemTools::RelativePath(this->GetSourceDirectory(), sf_full_path);
+    } else {
+      pathToHash = "ABS_" + sf_full_path;
+    }
+    unity_file << "/* " << pathToHash << " */\n"
+               << "#undef " << *uniqueIdName << "\n"
+               << "#define " << *uniqueIdName << " unity_"
+               << cmSystemTools::ComputeStringMD5(pathToHash) << "\n";
+  }
+
   if (beforeInclude) {
     unity_file << *beforeInclude << "\n";
   }
@@ -2782,9 +2816,10 @@ inline void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file,
   if (afterInclude) {
     unity_file << *afterInclude << "\n";
   }
+  unity_file << "\n";
 }
 
-std::vector<std::string> AddUnityFilesModeAuto(
+std::vector<std::string> cmLocalGenerator::AddUnityFilesModeAuto(
   cmGeneratorTarget* target, std::string const& lang,
   std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
   cmProp afterInclude, std::string const& filename_base, size_t batchSize)
@@ -2793,6 +2828,8 @@ std::vector<std::string> AddUnityFilesModeAuto(
     batchSize = filtered_sources.size();
   }
 
+  cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
+
   std::vector<std::string> unity_files;
   for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0;
        itemsLeft > 0; itemsLeft -= chunk, ++batch) {
@@ -2816,7 +2853,7 @@ std::vector<std::string> AddUnityFilesModeAuto(
         cmSourceFile* sf = filtered_sources[begin];
         RegisterUnitySources(target, sf, filename);
         IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude,
-                                  afterInclude);
+                                  afterInclude, uniqueIdName);
       }
     }
     cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
@@ -2825,7 +2862,7 @@ std::vector<std::string> AddUnityFilesModeAuto(
   return unity_files;
 }
 
-std::vector<std::string> AddUnityFilesModeGroup(
+std::vector<std::string> cmLocalGenerator::AddUnityFilesModeGroup(
   cmGeneratorTarget* target, std::string const& lang,
   std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
   cmProp afterInclude, std::string const& filename_base)
@@ -2847,6 +2884,8 @@ std::vector<std::string> AddUnityFilesModeGroup(
     }
   }
 
+  cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
+
   for (auto const& item : explicit_mapping) {
     auto const& name = item.first;
     std::string filename = cmStrCat(filename_base, "unity_", name,
@@ -2862,7 +2901,7 @@ std::vector<std::string> AddUnityFilesModeGroup(
       for (cmSourceFile* sf : item.second) {
         RegisterUnitySources(target, sf, filename);
         IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude,
-                                  afterInclude);
+                                  afterInclude, uniqueIdName);
       }
     }
     cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
@@ -2871,7 +2910,6 @@ std::vector<std::string> AddUnityFilesModeGroup(
 
   return unity_files;
 }
-}
 
 void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
 {
@@ -2934,7 +2972,7 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
     }
 
     for (auto const& file : unity_files) {
-      auto unity = this->GetMakefile()->GetOrCreateSource(file);
+      auto* unity = this->GetMakefile()->GetOrCreateSource(file);
       target->AddSource(file, true);
       unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON");
       unity->SetProperty("UNITY_SOURCE_FILE", file.c_str());
@@ -3235,7 +3273,7 @@ std::string cmLocalGenerator::GetProjectName() const
 }
 
 std::string cmLocalGenerator::ConstructComment(
-  cmCustomCommandGenerator const& ccg, const char* default_comment)
+  cmCustomCommandGenerator const& ccg, const char* default_comment) const
 {
   // Check for a comment provided with the command.
   if (ccg.GetComment()) {
@@ -3551,11 +3589,11 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
   // we don't end up having:
   // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj
   cmProp unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
-  cmProp psExtension = source.GetProperty("PCH_EXTENSION");
+  cmProp pchExtension = source.GetProperty("PCH_EXTENSION");
   const bool isPchObject = objectName.find("cmake_pch") != std::string::npos;
-  if (unitySourceFile || psExtension || isPchObject) {
-    if (psExtension) {
-      customOutputExtension = psExtension->c_str();
+  if (unitySourceFile || pchExtension || isPchObject) {
+    if (pchExtension) {
+      customOutputExtension = pchExtension->c_str();
     }
 
     cmsys::RegularExpression var("(CMakeFiles/[^/]+.dir/)");
@@ -3793,7 +3831,7 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING");
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION");
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT");
-  mf->ConfigureFile(inFile, fname, false, false, false, true);
+  mf->ConfigureFile(inFile, fname, false, false, false);
 }
 
 void cmLocalGenerator::GenerateFrameworkInfoPList(
@@ -3828,49 +3866,107 @@ void cmLocalGenerator::GenerateFrameworkInfoPList(
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
-  mf->ConfigureFile(inFile, fname, false, false, false, true);
+  mf->ConfigureFile(inFile, fname, false, false, false);
 }
 
 namespace {
+cm::string_view CustomOutputRoleKeyword(cmLocalGenerator::OutputRole role)
+{
+  return (role == cmLocalGenerator::OutputRole::Primary ? "OUTPUT"_s
+                                                        : "BYPRODUCTS"_s);
+}
+
 void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
+                           cmLocalGenerator::OutputRole role,
                            cmCommandOrigin origin,
                            const cmListFileBacktrace& lfbt)
 {
-  if (cmGeneratorExpression::Find(output) == std::string::npos) {
-    // Outputs without generator expressions from the project are already
-    // created and marked as generated.  Do not mark them again, because
-    // other commands might have overwritten the property.
-    if (origin == cmCommandOrigin::Generator) {
-      lg.GetMakefile()->GetOrCreateGeneratedSource(output);
-    }
-  } else {
+  if (cmGeneratorExpression::Find(output) != std::string::npos) {
     lg.GetCMakeInstance()->IssueMessage(
       MessageType::FATAL_ERROR,
       "Generator expressions in custom command outputs are not implemented!",
       lfbt);
+    return;
+  }
+
+  // Make sure the file will not be generated into the source
+  // directory during an out of source build.
+  if (!lg.GetMakefile()->CanIWriteThisFile(output)) {
+    lg.GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat(CustomOutputRoleKeyword(role), " path\n  ", output,
+               "\nin a source directory as an output of custom command."),
+      lfbt);
+    return;
+  }
+
+  // Make sure the output file name has no invalid characters.
+  std::string::size_type pos = output.find_first_of("#<>");
+  if (pos != std::string::npos) {
+    lg.GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat(CustomOutputRoleKeyword(role), " containing a \"", output[pos],
+               "\" is not allowed."),
+      lfbt);
+    return;
+  }
+
+  // Outputs without generator expressions from the project are already
+  // created and marked as generated.  Do not mark them again, because
+  // other commands might have overwritten the property.
+  if (origin == cmCommandOrigin::Generator) {
+    lg.GetMakefile()->GetOrCreateGeneratedSource(output);
   }
 }
 
-void CreateGeneratedSources(cmLocalGenerator& lg,
-                            const std::vector<std::string>& outputs,
-                            cmCommandOrigin origin,
-                            const cmListFileBacktrace& lfbt)
+std::string ComputeCustomCommandRuleFileName(cmLocalGenerator& lg,
+                                             cmListFileBacktrace const& bt,
+                                             std::string const& output)
 {
-  for (std::string const& o : outputs) {
-    CreateGeneratedSource(lg, o, origin, lfbt);
+  // If the output path has no generator expressions, use it directly.
+  if (cmGeneratorExpression::Find(output) == std::string::npos) {
+    return output;
+  }
+
+  // The output path contains a generator expression, but we must choose
+  // a single source file path to which to attach the custom command.
+  // Use some heuristics to provie a nice-looking name when possible.
+
+  // If the only genex is $<CONFIG>, replace that gracefully.
+  {
+    std::string simple = output;
+    cmSystemTools::ReplaceString(simple, "$<CONFIG>", "(CONFIG)");
+    if (cmGeneratorExpression::Find(simple) == std::string::npos) {
+      return simple;
+    }
   }
+
+  // If the genex evaluates to the same value in all configurations, use that.
+  {
+    std::vector<std::string> allConfigOutputs =
+      lg.ExpandCustomCommandOutputGenex(output, bt);
+    if (allConfigOutputs.size() == 1) {
+      return allConfigOutputs.front();
+    }
+  }
+
+  // Fall back to a deterministic unique name.
+  cmCryptoHash h(cmCryptoHash::AlgoSHA256);
+  return cmStrCat(lg.GetCurrentBinaryDirectory(), "/CMakeFiles/",
+                  h.HashString(output).substr(0, 16));
 }
 
 cmSourceFile* AddCustomCommand(
   cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
-  const std::vector<std::string>& outputs,
+  cmCommandOrigin origin, const std::vector<std::string>& outputs,
   const std::vector<std::string>& byproducts,
   const std::vector<std::string>& depends, const std::string& main_dependency,
   const cmImplicitDependsList& implicit_depends,
   const cmCustomCommandLines& commandLines, const char* comment,
   const char* workingDir, bool replace, bool escapeOldStyle,
   bool uses_terminal, bool command_expand_lists, const std::string& depfile,
-  const std::string& job_pool, bool stdPipesUTF8)
+  const std::string& job_pool, bool stdPipesUTF8,
+  cmPolicies::PolicyStatus cmp0116)
 {
   cmMakefile* mf = lg.GetMakefile();
 
@@ -3900,7 +3996,8 @@ cmSourceFile* AddCustomCommand(
     cmGlobalGenerator* gg = lg.GetGlobalGenerator();
 
     // Construct a rule file associated with the first output produced.
-    std::string outName = gg->GenerateRuleFile(outputs[0]);
+    std::string outName = gg->GenerateRuleFile(
+      ComputeCustomCommandRuleFileName(lg, lfbt, outputs[0]));
 
     // Check if the rule file already exists.
     file = mf->GetSource(outName, cmSourceFileLocationKind::Known);
@@ -3941,12 +4038,38 @@ cmSourceFile* AddCustomCommand(
     cc->SetCommandExpandLists(command_expand_lists);
     cc->SetDepfile(depfile);
     cc->SetJobPool(job_pool);
+    cc->SetCMP0116Status(cmp0116);
     file->SetCustomCommand(std::move(cc));
 
-    mf->AddSourceOutputs(file, outputs, byproducts);
+    lg.AddSourceOutputs(file, outputs, cmLocalGenerator::OutputRole::Primary,
+                        lfbt, origin);
+    lg.AddSourceOutputs(file, byproducts,
+                        cmLocalGenerator::OutputRole::Byproduct, lfbt, origin);
   }
   return file;
 }
+
+bool AnyOutputMatches(const std::string& name,
+                      const std::vector<std::string>& outputs)
+{
+  return std::any_of(outputs.begin(), outputs.end(),
+                     [&name](std::string const& output) -> bool {
+                       std::string::size_type pos = output.rfind(name);
+                       // If the output matches exactly
+                       return (pos != std::string::npos &&
+                               pos == output.size() - name.size() &&
+                               (pos == 0 || output[pos - 1] == '/'));
+                     });
+}
+
+bool AnyTargetCommandOutputMatches(
+  const std::string& name, const std::vector<cmCustomCommand>& commands)
+{
+  return std::any_of(commands.begin(), commands.end(),
+                     [&name](cmCustomCommand const& command) -> bool {
+                       return AnyOutputMatches(name, command.GetByproducts());
+                     });
+}
 }
 
 namespace detail {
@@ -3960,13 +4083,9 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
                               const char* workingDir, bool escapeOldStyle,
                               bool uses_terminal, const std::string& depfile,
                               const std::string& job_pool,
-                              bool command_expand_lists, bool stdPipesUTF8)
+                              bool command_expand_lists, bool stdPipesUTF8,
+                              cmPolicies::PolicyStatus cmp0116)
 {
-  cmMakefile* mf = lg.GetMakefile();
-
-  // Always create the byproduct sources and mark them generated.
-  CreateGeneratedSources(lg, byproducts, origin, lfbt);
-
   // Add the command to the appropriate build step for the target.
   std::vector<std::string> no_output;
   cmCustomCommand cc(no_output, byproducts, depends, commandLines, lfbt,
@@ -3977,6 +4096,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
   cc.SetCommandExpandLists(command_expand_lists);
   cc.SetDepfile(depfile);
   cc.SetJobPool(job_pool);
+  cc.SetCMP0116Status(cmp0116);
   switch (type) {
     case cmCustomCommandType::PRE_BUILD:
       target->AddPreBuildCommand(std::move(cc));
@@ -3989,7 +4109,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
       break;
   }
 
-  mf->AddTargetByproducts(target, byproducts);
+  lg.AddTargetByproducts(target, byproducts, lfbt, origin);
 }
 
 cmSourceFile* AddCustomCommandToOutput(
@@ -4001,16 +4121,14 @@ cmSourceFile* AddCustomCommandToOutput(
   const cmCustomCommandLines& commandLines, const char* comment,
   const char* workingDir, bool replace, bool escapeOldStyle,
   bool uses_terminal, bool command_expand_lists, const std::string& depfile,
-  const std::string& job_pool, bool stdPipesUTF8)
+  const std::string& job_pool, bool stdPipesUTF8,
+  cmPolicies::PolicyStatus cmp0116)
 {
-  // Always create the output sources and mark them generated.
-  CreateGeneratedSources(lg, outputs, origin, lfbt);
-  CreateGeneratedSources(lg, byproducts, origin, lfbt);
-
-  return AddCustomCommand(
-    lg, lfbt, outputs, byproducts, depends, main_dependency, implicit_depends,
-    commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
-    command_expand_lists, depfile, job_pool, stdPipesUTF8);
+  return AddCustomCommand(lg, lfbt, origin, outputs, byproducts, depends,
+                          main_dependency, implicit_depends, commandLines,
+                          comment, workingDir, replace, escapeOldStyle,
+                          uses_terminal, command_expand_lists, depfile,
+                          job_pool, stdPipesUTF8, cmp0116);
 }
 
 void AppendCustomCommandToOutput(cmLocalGenerator& lg,
@@ -4021,7 +4139,22 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
                                  const cmCustomCommandLines& commandLines)
 {
   // Lookup an existing command.
-  if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) {
+  cmSourceFile* sf = nullptr;
+  if (cmGeneratorExpression::Find(output) == std::string::npos) {
+    sf = lg.GetSourceFileWithOutput(output);
+  } else {
+    // This output path has a generator expression.  Evaluate it to
+    // find the output for any configurations.
+    for (std::string const& out :
+         lg.ExpandCustomCommandOutputGenex(output, lfbt)) {
+      sf = lg.GetSourceFileWithOutput(out);
+      if (sf) {
+        break;
+      }
+    }
+  }
+
+  if (sf) {
     if (cmCustomCommand* cc = sf->GetCustomCommand()) {
       cc->AppendCommands(commandLines);
       cc->AppendDepends(depends);
@@ -4033,44 +4166,43 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
   // No existing command found.
   lg.GetCMakeInstance()->IssueMessage(
     MessageType::FATAL_ERROR,
-    cmStrCat("Attempt to append to output\n  ", output,
+    cmStrCat("Attempt to APPEND to custom command with output\n  ", output,
              "\nwhich is not already a custom command output."),
     lfbt);
 }
 
 void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
                        cmCommandOrigin origin, cmTarget* target,
-                       const cmUtilityOutput& force, const char* workingDir,
+                       const char* workingDir,
                        const std::vector<std::string>& byproducts,
                        const std::vector<std::string>& depends,
                        const cmCustomCommandLines& commandLines,
                        bool escapeOldStyle, const char* comment,
                        bool uses_terminal, bool command_expand_lists,
-                       const std::string& job_pool, bool stdPipesUTF8)
+                       const std::string& job_pool, bool stdPipesUTF8,
+                       cmPolicies::PolicyStatus cmp0116)
 {
-  // Always create the byproduct sources and mark them generated.
-  CreateGeneratedSource(lg, force.Name, origin, lfbt);
-  CreateGeneratedSources(lg, byproducts, origin, lfbt);
-
   // Use an empty comment to avoid generation of default comment.
   if (!comment) {
     comment = "";
   }
 
+  // Create the generated symbolic output name of the utility target.
+  std::string output =
+    lg.CreateUtilityOutput(target->GetName(), byproducts, lfbt);
+
   std::string no_main_dependency;
   cmImplicitDependsList no_implicit_depends;
   cmSourceFile* rule = AddCustomCommand(
-    lg, lfbt, { force.Name }, byproducts, depends, no_main_dependency,
+    lg, lfbt, origin, { output }, byproducts, depends, no_main_dependency,
     no_implicit_depends, commandLines, comment, workingDir,
     /*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists,
-    /*depfile=*/"", job_pool, stdPipesUTF8);
+    /*depfile=*/"", job_pool, stdPipesUTF8, cmp0116);
   if (rule) {
-    lg.GetMakefile()->AddTargetByproducts(target, byproducts);
+    lg.AddTargetByproducts(target, byproducts, lfbt, origin);
   }
 
-  if (!force.NameCMP0049.empty()) {
-    target->AddSource(force.NameCMP0049);
-  }
+  target->AddSource(output);
 }
 
 std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target)
@@ -4121,3 +4253,247 @@ std::vector<std::string> ComputeISPCExtraObjects(
   return computedObjects;
 }
 }
+
+cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput(
+  const std::string& name) const
+{
+  // Linear search?  Also see GetSourceFileWithOutput for detail.
+  if (!cmSystemTools::FileIsFullPath(name)) {
+    cmSourcesWithOutput sources;
+    sources.Target = this->LinearGetTargetWithOutput(name);
+    sources.Source = this->LinearGetSourceFileWithOutput(
+      name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
+    return sources;
+  }
+  // Otherwise we use an efficient lookup map.
+  auto o = this->OutputToSource.find(name);
+  if (o != this->OutputToSource.end()) {
+    return o->second.Sources;
+  }
+  return {};
+}
+
+cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput(
+  const std::string& name, cmSourceOutputKind kind) const
+{
+  // If the queried path is not absolute we use the backward compatible
+  // linear-time search for an output with a matching suffix.
+  if (!cmSystemTools::FileIsFullPath(name)) {
+    bool byproduct = false;
+    return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
+  }
+  // Otherwise we use an efficient lookup map.
+  auto o = this->OutputToSource.find(name);
+  if (o != this->OutputToSource.end() &&
+      (!o->second.Sources.SourceIsByproduct ||
+       kind == cmSourceOutputKind::OutputOrByproduct)) {
+    // Source file could also be null pointer for example if we found the
+    // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
+    // command of a target, or a not yet created custom command.
+    return o->second.Sources.Source;
+  }
+  return nullptr;
+}
+
+std::string cmLocalGenerator::CreateUtilityOutput(
+  std::string const& targetName, std::vector<std::string> const&,
+  cmListFileBacktrace const&)
+{
+  std::string force =
+    cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", targetName);
+  // The output is not actually created so mark it symbolic.
+  if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) {
+    sf->SetProperty("SYMBOLIC", "1");
+  } else {
+    cmSystemTools::Error("Could not get source file entry for " + force);
+  }
+  return force;
+}
+
+std::vector<cmCustomCommandGenerator>
+cmLocalGenerator::MakeCustomCommandGenerators(cmCustomCommand const& cc,
+                                              std::string const& config)
+{
+  std::vector<cmCustomCommandGenerator> ccgs;
+  ccgs.emplace_back(cc, config, this);
+  return ccgs;
+}
+
+std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths(
+  cmCompiledGeneratorExpression const& cge, std::string const& config)
+{
+  std::vector<std::string> paths = cmExpandedList(cge.Evaluate(this, config));
+  for (std::string& p : paths) {
+    p = cmSystemTools::CollapseFullPath(p, this->GetCurrentBinaryDirectory());
+  }
+  return paths;
+}
+
+std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex(
+  std::string const& o, cmListFileBacktrace const& bt)
+{
+  std::vector<std::string> allConfigOutputs;
+  cmGeneratorExpression ge(bt);
+  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o);
+  std::vector<std::string> configs =
+    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+  for (std::string const& config : configs) {
+    std::vector<std::string> configOutputs =
+      this->ExpandCustomCommandOutputPaths(*cge, config);
+    allConfigOutputs.reserve(allConfigOutputs.size() + configOutputs.size());
+    std::move(configOutputs.begin(), configOutputs.end(),
+              std::back_inserter(allConfigOutputs));
+  }
+  auto endUnique =
+    cmRemoveDuplicates(allConfigOutputs.begin(), allConfigOutputs.end());
+  allConfigOutputs.erase(endUnique, allConfigOutputs.end());
+  return allConfigOutputs;
+}
+
+void cmLocalGenerator::AddTargetByproducts(
+  cmTarget* target, const std::vector<std::string>& byproducts,
+  cmListFileBacktrace const& bt, cmCommandOrigin origin)
+{
+  for (std::string const& o : byproducts) {
+    if (cmGeneratorExpression::Find(o) == std::string::npos) {
+      this->UpdateOutputToSourceMap(o, target, bt, origin);
+      continue;
+    }
+
+    // This byproduct path has a generator expression.  Evaluate it to
+    // register the byproducts for all configurations.
+    for (std::string const& b : this->ExpandCustomCommandOutputGenex(o, bt)) {
+      this->UpdateOutputToSourceMap(b, target, bt, cmCommandOrigin::Generator);
+    }
+  }
+}
+
+void cmLocalGenerator::AddSourceOutputs(
+  cmSourceFile* source, const std::vector<std::string>& outputs,
+  OutputRole role, cmListFileBacktrace const& bt, cmCommandOrigin origin)
+{
+  for (std::string const& o : outputs) {
+    if (cmGeneratorExpression::Find(o) == std::string::npos) {
+      this->UpdateOutputToSourceMap(o, source, role, bt, origin);
+      continue;
+    }
+
+    // This output path has a generator expression.  Evaluate it to
+    // register the outputs for all configurations.
+    for (std::string const& out :
+         this->ExpandCustomCommandOutputGenex(o, bt)) {
+      this->UpdateOutputToSourceMap(out, source, role, bt,
+                                    cmCommandOrigin::Generator);
+    }
+  }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct,
+                                               cmTarget* target,
+                                               cmListFileBacktrace const& bt,
+                                               cmCommandOrigin origin)
+{
+  SourceEntry entry;
+  entry.Sources.Target = target;
+
+  auto pr = this->OutputToSource.emplace(byproduct, entry);
+  if (pr.second) {
+    CreateGeneratedSource(*this, byproduct, OutputRole::Byproduct, origin, bt);
+  } else {
+    SourceEntry& current = pr.first->second;
+    // Has the target already been set?
+    if (!current.Sources.Target) {
+      current.Sources.Target = target;
+    } else {
+      // Multiple custom commands/targets produce the same output (source file
+      // or target).  See also comment in other UpdateOutputToSourceMap
+      // overload.
+      //
+      // TODO: Warn the user about this case.
+    }
+  }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output,
+                                               cmSourceFile* source,
+                                               OutputRole role,
+                                               cmListFileBacktrace const& bt,
+                                               cmCommandOrigin origin)
+{
+  SourceEntry entry;
+  entry.Sources.Source = source;
+  entry.Sources.SourceIsByproduct = role == OutputRole::Byproduct;
+
+  auto pr = this->OutputToSource.emplace(output, entry);
+  if (pr.second) {
+    CreateGeneratedSource(*this, output, role, origin, bt);
+  } else {
+    SourceEntry& current = pr.first->second;
+    // Outputs take precedence over byproducts
+    if (!current.Sources.Source ||
+        (current.Sources.SourceIsByproduct && role == OutputRole::Primary)) {
+      current.Sources.Source = source;
+      current.Sources.SourceIsByproduct = false;
+    } else {
+      // Multiple custom commands produce the same output but may
+      // be attached to a different source file (MAIN_DEPENDENCY).
+      // LinearGetSourceFileWithOutput would return the first one,
+      // so keep the mapping for the first one.
+      //
+      // TODO: Warn the user about this case.  However, the VS 8 generator
+      // triggers it for separate generate.stamp rules in ZERO_CHECK and
+      // individual targets.
+    }
+  }
+}
+
+cmTarget* cmLocalGenerator::LinearGetTargetWithOutput(
+  const std::string& name) const
+{
+  // We go through the ordered vector of targets to get reproducible results
+  // should multiple names match.
+  for (cmTarget* t : this->Makefile->GetOrderedTargets()) {
+    // Does the output of any command match the source file name?
+    if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
+      return t;
+    }
+    if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
+      return t;
+    }
+    if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
+      return t;
+    }
+  }
+  return nullptr;
+}
+
+cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput(
+  const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
+{
+  // Outputs take precedence over byproducts.
+  byproduct = false;
+  cmSourceFile* fallback = nullptr;
+
+  // Look through all the source files that have custom commands and see if the
+  // custom command has the passed source file as an output.
+  for (const auto& src : this->Makefile->GetSourceFiles()) {
+    // Does this source file have a custom command?
+    if (src->GetCustomCommand()) {
+      // Does the output of the custom command match the source file name?
+      if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
+        // Return the first matching output.
+        return src.get();
+      }
+      if (kind == cmSourceOutputKind::OutputOrByproduct) {
+        if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
+          // Do not return the source yet as there might be a matching output.
+          fallback = src.get();
+        }
+      }
+    }
+  }
+
+  // Did we find a byproduct?
+  byproduct = fallback != nullptr;
+  return fallback;
+}
index 0fa8759..e48849a 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <cstddef>
 #include <iosfwd>
 #include <map>
 #include <memory>
 #include "cmProperty.h"
 #include "cmStateSnapshot.h"
 
+class cmCompiledGeneratorExpression;
 class cmComputeLinkInformation;
+class cmCustomCommand;
 class cmCustomCommandGenerator;
 class cmCustomCommandLines;
+class cmGeneratedFileStream;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
 class cmImplicitDependsList;
@@ -36,6 +40,31 @@ class cmState;
 class cmTarget;
 class cmake;
 
+/** Flag if byproducts shall also be considered.  */
+enum class cmSourceOutputKind
+{
+  OutputOnly,
+  OutputOrByproduct
+};
+
+/** What scanner to use for dependencies lookup.  */
+enum class cmDependencyScannerKind
+{
+  CMake,
+  Compiler
+};
+
+/** Target and source file which have a specific output.  */
+struct cmSourcesWithOutput
+{
+  /** Target with byproduct.  */
+  cmTarget* Target = nullptr;
+
+  /** Source file with output or byproduct.  */
+  cmSourceFile* Source = nullptr;
+  bool SourceIsByproduct = false;
+};
+
 /** \class cmLocalGenerator
  * \brief Create required build files for a directory.
  *
@@ -59,7 +88,7 @@ public:
   /**
    * Calls TraceVSDependencies() on all targets of this generator.
    */
-  void TraceDependencies();
+  void TraceDependencies() const;
 
   virtual void AddHelperCommands() {}
 
@@ -295,7 +324,8 @@ public:
     const std::string& target, const std::vector<std::string>& byproducts,
     const std::vector<std::string>& depends,
     const cmCustomCommandLines& commandLines, cmCustomCommandType type,
-    const char* comment, const char* workingDir, bool escapeOldStyle = true,
+    const char* comment, const char* workingDir,
+    cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle = true,
     bool uses_terminal = false, const std::string& depfile = "",
     const std::string& job_pool = "", bool command_expand_lists = false,
     cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject,
@@ -308,7 +338,8 @@ public:
     const std::string& output, const std::vector<std::string>& depends,
     const std::string& main_dependency,
     const cmCustomCommandLines& commandLines, const char* comment,
-    const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+    const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+    bool replace = false, bool escapeOldStyle = true,
     bool uses_terminal = false, bool command_expand_lists = false,
     const std::string& depfile = "", const std::string& job_pool = "",
     bool stdPipesUTF8 = false);
@@ -319,7 +350,8 @@ public:
     const std::string& main_dependency,
     const cmImplicitDependsList& implicit_depends,
     const cmCustomCommandLines& commandLines, const char* comment,
-    const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+    const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+    bool replace = false, bool escapeOldStyle = true,
     bool uses_terminal = false, bool command_expand_lists = false,
     const std::string& depfile = "", const std::string& job_pool = "",
     bool stdPipesUTF8 = false);
@@ -332,10 +364,59 @@ public:
     const std::string& utilityName, bool excludeFromAll,
     const char* workingDir, const std::vector<std::string>& byproducts,
     const std::vector<std::string>& depends,
-    const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
-    const char* comment = nullptr, bool uses_terminal = false,
-    bool command_expand_lists = false, const std::string& job_pool = "",
-    bool stdPipesUTF8 = false);
+    const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+    bool escapeOldStyle = true, const char* comment = nullptr,
+    bool uses_terminal = false, bool command_expand_lists = false,
+    const std::string& job_pool = "", bool stdPipesUTF8 = false);
+
+  virtual std::string CreateUtilityOutput(
+    std::string const& targetName, std::vector<std::string> const& byproducts,
+    cmListFileBacktrace const& bt);
+
+  virtual std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators(
+    cmCustomCommand const& cc, std::string const& config);
+
+  std::vector<std::string> ExpandCustomCommandOutputPaths(
+    cmCompiledGeneratorExpression const& cge, std::string const& config);
+  std::vector<std::string> ExpandCustomCommandOutputGenex(
+    std::string const& o, cmListFileBacktrace const& bt);
+
+  /**
+   * Add target byproducts.
+   */
+  void AddTargetByproducts(cmTarget* target,
+                           const std::vector<std::string>& byproducts,
+                           cmListFileBacktrace const& bt,
+                           cmCommandOrigin origin);
+
+  enum class OutputRole
+  {
+    Primary,
+    Byproduct,
+  };
+
+  /**
+   * Add source file outputs.
+   */
+  void AddSourceOutputs(cmSourceFile* source,
+                        std::vector<std::string> const& outputs,
+                        OutputRole role, cmListFileBacktrace const& bt,
+                        cmCommandOrigin origin);
+
+  /**
+   * Return the target if the provided source name is a byproduct of a utility
+   * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
+   * Return the source file which has the provided source name as output.
+   */
+  cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
+
+  /**
+   * Is there a source file that has the provided source name as an output?
+   * If so then return it.
+   */
+  cmSourceFile* GetSourceFileWithOutput(
+    const std::string& name,
+    cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
 
   std::string GetProjectName() const;
 
@@ -405,7 +486,7 @@ public:
                                   const std::string& fname);
   /** Construct a comment for a custom command.  */
   std::string ConstructComment(cmCustomCommandGenerator const& ccg,
-                               const char* default_comment = "");
+                               const char* default_comment = "") const;
   // Compute object file names.
   std::string GetObjectFileNameWithoutTarget(
     const cmSourceFile& source, std::string const& dir_max,
@@ -473,8 +554,7 @@ public:
   void CreateEvaluationFileOutputs(const std::string& config);
   void ProcessEvaluationFiles(std::vector<std::string>& generatedFiles);
 
-  const char* GetRuleLauncher(cmGeneratorTarget* target,
-                              const std::string& prop);
+  cmProp GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop);
 
 protected:
   //! put all the libraries for a target on into the given stream
@@ -534,6 +614,36 @@ protected:
   bool BackwardsCompatibilityFinal;
 
 private:
+  /**
+   * See LinearGetSourceFileWithOutput for background information
+   */
+  cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
+
+  /**
+   * Generalized old version of GetSourceFileWithOutput kept for
+   * backward-compatibility. It implements a linear search and supports
+   * relative file paths. It is used as a fall back by GetSourceFileWithOutput
+   * and GetSourcesWithOutput.
+   */
+  cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
+                                              cmSourceOutputKind kind,
+                                              bool& byproduct) const;
+  struct SourceEntry
+  {
+    cmSourcesWithOutput Sources;
+  };
+
+  // A map for fast output to input look up.
+  using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
+  OutputToSourceMap OutputToSource;
+
+  void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target,
+                               cmListFileBacktrace const& bt,
+                               cmCommandOrigin origin);
+  void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
+                               OutputRole role, cmListFileBacktrace const& bt,
+                               cmCommandOrigin origin);
+
   void AddSharedFlags(std::string& flags, const std::string& lang,
                       bool shared);
   bool GetShouldUseOldFlags(bool shared, const std::string& lang) const;
@@ -548,6 +658,18 @@ private:
                          const std::string& ReuseFrom,
                          cmGeneratorTarget* reuseTarget,
                          std::vector<std::string> const& extensions);
+  void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file,
+                                 std::string const& sf_full_path,
+                                 cmProp beforeInclude, cmProp afterInclude,
+                                 cmProp uniqueIdName) const;
+  std::vector<std::string> AddUnityFilesModeAuto(
+    cmGeneratorTarget* target, std::string const& lang,
+    std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
+    cmProp afterInclude, std::string const& filename_base, size_t batchSize);
+  std::vector<std::string> AddUnityFilesModeGroup(
+    cmGeneratorTarget* target, std::string const& lang,
+    std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude,
+    cmProp afterInclude, std::string const& filename_base);
 };
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -567,7 +689,8 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
                               const char* workingDir, bool escapeOldStyle,
                               bool uses_terminal, const std::string& depfile,
                               const std::string& job_pool,
-                              bool command_expand_lists, bool stdPipesUTF8);
+                              bool command_expand_lists, bool stdPipesUTF8,
+                              cmPolicies::PolicyStatus cmp0116);
 
 cmSourceFile* AddCustomCommandToOutput(
   cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
@@ -578,7 +701,8 @@ cmSourceFile* AddCustomCommandToOutput(
   const cmCustomCommandLines& commandLines, const char* comment,
   const char* workingDir, bool replace, bool escapeOldStyle,
   bool uses_terminal, bool command_expand_lists, const std::string& depfile,
-  const std::string& job_pool, bool stdPipesUTF8);
+  const std::string& job_pool, bool stdPipesUTF8,
+  cmPolicies::PolicyStatus cmp0116);
 
 void AppendCustomCommandToOutput(cmLocalGenerator& lg,
                                  const cmListFileBacktrace& lfbt,
@@ -589,13 +713,14 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
 
 void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
                        cmCommandOrigin origin, cmTarget* target,
-                       const cmUtilityOutput& force, const char* workingDir,
+                       const char* workingDir,
                        const std::vector<std::string>& byproducts,
                        const std::vector<std::string>& depends,
                        const cmCustomCommandLines& commandLines,
                        bool escapeOldStyle, const char* comment,
                        bool uses_terminal, bool command_expand_lists,
-                       const std::string& job_pool, bool stdPipesUTF8);
+                       const std::string& job_pool, bool stdPipesUTF8,
+                       cmPolicies::PolicyStatus cmp0116);
 
 std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target);
 std::vector<std::string> ComputeISPCExtraObjects(
index ad782ee..8ed411a 100644 (file)
@@ -10,6 +10,8 @@
 #include <sstream>
 #include <utility>
 
+#include <cmext/string_view>
+
 #include "cmsys/FStream.hxx"
 
 #include "cmCryptoHash.h"
@@ -22,7 +24,9 @@
 #include "cmGlobalNinjaGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
 #include "cmNinjaTargetGenerator.h"
+#include "cmPolicies.h"
 #include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
@@ -36,7 +40,6 @@
 cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg,
                                              cmMakefile* mf)
   : cmLocalCommonGenerator(gg, mf, mf->GetState()->GetBinaryDirectory())
-  , HomeRelativeOutputPath("")
 {
 }
 
@@ -553,9 +556,13 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines(
   std::string launcher = this->MakeCustomLauncher(ccg);
 
   for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) {
+    std::string c = ccg.GetCommand(i);
+    if (c.empty()) {
+      continue;
+    }
     cmdLines.push_back(launcher +
                        this->ConvertToOutputFormat(
-                         ccg.GetCommand(i),
+                         c,
                          gg->IsMultiConfig() ? cmOutputConverter::NINJAMULTI
                                              : cmOutputConverter::SHELL));
 
@@ -565,71 +572,252 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines(
 }
 
 void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
-  cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps,
-  const std::string& config)
+  cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets,
+  const std::string& fileConfig)
 {
   cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
-  if (gg->SeenCustomCommand(cc, config)) {
+  if (gg->SeenCustomCommand(cc, fileConfig)) {
     return;
   }
 
-  cmCustomCommandGenerator ccg(*cc, config, this);
+  auto ccgs = this->MakeCustomCommandGenerators(*cc, fileConfig);
+  for (cmCustomCommandGenerator const& ccg : ccgs) {
+    cmNinjaDeps orderOnlyDeps;
 
-  const std::vector<std::string>& outputs = ccg.GetOutputs();
-  const std::vector<std::string>& byproducts = ccg.GetByproducts();
-
-  bool symbolic = false;
-  for (std::string const& output : outputs) {
-    if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
-      if (sf->GetPropertyAsBool("SYMBOLIC")) {
-        symbolic = true;
-        break;
+    // A custom command may appear on multiple targets.  However, some build
+    // systems exist where the target dependencies on some of the targets are
+    // overspecified, leading to a dependency cycle.  If we assume all target
+    // dependencies are a superset of the true target dependencies for this
+    // custom command, we can take the set intersection of all target
+    // dependencies to obtain a correct dependency list.
+    //
+    // FIXME: This won't work in certain obscure scenarios involving indirect
+    // dependencies.
+    auto j = targets.begin();
+    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;
+      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;
+    }
+
+    const std::vector<std::string>& outputs = ccg.GetOutputs();
+    const std::vector<std::string>& byproducts = ccg.GetByproducts();
+
+    bool symbolic = false;
+    for (std::string const& output : outputs) {
+      if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
+        if (sf->GetPropertyAsBool("SYMBOLIC")) {
+          symbolic = true;
+          break;
+        }
+      }
+    }
+
+    cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size());
+    std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(),
+                   gg->MapToNinjaPath());
+    std::transform(byproducts.begin(), byproducts.end(),
+                   ninjaOutputs.begin() + outputs.size(),
+                   gg->MapToNinjaPath());
+
+    for (std::string const& ninjaOutput : ninjaOutputs) {
+      gg->SeenCustomCommandOutput(ninjaOutput);
+    }
+
+    cmNinjaDeps ninjaDeps;
+    this->AppendCustomCommandDeps(ccg, ninjaDeps, fileConfig);
+
+    std::vector<std::string> cmdLines;
+    this->AppendCustomCommandLines(ccg, cmdLines);
+
+    if (cmdLines.empty()) {
+      cmNinjaBuild build("phony");
+      build.Comment = "Phony custom command for " + ninjaOutputs[0];
+      build.Outputs = std::move(ninjaOutputs);
+      build.ExplicitDeps = std::move(ninjaDeps);
+      build.OrderOnlyDeps = orderOnlyDeps;
+      gg->WriteBuild(this->GetImplFileStream(fileConfig), build);
+    } else {
+      std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
+      // Hash full path to make unique.
+      customStep += '-';
+      cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+      customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
+
+      std::string depfile = cc->GetDepfile();
+      if (!depfile.empty()) {
+        switch (cc->GetCMP0116Status()) {
+          case cmPolicies::WARN:
+            if (this->GetCurrentBinaryDirectory() !=
+                  this->GetBinaryDirectory() ||
+                this->Makefile->PolicyOptionalWarningEnabled(
+                  "CMAKE_POLICY_WARNING_CMP0116")) {
+              this->GetCMakeInstance()->IssueMessage(
+                MessageType::AUTHOR_WARNING,
+                cmPolicies::GetPolicyWarning(cmPolicies::CMP0116),
+                cc->GetBacktrace());
+            }
+            CM_FALLTHROUGH;
+          case cmPolicies::OLD:
+            break;
+          case cmPolicies::REQUIRED_IF_USED:
+          case cmPolicies::REQUIRED_ALWAYS:
+          case cmPolicies::NEW:
+            cmSystemTools::MakeDirectory(
+              cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles/d"));
+            depfile = ccg.GetInternalDepfile();
+            break;
+        }
       }
+
+      gg->WriteCustomCommandBuild(
+        this->BuildCommandLine(cmdLines, customStep),
+        this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
+        depfile, cc->GetJobPool(), cc->GetUsesTerminal(),
+        /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, fileConfig,
+        ninjaDeps, orderOnlyDeps);
     }
   }
+}
 
-#if 0
-#  error TODO: Once CC in an ExternalProject target must provide the \
-    file of each imported target that has an add_dependencies pointing \
-    at us.  How to know which ExternalProject step actually provides it?
-#endif
-  cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size());
-  std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(),
-                 gg->MapToNinjaPath());
-  std::transform(byproducts.begin(), byproducts.end(),
-                 ninjaOutputs.begin() + outputs.size(), gg->MapToNinjaPath());
+bool cmLocalNinjaGenerator::HasUniqueByproducts(
+  std::vector<std::string> const& byproducts, cmListFileBacktrace const& bt)
+{
+  std::vector<std::string> configs =
+    this->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+  cmGeneratorExpression ge(bt);
+  for (std::string const& p : byproducts) {
+    if (cmGeneratorExpression::Find(p) == std::string::npos) {
+      return false;
+    }
+    std::set<std::string> seen;
+    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
+    for (std::string const& config : configs) {
+      for (std::string const& b :
+           this->ExpandCustomCommandOutputPaths(*cge, config)) {
+        if (!seen.insert(b).second) {
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
 
-  for (std::string const& ninjaOutput : ninjaOutputs) {
-    gg->SeenCustomCommandOutput(ninjaOutput);
+namespace {
+bool HasUniqueOutputs(std::vector<cmCustomCommandGenerator> const& ccgs)
+{
+  std::set<std::string> allOutputs;
+  std::set<std::string> allByproducts;
+  for (cmCustomCommandGenerator const& ccg : ccgs) {
+    for (std::string const& output : ccg.GetOutputs()) {
+      if (!allOutputs.insert(output).second) {
+        return false;
+      }
+    }
+    for (std::string const& byproduct : ccg.GetByproducts()) {
+      if (!allByproducts.insert(byproduct).second) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+}
+
+std::string cmLocalNinjaGenerator::CreateUtilityOutput(
+  std::string const& targetName, std::vector<std::string> const& byproducts,
+  cmListFileBacktrace const& bt)
+{
+  // In Ninja Multi-Config, we can only produce cross-config utility
+  // commands if all byproducts are per-config.
+  if (!this->GetGlobalGenerator()->IsMultiConfig() ||
+      !this->HasUniqueByproducts(byproducts, bt)) {
+    return this->cmLocalGenerator::CreateUtilityOutput(targetName, byproducts,
+                                                       bt);
+  }
+
+  std::string const base = cmStrCat(this->GetCurrentBinaryDirectory(),
+                                    "/CMakeFiles/", targetName, '-');
+  // The output is not actually created so mark it symbolic.
+  for (std::string const& config :
+       this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
+    std::string const force = cmStrCat(base, config);
+    if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) {
+      sf->SetProperty("SYMBOLIC", "1");
+    } else {
+      cmSystemTools::Error("Could not get source file entry for " + force);
+    }
   }
+  this->GetGlobalNinjaGenerator()->AddPerConfigUtilityTarget(targetName);
+  return cmStrCat(base, "$<CONFIG>"_s);
+}
+
+std::vector<cmCustomCommandGenerator>
+cmLocalNinjaGenerator::MakeCustomCommandGenerators(
+  cmCustomCommand const& cc, std::string const& fileConfig)
+{
+  cmGlobalNinjaGenerator const* gg = this->GetGlobalNinjaGenerator();
 
-  cmNinjaDeps ninjaDeps;
-  this->AppendCustomCommandDeps(ccg, ninjaDeps, config);
+  bool transformDepfile = false;
+  switch (cc.GetCMP0116Status()) {
+    case cmPolicies::OLD:
+    case cmPolicies::WARN:
+      break;
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::NEW:
+      transformDepfile = true;
+      break;
+  }
 
-  std::vector<std::string> cmdLines;
-  this->AppendCustomCommandLines(ccg, cmdLines);
+  // Start with the build graph's configuration.
+  std::vector<cmCustomCommandGenerator> ccgs;
+  ccgs.emplace_back(cc, fileConfig, this, transformDepfile);
 
-  if (cmdLines.empty()) {
-    cmNinjaBuild build("phony");
-    build.Comment = "Phony custom command for " + ninjaOutputs[0];
-    build.Outputs = std::move(ninjaOutputs);
-    build.ExplicitDeps = std::move(ninjaDeps);
-    build.OrderOnlyDeps = orderOnlyDeps;
-    gg->WriteBuild(this->GetImplFileStream(config), build);
-  } else {
-    std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
-    // Hash full path to make unique.
-    customStep += '-';
-    cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
-    customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
+  // Consider adding cross configurations.
+  if (!gg->EnableCrossConfigBuild()) {
+    return ccgs;
+  }
+
+  // Outputs and byproducts must be expressed using generator expressions.
+  for (std::string const& output : cc.GetOutputs()) {
+    if (cmGeneratorExpression::Find(output) == std::string::npos) {
+      return ccgs;
+    }
+  }
+  for (std::string const& byproduct : cc.GetByproducts()) {
+    if (cmGeneratorExpression::Find(byproduct) == std::string::npos) {
+      return ccgs;
+    }
+  }
 
-    gg->WriteCustomCommandBuild(
-      this->BuildCommandLine(cmdLines, customStep),
-      this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
-      cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(),
-      /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, config,
-      ninjaDeps, orderOnlyDeps);
+  // Tentatively add the other cross configurations.
+  for (std::string const& config : gg->GetCrossConfigs(fileConfig)) {
+    if (fileConfig != config) {
+      ccgs.emplace_back(cc, fileConfig, this, transformDepfile, config);
+    }
+  }
+
+  // If outputs and byproducts are not unique to each configuration,
+  // drop the cross configurations.
+  if (!HasUniqueOutputs(ccgs)) {
+    ccgs.erase(ccgs.begin() + 1, ccgs.end());
   }
+
+  return ccgs;
 }
 
 void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc,
@@ -645,42 +833,13 @@ void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc,
 }
 
 void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements(
-  const std::string& config)
+  const std::string& fileConfig)
 {
   for (cmCustomCommand const* customCommand : this->CustomCommands) {
     auto i = this->CustomCommandTargets.find(customCommand);
     assert(i != this->CustomCommandTargets.end());
 
-    // A custom command may appear on multiple targets.  However, some build
-    // systems exist where the target dependencies on some of the targets are
-    // overspecified, leading to a dependency cycle.  If we assume all target
-    // dependencies are a superset of the true target dependencies for this
-    // custom command, we can take the set intersection of all target
-    // dependencies to obtain a correct dependency list.
-    //
-    // FIXME: This won't work in certain obscure scenarios involving indirect
-    // dependencies.
-    auto j = i->second.begin();
-    assert(j != i->second.end());
-    std::vector<std::string> ccTargetDeps;
-    this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
-      *j, ccTargetDeps, config);
-    std::sort(ccTargetDeps.begin(), ccTargetDeps.end());
-    ++j;
-
-    for (; j != i->second.end(); ++j) {
-      std::vector<std::string> jDeps;
-      std::vector<std::string> depsIntersection;
-      this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps,
-                                                                  config);
-      std::sort(jDeps.begin(), jDeps.end());
-      std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(),
-                            jDeps.begin(), jDeps.end(),
-                            std::back_inserter(depsIntersection));
-      ccTargetDeps = depsIntersection;
-    }
-
-    this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps, config);
+    this->WriteCustomCommandBuildStatement(i->first, i->second, fileConfig);
   }
 }
 
index e81402c..5b850f3 100644 (file)
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "cmListFileCache.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmNinjaTypes.h"
 #include "cmOutputConverter.h"
@@ -70,6 +71,13 @@ public:
                            const std::string& fileConfig,
                            cmNinjaTargetDepends depends);
 
+  std::string CreateUtilityOutput(std::string const& targetName,
+                                  std::vector<std::string> const& byproducts,
+                                  cmListFileBacktrace const& bt) override;
+
+  std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators(
+    cmCustomCommand const& cc, std::string const& config) override;
+
   void AddCustomCommandTarget(cmCustomCommand const* cc,
                               cmGeneratorTarget* target);
   void AppendCustomCommandLines(cmCustomCommandGenerator const& ccg,
@@ -78,6 +86,9 @@ public:
                                cmNinjaDeps& ninjaDeps,
                                const std::string& config);
 
+  bool HasUniqueByproducts(std::vector<std::string> const& byproducts,
+                           cmListFileBacktrace const& bt);
+
 protected:
   std::string ConvertToIncludeReference(
     std::string const& path,
@@ -99,9 +110,9 @@ private:
   void WriteProcessedMakefile(std::ostream& os);
   void WritePools(std::ostream& os);
 
-  void WriteCustomCommandBuildStatement(cmCustomCommand const* cc,
-                                        const cmNinjaDeps& orderOnlyDeps,
-                                        const std::string& config);
+  void WriteCustomCommandBuildStatement(
+    cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets,
+    const std::string& config);
 
   void WriteCustomCommandBuildStatements(const std::string& config);
 
index c877cf8..464df68 100644 (file)
@@ -5,18 +5,23 @@
 #include <algorithm>
 #include <cassert>
 #include <cstdio>
+#include <functional>
 #include <sstream>
 #include <utility>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cm/vector>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/Terminal.h"
 
+#include "cmCMakePath.h"
 #include "cmCustomCommand.h" // IWYU pragma: keep
 #include "cmCustomCommandGenerator.h"
+#include "cmDependsCompiler.h"
 #include "cmFileTimeCache.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
@@ -50,8 +55,9 @@
 #  include "cmDependsJava.h"
 #endif
 
+namespace {
 // Helper function used below.
-static std::string cmSplitExtension(std::string const& in, std::string& base)
+std::string cmSplitExtension(std::string const& in, std::string& base)
 {
   std::string ext;
   std::string::size_type dot_pos = in.rfind('.');
@@ -65,6 +71,43 @@ static std::string cmSplitExtension(std::string const& in, std::string& base)
   return ext;
 }
 
+// Helper predicate for removing absolute paths that don't point to the
+// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
+// is set ON, to only consider in-project dependencies during the build.
+class NotInProjectDir
+{
+public:
+  // Constructor with the source and binary directory's path
+  NotInProjectDir(cm::string_view sourceDir, cm::string_view binaryDir)
+    : SourceDir(sourceDir)
+    , BinaryDir(binaryDir)
+  {
+  }
+
+  // Operator evaluating the predicate
+  bool operator()(const std::string& p) const
+  {
+    auto path = cmCMakePath(p).Normal();
+
+    // Keep all relative paths:
+    if (path.IsRelative()) {
+      return false;
+    }
+
+    // If it's an absolute path, check if it starts with the source
+    // directory:
+    return !(cmCMakePath(this->SourceDir).IsPrefix(path) ||
+             cmCMakePath(this->BinaryDir).IsPrefix(path));
+  }
+
+private:
+  // The path to the source directory
+  cm::string_view SourceDir;
+  // The path to the binary directory
+  cm::string_view BinaryDir;
+};
+}
+
 cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3(
   cmGlobalGenerator* gg, cmMakefile* mf)
   : cmLocalCommonGenerator(gg, mf, mf->GetCurrentBinaryDirectory())
@@ -108,8 +151,8 @@ void cmLocalUnixMakefileGenerator3::Generate()
     }
 
     auto& gtVisited = this->GetCommandsVisited(gt);
-    auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
-    for (auto& d : deps) {
+    const auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
+    for (const auto& d : deps) {
       // Take the union of visited source files of custom commands
       auto depVisited = this->GetCommandsVisited(d);
       gtVisited.insert(depVisited.begin(), depVisited.end());
@@ -552,8 +595,10 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule(
     }
   }
 
-  // Write the list of commands.
-  os << cmWrap("\t", commands, "", "\n") << "\n";
+  if (!commands.empty()) {
+    // Write the list of commands.
+    os << cmWrap("\t", commands, "", "\n") << "\n";
+  }
   if (symbolic && !this->IsWatcomWMake()) {
     os << ".PHONY : " << tgt << "\n";
   }
@@ -673,7 +718,7 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop(
     constexpr const char* vcs_rules[] = {
       "%,v", "RCS/%", "RCS/%,v", "SCCS/s.%", "s.%",
     };
-    for (auto vcs_rule : vcs_rules) {
+    for (const auto* vcs_rule : vcs_rules) {
       std::vector<std::string> vcs_depend;
       vcs_depend.emplace_back(vcs_rule);
       this->WriteMakeRule(makefileStream, "Disable VCS-based implicit rules.",
@@ -960,7 +1005,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
 
       std::string launcher;
       // Short-circuit if there is no launcher.
-      const char* val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
+      cmProp val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
       if (cmNonempty(val)) {
         // Expand rule variables referenced in the given launcher command.
         cmRulePlaceholderExpander::RuleVariables vars;
@@ -980,7 +1025,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
         }
         vars.Output = output.c_str();
 
-        launcher = val;
+        launcher = *val;
         rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars);
         if (!launcher.empty()) {
           launcher += " ";
@@ -1298,91 +1343,153 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
     cmSystemTools::Error("Target DependInfo.cmake file not found");
   }
 
+  bool status = true;
+
   // Check if any multiple output pairs have a missing file.
   this->CheckMultipleOutputs(verbose);
 
   std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo);
-  std::string const internalDependFile = targetDir + "/depend.internal";
-  std::string const dependFile = targetDir + "/depend.make";
-
-  // If the target DependInfo.cmake file has changed since the last
-  // time dependencies were scanned then force rescanning.  This may
-  // happen when a new source file is added and CMake regenerates the
-  // project but no other sources were touched.
-  bool needRescanDependInfo = false;
-  cmFileTimeCache* ftc =
-    this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
-  {
-    int result;
-    if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
-      if (verbose) {
-        cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo,
-                                       "\" is newer than depender \"",
-                                       internalDependFile, "\".\n"));
+  if (!this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) {
+    // dependencies are managed by CMake itself
+
+    std::string const internalDependFile = targetDir + "/depend.internal";
+    std::string const dependFile = targetDir + "/depend.make";
+
+    // If the target DependInfo.cmake file has changed since the last
+    // time dependencies were scanned then force rescanning.  This may
+    // happen when a new source file is added and CMake regenerates the
+    // project but no other sources were touched.
+    bool needRescanDependInfo = false;
+    cmFileTimeCache* ftc =
+      this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
+    {
+      int result;
+      if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
+        if (verbose) {
+          cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo,
+                                         "\" is newer than depender \"",
+                                         internalDependFile, "\".\n"));
+        }
+        needRescanDependInfo = true;
       }
-      needRescanDependInfo = true;
     }
-  }
 
-  // If the directory information is newer than depend.internal, include dirs
-  // may have changed. In this case discard all old dependencies.
-  bool needRescanDirInfo = false;
-  {
-    std::string dirInfoFile =
-      cmStrCat(this->GetCurrentBinaryDirectory(),
-               "/CMakeFiles/CMakeDirectoryInformation.cmake");
-    int result;
-    if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
-        result < 0) {
-      if (verbose) {
-        cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile,
-                                       "\" is newer than depender \"",
-                                       internalDependFile, "\".\n"));
+    // If the directory information is newer than depend.internal, include
+    // dirs may have changed. In this case discard all old dependencies.
+    bool needRescanDirInfo = false;
+    {
+      std::string dirInfoFile =
+        cmStrCat(this->GetCurrentBinaryDirectory(),
+                 "/CMakeFiles/CMakeDirectoryInformation.cmake");
+      int result;
+      if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
+          result < 0) {
+        if (verbose) {
+          cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile,
+                                         "\" is newer than depender \"",
+                                         internalDependFile, "\".\n"));
+        }
+        needRescanDirInfo = true;
       }
-      needRescanDirInfo = true;
+    }
+
+    // Check the implicit dependencies to see if they are up to date.
+    // The build.make file may have explicit dependencies for the object
+    // files but these will not affect the scanning process so they need
+    // not be considered.
+    cmDepends::DependencyMap validDependencies;
+    bool needRescanDependencies = false;
+    if (!needRescanDirInfo) {
+      cmDependsC checker;
+      checker.SetVerbose(verbose);
+      checker.SetFileTimeCache(ftc);
+      // cmDependsC::Check() fills the vector validDependencies() with the
+      // dependencies for those files where they are still valid, i.e.
+      // neither the files themselves nor any files they depend on have
+      // changed. We don't do that if the CMakeDirectoryInformation.cmake
+      // file has changed, because then potentially all dependencies have
+      // changed. This information is given later on to cmDependsC, which
+      // then only rescans the files where it did not get valid dependencies
+      // via this dependency vector. This means that in the normal case, when
+      // only few or one file have been edited, then also only this one file
+      // is actually scanned again, instead of all files for this target.
+      needRescanDependencies =
+        !checker.Check(dependFile, internalDependFile, validDependencies);
+    }
+
+    if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
+      // The dependencies must be regenerated.
+      std::string targetName = cmSystemTools::GetFilenameName(targetDir);
+      targetName = targetName.substr(0, targetName.length() - 4);
+      std::string message =
+        cmStrCat("Scanning dependencies of target ", targetName);
+      cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
+                                         cmsysTerminal_Color_ForegroundBold,
+                                       message.c_str(), true, color);
+
+      status = this->ScanDependencies(targetDir, dependFile,
+                                      internalDependFile, validDependencies);
     }
   }
 
-  // Check the implicit dependencies to see if they are up to date.
-  // The build.make file may have explicit dependencies for the object
-  // files but these will not affect the scanning process so they need
-  // not be considered.
-  cmDepends::DependencyMap validDependencies;
-  bool needRescanDependencies = false;
-  if (!needRescanDirInfo) {
-    cmDependsC checker;
-    checker.SetVerbose(verbose);
-    checker.SetFileTimeCache(ftc);
-    // cmDependsC::Check() fills the vector validDependencies() with the
-    // dependencies for those files where they are still valid, i.e. neither
-    // the files themselves nor any files they depend on have changed.
-    // We don't do that if the CMakeDirectoryInformation.cmake file has
-    // changed, because then potentially all dependencies have changed.
-    // This information is given later on to cmDependsC, which then only
-    // rescans the files where it did not get valid dependencies via this
-    // dependency vector. This means that in the normal case, when only
-    // few or one file have been edited, then also only this one file is
-    // actually scanned again, instead of all files for this target.
-    needRescanDependencies =
-      !checker.Check(dependFile, internalDependFile, validDependencies);
-  }
-
-  if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
-    // The dependencies must be regenerated.
-    std::string targetName = cmSystemTools::GetFilenameName(targetDir);
-    targetName = targetName.substr(0, targetName.length() - 4);
-    std::string message =
-      cmStrCat("Scanning dependencies of target ", targetName);
-    cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
-                                       cmsysTerminal_Color_ForegroundBold,
-                                     message.c_str(), true, color);
-
-    return this->ScanDependencies(targetDir, dependFile, internalDependFile,
-                                  validDependencies);
+  auto depends =
+    this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
+  if (!depends.empty()) {
+    // dependencies are managed by compiler
+    auto depFiles = cmExpandedList(depends, true);
+    std::string const internalDepFile =
+      targetDir + "/compiler_depend.internal";
+    std::string const depFile = targetDir + "/compiler_depend.make";
+    cmDepends::DependencyMap dependencies;
+    cmDependsCompiler depsManager;
+    bool projectOnly = cmIsOn(
+      this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_IN_PROJECT_ONLY"));
+
+    depsManager.SetVerbose(verbose);
+    depsManager.SetLocalGenerator(this);
+
+    if (!depsManager.CheckDependencies(
+          internalDepFile, depFiles, dependencies,
+          projectOnly ? NotInProjectDir(this->GetSourceDirectory(),
+                                        this->GetBinaryDirectory())
+                      : std::function<bool(const std::string&)>())) {
+      // regenerate dependencies files
+      std::string targetName =
+        cmCMakePath(targetDir).GetFileName().RemoveExtension().GenericString();
+      auto message = cmStrCat(
+        "Consolidate compiler generated dependencies of target ", targetName);
+      cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
+                                         cmsysTerminal_Color_ForegroundBold,
+                                       message.c_str(), true, color);
+
+      // Open the make depends file.  This should be copy-if-different
+      // because the make tool may try to reload it needlessly otherwise.
+      cmGeneratedFileStream ruleFileStream(
+        depFile, false, this->GlobalGenerator->GetMakefileEncoding());
+      ruleFileStream.SetCopyIfDifferent(true);
+      if (!ruleFileStream) {
+        return false;
+      }
+
+      // Open the cmake dependency tracking file.  This should not be
+      // copy-if-different because dependencies are re-scanned when it is
+      // older than the DependInfo.cmake.
+      cmGeneratedFileStream internalRuleFileStream(
+        internalDepFile, false, this->GlobalGenerator->GetMakefileEncoding());
+      if (!internalRuleFileStream) {
+        return false;
+      }
+
+      this->WriteDisclaimer(ruleFileStream);
+      this->WriteDisclaimer(internalRuleFileStream);
+
+      depsManager.WriteDependencies(dependencies, ruleFileStream,
+                                    internalRuleFileStream);
+    }
   }
 
   // The dependencies are already up-to-date.
-  return true;
+  return status;
 }
 
 bool cmLocalUnixMakefileGenerator3::ScanDependencies(
@@ -1721,178 +1828,207 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
   cmDepends clearer;
   clearer.SetVerbose(verbose);
   for (std::string const& file : files) {
-    std::string dir = cmSystemTools::GetFilenamePath(file);
+    auto snapshot = mf->GetState()->CreateBaseSnapshot();
+    cmMakefile lmf(mf->GetGlobalGenerator(), snapshot);
+    lmf.ReadListFile(file);
 
-    // Clear the implicit dependency makefile.
-    std::string dependFile = dir + "/depend.make";
-    clearer.Clear(dependFile);
+    if (!lmf.GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) {
+      std::string dir = cmSystemTools::GetFilenamePath(file);
 
-    // Remove the internal dependency check file to force
-    // regeneration.
-    std::string internalDependFile = dir + "/depend.internal";
-    cmSystemTools::RemoveFile(internalDependFile);
-  }
-}
-
-namespace {
-// Helper predicate for removing absolute paths that don't point to the
-// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
-// is set ON, to only consider in-project dependencies during the build.
-class NotInProjectDir
-{
-public:
-  // Constructor with the source and binary directory's path
-  NotInProjectDir(std::string sourceDir, std::string binaryDir)
-    : SourceDir(std::move(sourceDir))
-    , BinaryDir(std::move(binaryDir))
-  {
-  }
+      // Clear the implicit dependency makefile.
+      std::string dependFile = dir + "/depend.make";
+      clearer.Clear(dependFile);
 
-  // Operator evaluating the predicate
-  bool operator()(const std::string& path) const
-  {
-    // Keep all relative paths:
-    if (!cmSystemTools::FileIsFullPath(path)) {
-      return false;
+      // Remove the internal dependency check file to force
+      // regeneration.
+      std::string internalDependFile = dir + "/depend.internal";
+      cmSystemTools::RemoveFile(internalDependFile);
     }
-    // If it's an absolute path, check if it starts with the source
-    // directory:
-    return (
-      !(IsInDirectory(SourceDir, path) || IsInDirectory(BinaryDir, path)));
-  }
 
-private:
-  // Helper function used by the predicate
-  static bool IsInDirectory(const std::string& baseDir,
-                            const std::string& testDir)
-  {
-    // First check if the test directory "starts with" the base directory:
-    if (!cmHasPrefix(testDir, baseDir)) {
-      return false;
+    auto depsFiles = lmf.GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
+    if (!depsFiles.empty()) {
+      auto dir = cmCMakePath(file).GetParentPath();
+      // Clear the implicit dependency makefile.
+      auto depFile = cmCMakePath(dir).Append("compiler_depend.make");
+      clearer.Clear(depFile.GenericString());
+
+      // Remove the internal dependency check file
+      auto internalDepFile =
+        cmCMakePath(dir).Append("compiler_depend.internal");
+      cmSystemTools::RemoveFile(internalDepFile.GenericString());
+
+      // Touch timestamp file to force dependencies regeneration
+      auto DepTimestamp = cmCMakePath(dir).Append("compiler_depend.ts");
+      cmSystemTools::Touch(DepTimestamp.GenericString(), true);
+
+      // clear the dependencies files generated by the compiler
+      std::vector<std::string> dependencies = cmExpandedList(depsFiles);
+      cmDependsCompiler depsManager;
+      depsManager.SetVerbose(verbose);
+      depsManager.ClearDependencies(dependencies);
     }
-    // If it does, then check that it's either the same string, or that the
-    // next character is a slash:
-    return ((testDir.size() == baseDir.size()) ||
-            (testDir[baseDir.size()] == '/'));
   }
-
-  // The path to the source directory
-  std::string SourceDir;
-  // The path to the binary directory
-  std::string BinaryDir;
-};
 }
 
 void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
   std::ostream& cmakefileStream, cmGeneratorTarget* target)
 {
-  ImplicitDependLanguageMap const& implicitLangs =
-    this->GetImplicitDepends(target);
+  // To enable dependencies filtering
+  cmakefileStream << "\n"
+                  << "# Consider dependencies only in project.\n"
+                  << "set(CMAKE_DEPENDS_IN_PROJECT_ONLY "
+                  << (cmIsOn(this->Makefile->GetSafeDefinition(
+                        "CMAKE_DEPENDS_IN_PROJECT_ONLY"))
+                        ? "ON"
+                        : "OFF")
+                  << ")\n\n";
+
+  auto const& implicitLangs =
+    this->GetImplicitDepends(target, cmDependencyScannerKind::CMake);
 
   // list the languages
-  cmakefileStream
-    << "# The set of languages for which implicit dependencies are needed:\n";
+  cmakefileStream << "# The set of languages for which implicit "
+                     "dependencies are needed:\n";
   cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n";
   for (auto const& implicitLang : implicitLangs) {
     cmakefileStream << "  \"" << implicitLang.first << "\"\n";
   }
   cmakefileStream << "  )\n";
 
-  // now list the files for each language
-  cmakefileStream
-    << "# The set of files for implicit dependencies of each language:\n";
-  for (auto const& implicitLang : implicitLangs) {
-    cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << implicitLang.first
-                    << "\n";
-    ImplicitDependFileMap const& implicitPairs = implicitLang.second;
-
-    // for each file pair
-    for (auto const& implicitPair : implicitPairs) {
-      for (auto const& di : implicitPair.second) {
-        cmakefileStream << "  \"" << di << "\" ";
-        cmakefileStream << "\"" << implicitPair.first << "\"\n";
+  if (!implicitLangs.empty()) {
+    // now list the files for each language
+    cmakefileStream
+      << "# The set of files for implicit dependencies of each language:\n";
+    for (auto const& implicitLang : implicitLangs) {
+      const auto& lang = implicitLang.first;
+
+      cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << lang << "\n";
+      auto const& implicitPairs = implicitLang.second;
+
+      // for each file pair
+      for (auto const& implicitPair : implicitPairs) {
+        for (auto const& di : implicitPair.second) {
+          cmakefileStream << "  \"" << di << "\" ";
+          cmakefileStream << "\"" << implicitPair.first << "\"\n";
+        }
       }
-    }
-    cmakefileStream << "  )\n";
-
-    // Tell the dependency scanner what compiler is used.
-    std::string cidVar =
-      cmStrCat("CMAKE_", implicitLang.first, "_COMPILER_ID");
-    cmProp cid = this->Makefile->GetDefinition(cidVar);
-    if (cmNonempty(cid)) {
-      cmakefileStream << "set(CMAKE_" << implicitLang.first
-                      << "_COMPILER_ID \"" << *cid << "\")\n";
-    }
+      cmakefileStream << "  )\n";
 
-    if (implicitLang.first == "Fortran") {
-      std::string smodSep =
-        this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
-      std::string smodExt =
-        this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
-      cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep
-                      << "\")\n";
-      cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt
-                      << "\")\n";
-    }
+      // Tell the dependency scanner what compiler is used.
+      std::string cidVar = cmStrCat("CMAKE_", lang, "_COMPILER_ID");
+      cmProp cid = this->Makefile->GetDefinition(cidVar);
+      if (cmNonempty(cid)) {
+        cmakefileStream << "set(CMAKE_" << lang << "_COMPILER_ID \"" << *cid
+                        << "\")\n";
+      }
 
-    // Build a list of preprocessor definitions for the target.
-    std::set<std::string> defines;
-    this->GetTargetDefines(target, this->GetConfigName(), implicitLang.first,
-                           defines);
-    if (!defines.empty()) {
-      /* clang-format off */
+      if (lang == "Fortran") {
+        std::string smodSep =
+          this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
+        std::string smodExt =
+          this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
+        cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep
+                        << "\")\n";
+        cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt
+                        << "\")\n";
+      }
+
+      // Build a list of preprocessor definitions for the target.
+      std::set<std::string> defines;
+      this->GetTargetDefines(target, this->GetConfigName(), lang, defines);
+      if (!defines.empty()) {
+        /* clang-format off */
       cmakefileStream
         << "\n"
         << "# Preprocessor definitions for this target.\n"
-        << "set(CMAKE_TARGET_DEFINITIONS_" << implicitLang.first << "\n";
-      /* clang-format on */
-      for (std::string const& define : defines) {
-        cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(define)
-                        << "\n";
+        << "set(CMAKE_TARGET_DEFINITIONS_" << lang << "\n";
+        /* clang-format on */
+        for (std::string const& define : defines) {
+          cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(define)
+                          << "\n";
+        }
+        cmakefileStream << "  )\n";
+      }
+
+      // Target-specific include directories:
+      cmakefileStream << "\n"
+                      << "# The include file search paths:\n";
+      cmakefileStream << "set(CMAKE_" << lang << "_TARGET_INCLUDE_PATH\n";
+      std::vector<std::string> includes;
+
+      this->GetIncludeDirectories(includes, target, lang,
+                                  this->GetConfigName());
+      std::string const& binaryDir = this->GetState()->GetBinaryDirectory();
+      if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
+        std::string const& sourceDir = this->GetState()->GetSourceDirectory();
+        cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
+      }
+      for (std::string const& include : includes) {
+        cmakefileStream << "  \""
+                        << this->MaybeConvertToRelativePath(binaryDir, include)
+                        << "\"\n";
       }
       cmakefileStream << "  )\n";
     }
 
-    // Target-specific include directories:
-    cmakefileStream << "\n"
-                    << "# The include file search paths:\n";
-    cmakefileStream << "set(CMAKE_" << implicitLang.first
-                    << "_TARGET_INCLUDE_PATH\n";
-    std::vector<std::string> includes;
-
-    this->GetIncludeDirectories(includes, target, implicitLang.first,
-                                this->GetConfigName());
-    std::string binaryDir = this->GetState()->GetBinaryDirectory();
-    if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
-      std::string const& sourceDir = this->GetState()->GetSourceDirectory();
-      cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
+    // Store include transform rule properties.  Write the directory
+    // rules first because they may be overridden by later target rules.
+    std::vector<std::string> transformRules;
+    if (cmProp xform =
+          this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+      cmExpandList(*xform, transformRules);
     }
-    for (std::string const& include : includes) {
-      cmakefileStream << "  \""
-                      << this->MaybeConvertToRelativePath(binaryDir, include)
-                      << "\"\n";
+    if (cmProp xform =
+          target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
+      cmExpandList(*xform, transformRules);
+    }
+    if (!transformRules.empty()) {
+      cmakefileStream << "\nset(CMAKE_INCLUDE_TRANSFORMS\n";
+      for (std::string const& tr : transformRules) {
+        cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(tr)
+                        << "\n";
+      }
+      cmakefileStream << "  )\n";
     }
-    cmakefileStream << "  )\n";
   }
 
-  // Store include transform rule properties.  Write the directory
-  // rules first because they may be overridden by later target rules.
-  std::vector<std::string> transformRules;
-  if (cmProp xform =
-        this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
-    cmExpandList(*xform, transformRules);
-  }
-  if (cmProp xform =
-        target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
-    cmExpandList(*xform, transformRules);
-  }
-  if (!transformRules.empty()) {
-    cmakefileStream << "set(CMAKE_INCLUDE_TRANSFORMS\n";
-    for (std::string const& tr : transformRules) {
-      cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(tr) << "\n";
+  auto const& compilerLangs =
+    this->GetImplicitDepends(target, cmDependencyScannerKind::Compiler);
+
+  // list the dependency files managed by the compiler
+  cmakefileStream << "\n# The set of dependency files which are needed:\n";
+  cmakefileStream << "set(CMAKE_DEPENDS_DEPENDENCY_FILES\n";
+  for (auto const& compilerLang : compilerLangs) {
+    auto const& compilerPairs = compilerLang.second;
+    if (compilerLang.first == "CUSTOM"_s) {
+      for (auto const& compilerPair : compilerPairs) {
+        for (auto const& src : compilerPair.second) {
+          cmakefileStream << R"(  "" ")"
+                          << this->MaybeConvertToRelativePath(
+                               this->GetBinaryDirectory(), compilerPair.first)
+                          << R"(" "custom" ")"
+                          << this->MaybeConvertToRelativePath(
+                               this->GetBinaryDirectory(), src)
+                          << "\"\n";
+        }
+      }
+    } else {
+      auto depFormat = this->Makefile->GetSafeDefinition(
+        cmStrCat("CMAKE_", compilerLang.first, "_DEPFILE_FORMAT"));
+      for (auto const& compilerPair : compilerPairs) {
+        for (auto const& src : compilerPair.second) {
+          cmakefileStream << "  \"" << src << "\" \""
+                          << this->MaybeConvertToRelativePath(
+                               this->GetBinaryDirectory(), compilerPair.first)
+                          << "\" \"" << depFormat << "\" \""
+                          << this->MaybeConvertToRelativePath(
+                               this->GetBinaryDirectory(), compilerPair.first)
+                          << ".d\"\n";
+        }
+      }
     }
-    cmakefileStream << "  )\n";
   }
+  cmakefileStream << "  )\n";
 }
 
 void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
@@ -2049,16 +2185,18 @@ std::string cmLocalUnixMakefileGenerator3::GetTargetDirectory(
 }
 
 cmLocalUnixMakefileGenerator3::ImplicitDependLanguageMap const&
-cmLocalUnixMakefileGenerator3::GetImplicitDepends(const cmGeneratorTarget* tgt)
+cmLocalUnixMakefileGenerator3::GetImplicitDepends(
+  const cmGeneratorTarget* tgt, cmDependencyScannerKind scanner)
 {
-  return this->ImplicitDepends[tgt->GetName()];
+  return this->ImplicitDepends[tgt->GetName()][scanner];
 }
 
 void cmLocalUnixMakefileGenerator3::AddImplicitDepends(
   const cmGeneratorTarget* tgt, const std::string& lang,
-  const std::string& obj, const std::string& src)
+  const std::string& obj, const std::string& src,
+  cmDependencyScannerKind scanner)
 {
-  this->ImplicitDepends[tgt->GetName()][lang][obj].push_back(src);
+  this->ImplicitDepends[tgt->GetName()][scanner][lang][obj].push_back(src);
 }
 
 void cmLocalUnixMakefileGenerator3::CreateCDCommand(
index 8286d67..14dd0ba 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "cmDepends.h"
 #include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
 
 class cmCustomCommand;
 class cmCustomCommandGenerator;
@@ -152,23 +153,21 @@ public:
 
   // File pairs for implicit dependency scanning.  The key of the map
   // is the depender and the value is the explicit dependee.
-  struct ImplicitDependFileMap : public cmDepends::DependencyMap
-  {
-  };
-  struct ImplicitDependLanguageMap
-    : public std::map<std::string, ImplicitDependFileMap>
-  {
-  };
-  struct ImplicitDependTargetMap
-    : public std::map<std::string, ImplicitDependLanguageMap>
-  {
-  };
+  using ImplicitDependFileMap = cmDepends::DependencyMap;
+  using ImplicitDependLanguageMap =
+    std::map<std::string, ImplicitDependFileMap>;
+  using ImplicitDependScannerMap =
+    std::map<cmDependencyScannerKind, ImplicitDependLanguageMap>;
+  using ImplicitDependTargetMap =
+    std::map<std::string, ImplicitDependScannerMap>;
   ImplicitDependLanguageMap const& GetImplicitDepends(
-    cmGeneratorTarget const* tgt);
+    cmGeneratorTarget const* tgt,
+    cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake);
 
-  void AddImplicitDepends(cmGeneratorTarget const* tgt,
-                          const std::string& lang, const std::string& obj,
-                          const std::string& src);
+  void AddImplicitDepends(
+    cmGeneratorTarget const* tgt, const std::string& lang,
+    const std::string& obj, const std::string& src,
+    cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake);
 
   // write the target rules for the local Makefile into the stream
   void WriteLocalAllRules(std::ostream& ruleFileStream);
@@ -178,11 +177,11 @@ public:
   /** Get whether to create rules to generate preprocessed and
       assembly sources.  This could be converted to a variable lookup
       later.  */
-  bool GetCreatePreprocessedSourceRules()
+  bool GetCreatePreprocessedSourceRules() const
   {
     return !this->SkipPreprocessedSourceRules;
   }
-  bool GetCreateAssemblySourceRules()
+  bool GetCreateAssemblySourceRules() const
   {
     return !this->SkipAssemblySourceRules;
   }
index d2cdb99..a3940ea 100644 (file)
@@ -121,7 +121,7 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets()
       }
       if (cmSourceFile* file = this->AddCustomCommandToOutput(
             force, no_depends, no_main_dependency, force_commands, " ",
-            nullptr, true)) {
+            nullptr, cmPolicies::NEW, true)) {
         l->AddSource(file->ResolveFullPath());
       }
     }
@@ -245,9 +245,10 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
                               "--check-stamp-file", stampName });
   std::string comment = cmStrCat("Building Custom Rule ", makefileIn);
   const char* no_working_directory = nullptr;
-  this->AddCustomCommandToOutput(
-    stampName, listFiles, makefileIn, commandLines, comment.c_str(),
-    no_working_directory, true, false, false, false, "", "", stdPipesUTF8);
+  this->AddCustomCommandToOutput(stampName, listFiles, makefileIn,
+                                 commandLines, comment.c_str(),
+                                 no_working_directory, cmPolicies::NEW, true,
+                                 false, false, false, "", "", stdPipesUTF8);
   if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
     // Finalize the source file path now since we're adding this after
     // the generator validated all project-named sources.
@@ -1010,7 +1011,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
       this->GetStaticLibraryFlags(
         libflags, configName, target->GetLinkerLanguage(configName), target);
       if (!libflags.empty()) {
-        fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n";
+        fout << "\t\t\t\tAdditionalOptions=\"" << this->EscapeForXML(libflags)
+             << "\"\n";
       }
       fout << "\t\t\t\tOutputFile=\""
            << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n";
index 74c9435..8cf3765 100644 (file)
@@ -36,5 +36,5 @@ std::string cmMSVC60LinkLineComputer::ConvertToLinkReference(
   }
 #endif
 
-  return cmLinkLineComputer::ConvertToLinkReference(lib);
+  return this->cmLinkLineComputer::ConvertToLinkReference(lib);
 }
index be92c95..faa024b 100644 (file)
@@ -7,8 +7,8 @@
 #include <iosfwd>
 #include <string>
 
-#if !defined(CMAKE_USE_MACH_PARSER)
-#  error "This file may be included only if CMAKE_USE_MACH_PARSER is enabled."
+#if !defined(CMake_USE_MACH_PARSER)
+#  error "This file may be included only if CMake_USE_MACH_PARSER is enabled."
 #endif
 
 class cmMachOInternal;
index 98f88c1..8c4b2a7 100644 (file)
@@ -171,8 +171,11 @@ bool cmMacroFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
   f.Functions = std::move(functions);
   f.FilePath = this->GetStartingContext().FilePath;
   mf.RecordPolicies(f.Policies);
-  mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f));
-  return true;
+  return mf.GetState()->AddScriptedCommand(
+    this->Args[0],
+    BT<cmState::Command>(std::move(f),
+                         mf.GetBacktrace().Push(this->GetStartingContext())),
+    mf);
 }
 }
 
index 3946841..78cae0e 100644 (file)
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
-#include "cm_sys_stat.h"
-
 #include "cmCommandArgumentParserHelper.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmExecutionStatus.h"
 #include "cmExpandedCommandArgument.h" // IWYU pragma: keep
 #include "cmExportBuildFileGenerator.h"
-#include "cmFSPermissions.h"
 #include "cmFileLockPool.h"
 #include "cmFunctionBlocker.h"
 #include "cmGeneratedFileStream.h"
@@ -72,8 +69,6 @@
 
 class cmMessenger;
 
-using namespace cmFSPermissions;
-
 cmDirectoryId::cmDirectoryId(std::string s)
   : String(std::move(s))
 {
@@ -871,12 +866,13 @@ void cmMakefile::AddEvaluationFile(
   const std::string& inputFile, const std::string& targetName,
   std::unique_ptr<cmCompiledGeneratorExpression> outputName,
   std::unique_ptr<cmCompiledGeneratorExpression> condition,
-  bool inputIsContent)
+  const std::string& newLineCharacter, mode_t permissions, bool inputIsContent)
 {
   this->EvaluationFiles.push_back(
     cm::make_unique<cmGeneratorExpressionEvaluationFile>(
       inputFile, targetName, std::move(outputName), std::move(condition),
-      inputIsContent, this->GetPolicyStatus(cmPolicies::CMP0070)));
+      inputIsContent, newLineCharacter, permissions,
+      this->GetPolicyStatus(cmPolicies::CMP0070)));
 }
 
 const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
@@ -939,8 +935,6 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg)
     action.Value(lg, action.Backtrace);
   }
   this->GeneratorActionsInvoked = true;
-  this->DelayedOutputFiles.clear();
-  this->DelayedOutputFilesHaveGenex = false;
 
   // go through all configured files and see which ones still exist.
   // we don't want cmake to re-run if a configured file is created and deleted
@@ -984,7 +978,7 @@ struct BacktraceGuard
     this->Backtrace = std::move(current);
   }
 
-  ~BacktraceGuard() { this->Backtrace = std::move(Previous); }
+  ~BacktraceGuard() { this->Backtrace = std::move(this->Previous); }
 
 private:
   cmListFileBacktrace& Backtrace;
@@ -1091,8 +1085,9 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
   const std::string& target, const std::vector<std::string>& byproducts,
   const std::vector<std::string>& depends,
   const cmCustomCommandLines& commandLines, cmCustomCommandType type,
-  const char* comment, const char* workingDir, bool escapeOldStyle,
-  bool uses_terminal, const std::string& depfile, const std::string& job_pool,
+  const char* comment, const char* workingDir,
+  cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle, bool uses_terminal,
+  const std::string& depfile, const std::string& job_pool,
   bool command_expand_lists, bool stdPipesUTF8)
 {
   cmTarget* t = this->GetCustomCommandTarget(
@@ -1104,7 +1099,7 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
   }
 
   // Always create the byproduct sources and mark them generated.
-  this->CreateGeneratedByproducts(byproducts);
+  this->CreateGeneratedOutputs(byproducts);
 
   // Strings could be moved into the callback function with C++14.
   cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -1118,7 +1113,7 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
         lg, lfbt, cmCommandOrigin::Project, t, byproducts, depends,
         commandLines, type, GetCStrOrNull(commentStr),
         GetCStrOrNull(workingStr), escapeOldStyle, uses_terminal, depfile,
-        job_pool, command_expand_lists, stdPipesUTF8);
+        job_pool, command_expand_lists, stdPipesUTF8, cmp0116);
     });
 
   return t;
@@ -1128,16 +1123,18 @@ void cmMakefile::AddCustomCommandToOutput(
   const std::string& output, const std::vector<std::string>& depends,
   const std::string& main_dependency, const cmCustomCommandLines& commandLines,
   const char* comment, const char* workingDir,
-  const CommandSourceCallback& callback, bool replace, bool escapeOldStyle,
-  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  cmPolicies::PolicyStatus cmp0116, const CommandSourceCallback& callback,
+  bool replace, bool escapeOldStyle, bool uses_terminal,
+  bool command_expand_lists, const std::string& depfile,
   const std::string& job_pool, bool stdPipesUTF8)
 {
   std::vector<std::string> no_byproducts;
   cmImplicitDependsList no_implicit_depends;
   this->AddCustomCommandToOutput(
     { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
-    commandLines, comment, workingDir, callback, replace, escapeOldStyle,
-    uses_terminal, command_expand_lists, depfile, job_pool, stdPipesUTF8);
+    commandLines, comment, workingDir, cmp0116, callback, replace,
+    escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool,
+    stdPipesUTF8);
 }
 
 void cmMakefile::AddCustomCommandToOutput(
@@ -1146,9 +1143,10 @@ void cmMakefile::AddCustomCommandToOutput(
   const std::vector<std::string>& depends, const std::string& main_dependency,
   const cmImplicitDependsList& implicit_depends,
   const cmCustomCommandLines& commandLines, const char* comment,
-  const char* workingDir, const CommandSourceCallback& callback, bool replace,
-  bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
-  const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8)
+  const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+  const CommandSourceCallback& callback, bool replace, bool escapeOldStyle,
+  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  const std::string& job_pool, bool stdPipesUTF8)
 {
   // Make sure there is at least one output.
   if (outputs.empty()) {
@@ -1163,7 +1161,7 @@ void cmMakefile::AddCustomCommandToOutput(
 
   // Always create the output sources and mark them generated.
   this->CreateGeneratedOutputs(outputs);
-  this->CreateGeneratedByproducts(byproducts);
+  this->CreateGeneratedOutputs(byproducts);
 
   // Strings could be moved into the callback function with C++14.
   cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -1178,7 +1176,7 @@ void cmMakefile::AddCustomCommandToOutput(
         main_dependency, implicit_depends, commandLines,
         GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), replace,
         escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool,
-        stdPipesUTF8);
+        stdPipesUTF8, cmp0116);
       if (callback && sf) {
         callback(sf);
       }
@@ -1188,7 +1186,8 @@ void cmMakefile::AddCustomCommandToOutput(
 void cmMakefile::AddCustomCommandOldStyle(
   const std::string& target, const std::vector<std::string>& outputs,
   const std::vector<std::string>& depends, const std::string& source,
-  const cmCustomCommandLines& commandLines, const char* comment)
+  const cmCustomCommandLines& commandLines, const char* comment,
+  cmPolicies::PolicyStatus cmp0116)
 {
   // Translate the old-style signature to one of the new-style
   // signatures.
@@ -1199,7 +1198,7 @@ void cmMakefile::AddCustomCommandOldStyle(
     std::vector<std::string> no_byproducts;
     this->AddCustomCommandToTarget(
       target, no_byproducts, depends, commandLines,
-      cmCustomCommandType::POST_BUILD, comment, nullptr);
+      cmCustomCommandType::POST_BUILD, comment, nullptr, cmp0116);
     return;
   }
 
@@ -1222,16 +1221,18 @@ void cmMakefile::AddCustomCommandOldStyle(
   };
 
   // Each output must get its own copy of this rule.
-  cmsys::RegularExpression sourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|cu|m|mm|"
-                                       "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
-                                       "hm|hpp|hxx|in|txx|inl)$");
+  cmsys::RegularExpression sourceFiles(
+    "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|cu|m|mm|"
+    "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
+    "hm|hpp|hxx|in|txx|inl)$");
 
   // Choose whether to use a main dependency.
   if (sourceFiles.find(source)) {
     // The source looks like a real file.  Use it as the main dependency.
     for (std::string const& output : outputs) {
       this->AddCustomCommandToOutput(output, depends, source, commandLines,
-                                     comment, nullptr, addRuleFileToTarget);
+                                     comment, nullptr, cmp0116,
+                                     addRuleFileToTarget);
     }
   } else {
     std::string no_main_dependency;
@@ -1241,22 +1242,17 @@ void cmMakefile::AddCustomCommandOldStyle(
     // The source may not be a real file.  Do not use a main dependency.
     for (std::string const& output : outputs) {
       this->AddCustomCommandToOutput(output, depends2, no_main_dependency,
-                                     commandLines, comment, nullptr,
+                                     commandLines, comment, nullptr, cmp0116,
                                      addRuleFileToTarget);
     }
   }
 }
 
-bool cmMakefile::AppendCustomCommandToOutput(
+void cmMakefile::AppendCustomCommandToOutput(
   const std::string& output, const std::vector<std::string>& depends,
   const cmImplicitDependsList& implicit_depends,
   const cmCustomCommandLines& commandLines)
 {
-  // Check as good as we can if there will be a command for this output.
-  if (!this->MightHaveCustomCommand(output)) {
-    return false;
-  }
-
   // Validate custom commands.
   if (this->ValidateCustomCommand(commandLines)) {
     // Dispatch command creation to allow generator expressions in outputs.
@@ -1267,38 +1263,15 @@ bool cmMakefile::AppendCustomCommandToOutput(
                                             implicit_depends, commandLines);
       });
   }
-
-  return true;
-}
-
-cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
-{
-  std::string force = cmStrCat(this->GetCurrentBinaryDirectory(),
-                               "/CMakeFiles/", target->GetName());
-  std::string forceCMP0049 = target->GetSourceCMP0049(force);
-  {
-    cmSourceFile* sf = nullptr;
-    if (!forceCMP0049.empty()) {
-      sf = this->GetOrCreateSource(forceCMP0049, false,
-                                   cmSourceFileLocationKind::Known);
-    }
-    // The output is not actually created so mark it symbolic.
-    if (sf) {
-      sf->SetProperty("SYMBOLIC", "1");
-    } else {
-      cmSystemTools::Error("Could not get source file entry for " + force);
-    }
-  }
-  return { std::move(force), std::move(forceCMP0049) };
 }
 
 cmTarget* cmMakefile::AddUtilityCommand(
   const std::string& utilityName, bool excludeFromAll, const char* workingDir,
   const std::vector<std::string>& byproducts,
   const std::vector<std::string>& depends,
-  const cmCustomCommandLines& commandLines, bool escapeOldStyle,
-  const char* comment, bool uses_terminal, bool command_expand_lists,
-  const std::string& job_pool, bool stdPipesUTF8)
+  const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+  bool escapeOldStyle, const char* comment, bool uses_terminal,
+  bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8)
 {
   cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll);
 
@@ -1308,12 +1281,8 @@ cmTarget* cmMakefile::AddUtilityCommand(
     return target;
   }
 
-  // Get the output name of the utility target and mark it generated.
-  cmUtilityOutput force = this->GetUtilityOutput(target);
-  this->GetOrCreateGeneratedSource(force.Name);
-
   // Always create the byproduct sources and mark them generated.
-  this->CreateGeneratedByproducts(byproducts);
+  this->CreateGeneratedOutputs(byproducts);
 
   // Strings could be moved into the callback function with C++14.
   cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -1323,11 +1292,11 @@ cmTarget* cmMakefile::AddUtilityCommand(
   this->AddGeneratorAction(
     [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
       BacktraceGuard guard(this->Backtrace, lfbt);
-      detail::AddUtilityCommand(lg, lfbt, cmCommandOrigin::Project, target,
-                                force, GetCStrOrNull(workingStr), byproducts,
-                                depends, commandLines, escapeOldStyle,
-                                GetCStrOrNull(commentStr), uses_terminal,
-                                command_expand_lists, job_pool, stdPipesUTF8);
+      detail::AddUtilityCommand(
+        lg, lfbt, cmCommandOrigin::Project, target, GetCStrOrNull(workingStr),
+        byproducts, depends, commandLines, escapeOldStyle,
+        GetCStrOrNull(commentStr), uses_terminal, command_expand_lists,
+        job_pool, stdPipesUTF8, cmp0116);
     });
 
   return target;
@@ -1496,15 +1465,14 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
   // Include transform property.  There is no per-config version.
   {
     const char* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM";
-    cmProp p = parent->GetProperty(prop);
-    this->SetProperty(prop, cmToCStr(p));
+    this->SetProperty(prop, cmToCStr(parent->GetProperty(prop)));
   }
 
   // compile definitions property and per-config versions
   cmPolicies::PolicyStatus polSt = this->GetPolicyStatus(cmPolicies::CMP0043);
   if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
-    cmProp p = parent->GetProperty("COMPILE_DEFINITIONS");
-    this->SetProperty("COMPILE_DEFINITIONS", cmToCStr(p));
+    this->SetProperty("COMPILE_DEFINITIONS",
+                      cmToCStr(parent->GetProperty("COMPILE_DEFINITIONS")));
     std::vector<std::string> configs =
       this->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
     for (std::string const& config : configs) {
@@ -1516,12 +1484,11 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
   }
 
   // labels
-  cmProp p = parent->GetProperty("LABELS");
-  this->SetProperty("LABELS", cmToCStr(p));
+  this->SetProperty("LABELS", cmToCStr(parent->GetProperty("LABELS")));
 
   // link libraries
-  p = parent->GetProperty("LINK_LIBRARIES");
-  this->SetProperty("LINK_LIBRARIES", cmToCStr(p));
+  this->SetProperty("LINK_LIBRARIES",
+                    cmToCStr(parent->GetProperty("LINK_LIBRARIES")));
 
   // the initial project name
   this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
@@ -1863,7 +1830,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
 
   auto subMfu =
     cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot);
-  auto subMf = subMfu.get();
+  auto* subMf = subMfu.get();
   this->GetGlobalGenerator()->AddMakefile(std::move(subMfu));
 
   if (excludeFromAll) {
@@ -1877,7 +1844,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
   }
 
   this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>(
-    subMf, binPath, excludeFromAll));
+    subMf, binPath, excludeFromAll, this->GetBacktrace()));
 }
 
 const std::string& cmMakefile::GetCurrentSourceDirectory() const
@@ -2038,7 +2005,7 @@ void cmMakefile::RemoveDefinition(const std::string& name)
 #endif
 }
 
-void cmMakefile::RemoveCacheDefinition(const std::string& name)
+void cmMakefile::RemoveCacheDefinition(const std::string& name) const
 {
   this->GetState()->RemoveCacheEntry(name);
 }
@@ -2154,213 +2121,6 @@ cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
 }
 
 namespace {
-bool AnyOutputMatches(const std::string& name,
-                      const std::vector<std::string>& outputs)
-{
-  for (std::string const& output : outputs) {
-    std::string::size_type pos = output.rfind(name);
-    // If the output matches exactly
-    if (pos != std::string::npos && pos == output.size() - name.size() &&
-        (pos == 0 || output[pos - 1] == '/')) {
-      return true;
-    }
-  }
-  return false;
-}
-
-bool AnyTargetCommandOutputMatches(
-  const std::string& name, const std::vector<cmCustomCommand>& commands)
-{
-  for (cmCustomCommand const& command : commands) {
-    if (AnyOutputMatches(name, command.GetByproducts())) {
-      return true;
-    }
-  }
-  return false;
-}
-}
-
-cmTarget* cmMakefile::LinearGetTargetWithOutput(const std::string& name) const
-{
-  // We go through the ordered vector of targets to get reproducible results
-  // should multiple names match.
-  for (cmTarget* t : this->OrderedTargets) {
-    // Does the output of any command match the source file name?
-    if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
-      return t;
-    }
-    if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
-      return t;
-    }
-    if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
-      return t;
-    }
-  }
-  return nullptr;
-}
-
-cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput(
-  const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
-{
-  // Outputs take precedence over byproducts.
-  byproduct = false;
-  cmSourceFile* fallback = nullptr;
-
-  // Look through all the source files that have custom commands and see if the
-  // custom command has the passed source file as an output.
-  for (const auto& src : this->SourceFiles) {
-    // Does this source file have a custom command?
-    if (src->GetCustomCommand()) {
-      // Does the output of the custom command match the source file name?
-      if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
-        // Return the first matching output.
-        return src.get();
-      }
-      if (kind == cmSourceOutputKind::OutputOrByproduct) {
-        if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
-          // Do not return the source yet as there might be a matching output.
-          fallback = src.get();
-        }
-      }
-    }
-  }
-
-  // Did we find a byproduct?
-  byproduct = fallback != nullptr;
-  return fallback;
-}
-
-cmSourcesWithOutput cmMakefile::GetSourcesWithOutput(
-  const std::string& name) const
-{
-  // Linear search?  Also see GetSourceFileWithOutput for detail.
-  if (!cmSystemTools::FileIsFullPath(name)) {
-    cmSourcesWithOutput sources;
-    sources.Target = this->LinearGetTargetWithOutput(name);
-    sources.Source = this->LinearGetSourceFileWithOutput(
-      name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
-    return sources;
-  }
-  // Otherwise we use an efficient lookup map.
-  auto o = this->OutputToSource.find(name);
-  if (o != this->OutputToSource.end()) {
-    return o->second.Sources;
-  }
-  return {};
-}
-
-cmSourceFile* cmMakefile::GetSourceFileWithOutput(
-  const std::string& name, cmSourceOutputKind kind) const
-{
-  // If the queried path is not absolute we use the backward compatible
-  // linear-time search for an output with a matching suffix.
-  if (!cmSystemTools::FileIsFullPath(name)) {
-    bool byproduct = false;
-    return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
-  }
-  // Otherwise we use an efficient lookup map.
-  auto o = this->OutputToSource.find(name);
-  if (o != this->OutputToSource.end() &&
-      (!o->second.Sources.SourceIsByproduct ||
-       kind == cmSourceOutputKind::OutputOrByproduct)) {
-    // Source file could also be null pointer for example if we found the
-    // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
-    // command of a target, or a not yet created custom command.
-    return o->second.Sources.Source;
-  }
-  return nullptr;
-}
-
-bool cmMakefile::MightHaveCustomCommand(const std::string& name) const
-{
-  if (this->DelayedOutputFilesHaveGenex ||
-      cmGeneratorExpression::Find(name) != std::string::npos) {
-    // Could be more restrictive, but for now we assume that there could always
-    // be a match when generator expressions are involved.
-    return true;
-  }
-  // Also see LinearGetSourceFileWithOutput.
-  if (!cmSystemTools::FileIsFullPath(name)) {
-    return AnyOutputMatches(name, this->DelayedOutputFiles);
-  }
-  // Otherwise we use an efficient lookup map.
-  auto o = this->OutputToSource.find(name);
-  if (o != this->OutputToSource.end()) {
-    return o->second.SourceMightBeOutput;
-  }
-  return false;
-}
-
-void cmMakefile::AddTargetByproducts(
-  cmTarget* target, const std::vector<std::string>& byproducts)
-{
-  for (std::string const& o : byproducts) {
-    this->UpdateOutputToSourceMap(o, target);
-  }
-}
-
-void cmMakefile::AddSourceOutputs(cmSourceFile* source,
-                                  const std::vector<std::string>& outputs,
-                                  const std::vector<std::string>& byproducts)
-{
-  for (std::string const& o : outputs) {
-    this->UpdateOutputToSourceMap(o, source, false);
-  }
-  for (std::string const& o : byproducts) {
-    this->UpdateOutputToSourceMap(o, source, true);
-  }
-}
-
-void cmMakefile::UpdateOutputToSourceMap(std::string const& byproduct,
-                                         cmTarget* target)
-{
-  SourceEntry entry;
-  entry.Sources.Target = target;
-
-  auto pr = this->OutputToSource.emplace(byproduct, entry);
-  if (!pr.second) {
-    SourceEntry& current = pr.first->second;
-    // Has the target already been set?
-    if (!current.Sources.Target) {
-      current.Sources.Target = target;
-    } else {
-      // Multiple custom commands/targets produce the same output (source file
-      // or target).  See also comment in other UpdateOutputToSourceMap
-      // overload.
-      //
-      // TODO: Warn the user about this case.
-    }
-  }
-}
-
-void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
-                                         cmSourceFile* source, bool byproduct)
-{
-  SourceEntry entry;
-  entry.Sources.Source = source;
-  entry.Sources.SourceIsByproduct = byproduct;
-  entry.SourceMightBeOutput = !byproduct;
-
-  auto pr = this->OutputToSource.emplace(output, entry);
-  if (!pr.second) {
-    SourceEntry& current = pr.first->second;
-    // Outputs take precedence over byproducts
-    if (!current.Sources.Source ||
-        (current.Sources.SourceIsByproduct && !byproduct)) {
-      current.Sources.Source = source;
-      current.Sources.SourceIsByproduct = false;
-      current.SourceMightBeOutput = true;
-    } else {
-      // Multiple custom commands produce the same output but may
-      // be attached to a different source file (MAIN_DEPENDENCY).
-      // LinearGetSourceFileWithOutput would return the first one,
-      // so keep the mapping for the first one.
-      //
-      // TODO: Warn the user about this case.  However, the VS 8 generator
-      // triggers it for separate generate.stamp rules in ZERO_CHECK and
-      // individual targets.
-    }
-  }
 }
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -2685,7 +2445,7 @@ cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const
 
 bool cmMakefile::PlatformIsAppleEmbedded() const
 {
-  return GetAppleSDKType() != AppleSDK::MacOS;
+  return this->GetAppleSDKType() != AppleSDK::MacOS;
 }
 
 const char* cmMakefile::GetSONameFlag(const std::string& language) const
@@ -2696,7 +2456,7 @@ const char* cmMakefile::GetSONameFlag(const std::string& language) const
     name += language;
   }
   name += "_FLAG";
-  return cmToCStr(GetDefinition(name));
+  return cmToCStr(this->GetDefinition(name));
 }
 
 bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const
@@ -2719,7 +2479,7 @@ const std::string& cmMakefile::GetRequiredDefinition(
   const std::string& name) const
 {
   static std::string const empty;
-  const std::string* def = GetDefinition(name);
+  const std::string* def = this->GetDefinition(name);
   if (!def) {
     cmSystemTools::Error("Error required internal CMake variable not "
                          "set, cmake may not be built correctly.\n"
@@ -2779,7 +2539,7 @@ cmProp cmMakefile::GetDefinition(const std::string& name) const
 const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
 {
   static std::string const empty;
-  const std::string* def = GetDefinition(name);
+  const std::string* def = this->GetDefinition(name);
   if (!def) {
     return empty;
   }
@@ -2845,24 +2605,24 @@ const std::string& cmMakefile::ExpandVariablesInString(
       // Suppress variable watches to avoid calling hooks twice. Suppress new
       // dereferences since the OLD behavior is still what is actually used.
       this->SuppressSideEffects = true;
-      newError = ExpandVariablesInStringNew(newErrorstr, newResult,
-                                            escapeQuotes, noEscapes, atOnly,
-                                            filename, line, replaceAt);
+      newError = this->ExpandVariablesInStringNew(
+        newErrorstr, newResult, escapeQuotes, noEscapes, atOnly, filename,
+        line, replaceAt);
       this->SuppressSideEffects = false;
       CM_FALLTHROUGH;
     }
     case cmPolicies::OLD:
-      mtype =
-        ExpandVariablesInStringOld(errorstr, source, escapeQuotes, noEscapes,
-                                   atOnly, filename, line, removeEmpty, true);
+      mtype = this->ExpandVariablesInStringOld(errorstr, source, escapeQuotes,
+                                               noEscapes, atOnly, filename,
+                                               line, removeEmpty, true);
       break;
     case cmPolicies::REQUIRED_IF_USED:
     case cmPolicies::REQUIRED_ALWAYS:
     // Messaging here would be *very* verbose.
     case cmPolicies::NEW:
-      mtype =
-        ExpandVariablesInStringNew(errorstr, source, escapeQuotes, noEscapes,
-                                   atOnly, filename, line, replaceAt);
+      mtype = this->ExpandVariablesInStringNew(errorstr, source, escapeQuotes,
+                                               noEscapes, atOnly, filename,
+                                               line, replaceAt);
       break;
   }
 
@@ -3055,7 +2815,7 @@ void cmMakefile::SetRecursionDepth(int recursionDepth)
   this->RecursionDepth = recursionDepth;
 }
 
-std::string cmMakefile::NewDeferId()
+std::string cmMakefile::NewDeferId() const
 {
   return this->GetGlobalGenerator()->NewDeferId();
 }
@@ -3616,7 +3376,7 @@ cmSourceFile* cmMakefile::GetSource(const std::string& sourceName,
 #endif
   auto sfsi = this->SourceFileSearchIndex.find(name);
   if (sfsi != this->SourceFileSearchIndex.end()) {
-    for (auto sf : sfsi->second) {
+    for (auto* sf : sfsi->second) {
       if (sf->Matches(sfl)) {
         return sf;
       }
@@ -3629,11 +3389,7 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName,
                                        bool generated,
                                        cmSourceFileLocationKind kind)
 {
-  auto sf = cm::make_unique<cmSourceFile>(this, sourceName, kind);
-  if (generated) {
-    sf->SetProperty("GENERATED", "1");
-  }
-
+  auto sf = cm::make_unique<cmSourceFile>(this, sourceName, generated, kind);
   auto name =
     this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName());
 #if defined(_WIN32) || defined(__APPLE__)
@@ -3665,7 +3421,7 @@ cmSourceFile* cmMakefile::GetOrCreateGeneratedSource(
 {
   cmSourceFile* sf =
     this->GetOrCreateSource(sourceName, true, cmSourceFileLocationKind::Known);
-  sf->SetProperty("GENERATED", "1");
+  sf->MarkAsGenerated(); // In case we did not create the source file.
   return sf;
 }
 
@@ -3675,38 +3431,10 @@ void cmMakefile::CreateGeneratedOutputs(
   for (std::string const& o : outputs) {
     if (cmGeneratorExpression::Find(o) == std::string::npos) {
       this->GetOrCreateGeneratedSource(o);
-      this->AddDelayedOutput(o);
-    } else {
-      this->DelayedOutputFilesHaveGenex = true;
     }
   }
 }
 
-void cmMakefile::CreateGeneratedByproducts(
-  const std::vector<std::string>& byproducts)
-{
-  for (std::string const& o : byproducts) {
-    if (cmGeneratorExpression::Find(o) == std::string::npos) {
-      this->GetOrCreateGeneratedSource(o);
-    }
-  }
-}
-
-void cmMakefile::AddDelayedOutput(std::string const& output)
-{
-  // Note that this vector might contain the output names in a different order
-  // than in source file iteration order.
-  this->DelayedOutputFiles.push_back(output);
-
-  SourceEntry entry;
-  entry.SourceMightBeOutput = true;
-
-  auto pr = this->OutputToSource.emplace(output, entry);
-  if (!pr.second) {
-    pr.first->second.SourceMightBeOutput = true;
-  }
-}
-
 void cmMakefile::AddTargetObject(std::string const& tgtName,
                                  std::string const& objFile)
 {
@@ -4094,8 +3822,7 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output,
 int cmMakefile::ConfigureFile(const std::string& infile,
                               const std::string& outfile, bool copyonly,
                               bool atOnly, bool escapeQuotes,
-                              bool use_source_permissions,
-                              cmNewLineStyle newLine)
+                              mode_t permissions, cmNewLineStyle newLine)
 {
   int res = 1;
   if (!this->CanIWriteThisFile(outfile)) {
@@ -4117,12 +3844,8 @@ int cmMakefile::ConfigureFile(const std::string& infile,
   // output files that now don't exist.
   this->AddCMakeOutputFile(soutfile);
 
-  mode_t perm = 0;
-  if (!use_source_permissions) {
-    perm = perm | mode_owner_read | mode_owner_write | mode_group_read |
-      mode_world_read;
-  } else {
-    cmSystemTools::GetPermissions(sinfile, perm);
+  if (permissions == 0) {
+    cmSystemTools::GetPermissions(sinfile, permissions);
   }
 
   std::string::size_type pos = soutfile.rfind('/');
@@ -4137,7 +3860,7 @@ int cmMakefile::ConfigureFile(const std::string& infile,
                          cmSystemTools::GetLastSystemError());
       return 0;
     }
-    if (!cmSystemTools::SetPermissions(soutfile, perm)) {
+    if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
       this->IssueMessage(MessageType::FATAL_ERROR,
                          cmSystemTools::GetLastSystemError());
       return 0;
@@ -4194,7 +3917,7 @@ int cmMakefile::ConfigureFile(const std::string& infile,
                          cmSystemTools::GetLastSystemError());
       res = 0;
     } else {
-      if (!cmSystemTools::SetPermissions(soutfile, perm)) {
+      if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
         this->IssueMessage(MessageType::FATAL_ERROR,
                            cmSystemTools::GetLastSystemError());
         res = 0;
@@ -4283,7 +4006,7 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const
 }
 
 void cmMakefile::GetTests(const std::string& config,
-                          std::vector<cmTest*>& tests)
+                          std::vector<cmTest*>& tests) const
 {
   for (const auto& generator : this->GetTestGenerators()) {
     if (generator->TestsForConfig(config)) {
@@ -4633,7 +4356,7 @@ cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id,
   return this->StateSnapshot.GetPolicy(id, parent_scope);
 }
 
-bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var)
+bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const
 {
   // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting.
   if (cmProp val = this->GetDefinition(var)) {
@@ -4670,7 +4393,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
 
   // Deprecate old policies, especially those that require a lot
   // of code to maintain the old behavior.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0072 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0075 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4738,7 +4461,7 @@ bool cmMakefile::HasCMP0054AlreadyBeenReported(
   return !this->CMP0054ReportedIds.insert(context).second;
 }
 
-void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm)
+void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const
 {
   /* Record the setting of every policy.  */
   using PolicyID = cmPolicies::PolicyID;
index c7940fb..71d765c 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cm_sys_stat.h"
+
 #include "cmAlgorithms.h"
 #include "cmCustomCommandTypes.h"
 #include "cmListFileCache.h"
@@ -59,24 +61,6 @@ class cmTestGenerator;
 class cmVariableWatch;
 class cmake;
 
-/** Flag if byproducts shall also be considered.  */
-enum class cmSourceOutputKind
-{
-  OutputOnly,
-  OutputOrByproduct
-};
-
-/** Target and source file which have a specific output.  */
-struct cmSourcesWithOutput
-{
-  /** Target with byproduct.  */
-  cmTarget* Target = nullptr;
-
-  /** Source file with output or byproduct.  */
-  cmSourceFile* Source = nullptr;
-  bool SourceIsByproduct = false;
-};
-
 /** A type-safe wrapper for a string representing a directory id.  */
 class cmDirectoryId
 {
@@ -185,7 +169,8 @@ public:
     const std::string& target, const std::vector<std::string>& byproducts,
     const std::vector<std::string>& depends,
     const cmCustomCommandLines& commandLines, cmCustomCommandType type,
-    const char* comment, const char* workingDir, bool escapeOldStyle = true,
+    const char* comment, const char* workingDir,
+    cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle = true,
     bool uses_terminal = false, const std::string& depfile = "",
     const std::string& job_pool = "", bool command_expand_lists = false,
     bool stdPipesUTF8 = false);
@@ -202,11 +187,11 @@ public:
     const std::string& output, const std::vector<std::string>& depends,
     const std::string& main_dependency,
     const cmCustomCommandLines& commandLines, const char* comment,
-    const char* workingDir, const CommandSourceCallback& callback = nullptr,
-    bool replace = false, bool escapeOldStyle = true,
-    bool uses_terminal = false, bool command_expand_lists = false,
-    const std::string& depfile = "", const std::string& job_pool = "",
-    bool stdPipesUTF8 = false);
+    const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+    const CommandSourceCallback& callback = nullptr, bool replace = false,
+    bool escapeOldStyle = true, bool uses_terminal = false,
+    bool command_expand_lists = false, const std::string& depfile = "",
+    const std::string& job_pool = "", bool stdPipesUTF8 = false);
   void AddCustomCommandToOutput(
     const std::vector<std::string>& outputs,
     const std::vector<std::string>& byproducts,
@@ -214,36 +199,24 @@ public:
     const std::string& main_dependency,
     const cmImplicitDependsList& implicit_depends,
     const cmCustomCommandLines& commandLines, const char* comment,
-    const char* workingDir, const CommandSourceCallback& callback = nullptr,
-    bool replace = false, bool escapeOldStyle = true,
-    bool uses_terminal = false, bool command_expand_lists = false,
-    const std::string& depfile = "", const std::string& job_pool = "",
-    bool stdPipesUTF8 = false);
+    const char* workingDir, cmPolicies::PolicyStatus cmp0116,
+    const CommandSourceCallback& callback = nullptr, bool replace = false,
+    bool escapeOldStyle = true, bool uses_terminal = false,
+    bool command_expand_lists = false, const std::string& depfile = "",
+    const std::string& job_pool = "", bool stdPipesUTF8 = false);
   void AddCustomCommandOldStyle(const std::string& target,
                                 const std::vector<std::string>& outputs,
                                 const std::vector<std::string>& depends,
                                 const std::string& source,
                                 const cmCustomCommandLines& commandLines,
-                                const char* comment);
-  bool AppendCustomCommandToOutput(
+                                const char* comment,
+                                cmPolicies::PolicyStatus cmp0116);
+  void AppendCustomCommandToOutput(
     const std::string& output, const std::vector<std::string>& depends,
     const cmImplicitDependsList& implicit_depends,
     const cmCustomCommandLines& commandLines);
 
   /**
-   * Add target byproducts.
-   */
-  void AddTargetByproducts(cmTarget* target,
-                           const std::vector<std::string>& byproducts);
-
-  /**
-   * Add source file outputs.
-   */
-  void AddSourceOutputs(cmSourceFile* source,
-                        const std::vector<std::string>& outputs,
-                        const std::vector<std::string>& byproducts);
-
-  /**
    * Add a define flag to the build.
    */
   void AddDefineFlag(std::string const& definition);
@@ -272,11 +245,6 @@ public:
                           bool excludeFromAll = false);
 
   /**
-   * Return the utility target output source file name and the CMP0049 name.
-   */
-  cmUtilityOutput GetUtilityOutput(cmTarget* target);
-
-  /**
    * Dispatch adding a utility to the build.  A utility target is a command
    * that is run every time the target is built.
    */
@@ -284,10 +252,10 @@ public:
     const std::string& utilityName, bool excludeFromAll,
     const char* workingDir, const std::vector<std::string>& byproducts,
     const std::vector<std::string>& depends,
-    const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
-    const char* comment = nullptr, bool uses_terminal = false,
-    bool command_expand_lists = false, const std::string& job_pool = "",
-    bool stdPipesUTF8 = false);
+    const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116,
+    bool escapeOldStyle = true, const char* comment = nullptr,
+    bool uses_terminal = false, bool command_expand_lists = false,
+    const std::string& job_pool = "", bool stdPipesUTF8 = false);
 
   /**
    * Add a subdirectory to the build.
@@ -326,7 +294,7 @@ public:
                           const char* doc, cmStateEnums::CacheEntryType type,
                           bool force = false)
   {
-    AddCacheDefinition(name, value.c_str(), doc, type, force);
+    this->AddCacheDefinition(name, value.c_str(), doc, type, force);
   }
 
   /**
@@ -335,7 +303,7 @@ public:
    */
   void RemoveDefinition(const std::string& name);
   //! Remove a definition from the cache.
-  void RemoveCacheDefinition(const std::string& name);
+  void RemoveCacheDefinition(const std::string& name) const;
 
   /**
    * Specify the name of the project for this build.
@@ -376,7 +344,7 @@ public:
                                            bool parent_scope = false) const;
   bool SetPolicyVersion(std::string const& version_min,
                         std::string const& version_max);
-  void RecordPolicies(cmPolicies::PolicyMap& pm);
+  void RecordPolicies(cmPolicies::PolicyMap& pm) const;
   //@}
 
   /** Helper class to push and pop policies automatically.  */
@@ -430,8 +398,7 @@ public:
   }
   const char* GetIncludeRegularExpression() const
   {
-    cmProp p = this->GetProperty("INCLUDE_REGULAR_EXPRESSION");
-    return p ? p->c_str() : nullptr;
+    return cmToCStr(this->GetProperty("INCLUDE_REGULAR_EXPRESSION"));
   }
 
   /**
@@ -690,8 +657,7 @@ public:
    */
   int ConfigureFile(const std::string& infile, const std::string& outfile,
                     bool copyonly, bool atOnly, bool escapeQuotes,
-                    bool use_source_permissions,
-                    cmNewLineStyle = cmNewLineStyle());
+                    mode_t permissions = 0, cmNewLineStyle = cmNewLineStyle());
 
   /**
    * Print a command's invocation
@@ -753,20 +719,10 @@ public:
     return this->SourceFiles;
   }
 
-  /**
-   * Return the target if the provided source name is a byproduct of a utility
-   * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
-   * Return the source file which has the provided source name as output.
-   */
-  cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
-
-  /**
-   * Is there a source file that has the provided source name as an output?
-   * If so then return it.
-   */
-  cmSourceFile* GetSourceFileWithOutput(
-    const std::string& name,
-    cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
+  std::vector<cmTarget*> const& GetOrderedTargets() const
+  {
+    return this->OrderedTargets;
+  }
 
   //! Add a new cmTest to the list of tests for this makefile.
   cmTest* CreateTest(const std::string& testName);
@@ -779,7 +735,7 @@ public:
   /**
    * Get all tests that run under the given configuration.
    */
-  void GetTests(const std::string& config, std::vector<cmTest*>& tests);
+  void GetTests(const std::string& config, std::vector<cmTest*>& tests) const;
 
   /**
    * Return a location of a file in cmake or custom modules directory
@@ -926,7 +882,7 @@ public:
     return this->SystemIncludeDirectories;
   }
 
-  bool PolicyOptionalWarningEnabled(std::string const& var);
+  bool PolicyOptionalWarningEnabled(std::string const& var) const;
 
   void PushLoopBlock();
   void PopLoopBlock();
@@ -945,6 +901,7 @@ public:
     const std::string& inputFile, const std::string& targetName,
     std::unique_ptr<cmCompiledGeneratorExpression> outputName,
     std::unique_ptr<cmCompiledGeneratorExpression> condition,
+    const std::string& newLineCharacter, mode_t permissions,
     bool inputIsContent);
   const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
   GetEvaluationFiles() const;
@@ -967,7 +924,7 @@ public:
   int GetRecursionDepth() const;
   void SetRecursionDepth(int recursionDepth);
 
-  std::string NewDeferId();
+  std::string NewDeferId() const;
   bool DeferCall(std::string id, std::string fileName, cmListFileFunction lff);
   bool DeferCancelCall(std::string const& id);
   cm::optional<std::string> DeferGetCallIds() const;
@@ -983,8 +940,7 @@ protected:
   mutable cmTargetMap Targets;
   std::map<std::string, std::string> AliasTargets;
 
-  using TargetsVec = std::vector<cmTarget*>;
-  TargetsVec OrderedTargets;
+  std::vector<cmTarget*> OrderedTargets;
 
   std::vector<std::unique_ptr<cmSourceFile>> SourceFiles;
 
@@ -1129,48 +1085,9 @@ private:
   bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const;
 
   void CreateGeneratedOutputs(const std::vector<std::string>& outputs);
-  void CreateGeneratedByproducts(const std::vector<std::string>& byproducts);
 
   std::vector<BT<GeneratorAction>> GeneratorActions;
   bool GeneratorActionsInvoked = false;
-  bool DelayedOutputFilesHaveGenex = false;
-  std::vector<std::string> DelayedOutputFiles;
-
-  void AddDelayedOutput(std::string const& output);
-
-  /**
-   * See LinearGetSourceFileWithOutput for background information
-   */
-  cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
-
-  /**
-   * Generalized old version of GetSourceFileWithOutput kept for
-   * backward-compatibility. It implements a linear search and supports
-   * relative file paths. It is used as a fall back by GetSourceFileWithOutput
-   * and GetSourcesWithOutput.
-   */
-  cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
-                                              cmSourceOutputKind kind,
-                                              bool& byproduct) const;
-
-  struct SourceEntry
-  {
-    cmSourcesWithOutput Sources;
-    bool SourceMightBeOutput = false;
-  };
-
-  // A map for fast output to input look up.
-  using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
-  OutputToSourceMap OutputToSource;
-
-  void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target);
-  void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
-                               bool byproduct);
-
-  /**
-   * Return if the provided source file might have a custom command.
-   */
-  bool MightHaveCustomCommand(const std::string& name) const;
 
   bool CheckSystemVars;
   bool CheckCMP0000;
index 871878c..1750e37 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmMakefile.h"
 #include "cmOSXBundleGenerator.h"
 #include "cmOutputConverter.h"
+#include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -232,10 +233,10 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
 
     std::string launcher;
 
-    const char* val = this->LocalGenerator->GetRuleLauncher(
-      this->GeneratorTarget, "RULE_LAUNCH_LINK");
+    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                       "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
-      launcher = cmStrCat(val, ' ');
+      launcher = cmStrCat(*val, ' ');
     }
 
     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
@@ -591,10 +592,10 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
 
     std::string launcher;
 
-    const char* val = this->LocalGenerator->GetRuleLauncher(
-      this->GeneratorTarget, "RULE_LAUNCH_LINK");
+    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                       "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
-      launcher = cmStrCat(val, ' ');
+      launcher = cmStrCat(*val, ' ');
     }
 
     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
index b32ea6a..ce64e2c 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmMakefile.h"
 #include "cmOSXBundleGenerator.h"
 #include "cmOutputConverter.h"
+#include "cmProperty.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -366,10 +367,10 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules(
     vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
 
     std::string launcher;
-    const char* val = this->LocalGenerator->GetRuleLauncher(
-      this->GeneratorTarget, "RULE_LAUNCH_LINK");
+    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                       "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
-      launcher = cmStrCat(val, ' ');
+      launcher = cmStrCat(*val, ' ');
     }
 
     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
@@ -816,10 +817,10 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
     vars.LanguageCompileFlags = langFlags.c_str();
 
     std::string launcher;
-    const char* val = this->LocalGenerator->GetRuleLauncher(
-      this->GeneratorTarget, "RULE_LAUNCH_LINK");
+    cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
+                                                       "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
-      launcher = cmStrCat(val, ' ');
+      launcher = cmStrCat(*val, ' ');
     }
 
     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
index c6d6c99..4918bf6 100644 (file)
@@ -12,7 +12,9 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
@@ -23,6 +25,7 @@
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmLinkLineComputer.h" // IWYU pragma: keep
 #include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmMakefileExecutableTargetGenerator.h"
@@ -68,7 +71,8 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
       this->CMP0113New = true;
       break;
   }
-  MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this);
+  this->MacOSXContentGenerator =
+    cm::make_unique<MacOSXContentGeneratorType>(this);
 }
 
 cmMakefileTargetGenerator::~cmMakefileTargetGenerator() = default;
@@ -325,28 +329,80 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
     << cmSystemTools::ConvertToOutputPath(
          this->LocalGenerator->MaybeConvertToRelativePath(
            this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull))
-    << "\n\n";
+    << "\n";
 
-  if (!this->NoRuleMessages) {
-    // Include the progress variables for the target.
+  std::string depsUseCompiler = "CMAKE_DEPENDS_USE_COMPILER";
+  if (!this->Makefile->IsDefinitionSet(depsUseCompiler) ||
+      this->Makefile->IsOn(depsUseCompiler)) {
+    std::string compilerDependFile =
+      cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make");
     *this->BuildFileStream
-      << "# Include the progress variables for this target.\n"
+      << "# Include any dependencies generated by the "
+         "compiler for this target.\n"
       << this->GlobalGenerator->IncludeDirective << " " << root
       << cmSystemTools::ConvertToOutputPath(
            this->LocalGenerator->MaybeConvertToRelativePath(
-             this->LocalGenerator->GetBinaryDirectory(),
-             this->ProgressFileNameFull))
+             this->LocalGenerator->GetBinaryDirectory(), compilerDependFile))
       << "\n\n";
-  }
 
-  // make sure the depend file exists
-  if (!cmSystemTools::FileExists(dependFileNameFull)) {
     // Write an empty dependency file.
     cmGeneratedFileStream depFileStream(
-      dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
-    depFileStream << "# Empty dependencies file for "
+      compilerDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
+    depFileStream << "# Empty compiler generated dependencies file for "
                   << this->GeneratorTarget->GetName() << ".\n"
                   << "# This may be replaced when dependencies are built.\n";
+    // remove internal dependency file
+    cmSystemTools::RemoveFile(
+      cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.internal"));
+
+    std::string compilerDependTimestamp =
+      cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts");
+    if (!cmSystemTools::FileExists(compilerDependTimestamp)) {
+      // Write a dependency timestamp file.
+      cmGeneratedFileStream timestampFileStream(
+        compilerDependTimestamp, false,
+        this->GlobalGenerator->GetMakefileEncoding());
+      timestampFileStream
+        << "# CMAKE generated file: DO NOT EDIT!\n"
+        << "# Timestamp file for compiler generated dependencies "
+           "management for "
+        << this->GeneratorTarget->GetName() << ".\n";
+    }
+
+    // deactivate no longer needed legacy dependency files
+    // Write an empty dependency file.
+    cmGeneratedFileStream legacyDepFileStream(
+      dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
+    legacyDepFileStream
+      << "# Empty dependencies file for " << this->GeneratorTarget->GetName()
+      << ".\n"
+      << "# This may be replaced when dependencies are built.\n";
+    // remove internal dependency file
+    cmSystemTools::RemoveFile(
+      cmStrCat(this->TargetBuildDirectoryFull, "/depend.internal"));
+  } else {
+    // make sure the depend file exists
+    if (!cmSystemTools::FileExists(dependFileNameFull)) {
+      // Write an empty dependency file.
+      cmGeneratedFileStream depFileStream(
+        dependFileNameFull, false,
+        this->GlobalGenerator->GetMakefileEncoding());
+      depFileStream << "# Empty dependencies file for "
+                    << this->GeneratorTarget->GetName() << ".\n"
+                    << "# This may be replaced when dependencies are built.\n";
+    }
+  }
+
+  if (!this->NoRuleMessages) {
+    // Include the progress variables for the target.
+    *this->BuildFileStream
+      << "# Include the progress variables for this target.\n"
+      << this->GlobalGenerator->IncludeDirective << " " << root
+      << cmSystemTools::ConvertToOutputPath(
+           this->LocalGenerator->MaybeConvertToRelativePath(
+             this->LocalGenerator->GetBinaryDirectory(),
+             this->ProgressFileNameFull))
+      << "\n\n";
   }
 
   // Open the flags file.  This should be copy-if-different because the
@@ -472,6 +528,14 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     return;
   }
 
+  // Use compiler to generate dependencies, if supported.
+  bool compilerGenerateDeps =
+    this->GlobalGenerator->SupportsCompilerDependencies() &&
+    cmIsOn(this->Makefile->GetDefinition(
+      cmStrCat("CMAKE_", lang, "_DEPENDS_USE_COMPILER")));
+  auto scanner = compilerGenerateDeps ? cmDependencyScannerKind::Compiler
+                                      : cmDependencyScannerKind::CMake;
+
   // Get the full path name of the object file.
   std::string const& objectName =
     this->GeneratorTarget->GetObjectName(&source);
@@ -511,7 +575,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
   std::string srcFullPath =
     cmSystemTools::CollapseFullPath(source.GetFullPath());
   this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
-                                           objFullPath, srcFullPath);
+                                           objFullPath, srcFullPath, scanner);
 
   this->LocalGenerator->AppendRuleDepend(depends,
                                          this->FlagFileNameFull.c_str());
@@ -553,8 +617,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
         depends.push_back(
           this->GeneratorTarget->GetPchFile(config, lang, arch));
       }
-      this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
-                                               objFullPath, pchHeader);
+      this->LocalGenerator->AddImplicitDepends(
+        this->GeneratorTarget, lang, objFullPath, pchHeader, scanner);
     }
   }
 
@@ -573,6 +637,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
   // Build the set of compiler flags.
   std::string flags;
 
+  // Explicitly add the explicit language flag before any other flag
+  // so user flags can override it.
+  this->GeneratorTarget->AddExplicitLanguageFlags(flags, source);
+
   // Add language-specific flags.
   std::string langFlags = cmStrCat("$(", lang, "_FLAGS", filterArch, ")");
   this->LocalGenerator->AppendFlags(flags, langFlags);
@@ -693,7 +761,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     source.GetFullPath(), cmOutputConverter::SHELL);
 
   // Construct the build message.
-  std::vector<std::string> no_commands;
+  std::vector<std::string> no_depends;
   std::vector<std::string> commands;
 
   // add in a progress call if needed
@@ -747,6 +815,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
       // avoiding a trailing backslash in the argument.
       targetOutPathCompilePDB.back() = '/';
     }
+
+    std::string compilePdbOutputPath =
+      this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
+    cmSystemTools::MakeDirectory(compilePdbOutputPath);
   }
   cmRulePlaceholderExpander::RuleVariables vars;
   vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
@@ -787,13 +859,34 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
                                     "$(" + lang + "_INCLUDES)");
   vars.Includes = includesString.c_str();
 
+  std::string dependencyTarget;
+  std::string shellDependencyFile;
+  std::string dependencyTimestamp;
+  if (compilerGenerateDeps) {
+    dependencyTarget = this->LocalGenerator->EscapeForShell(
+      this->LocalGenerator->ConvertToMakefilePath(
+        this->LocalGenerator->MaybeConvertToRelativePath(
+          this->LocalGenerator->GetBinaryDirectory(), relativeObj)));
+    vars.DependencyTarget = dependencyTarget.c_str();
+
+    auto depFile = cmStrCat(obj, ".d");
+    shellDependencyFile = this->LocalGenerator->ConvertToOutputFormat(
+      depFile, cmOutputConverter::SHELL);
+    vars.DependencyFile = shellDependencyFile.c_str();
+    this->CleanFiles.insert(depFile);
+
+    dependencyTimestamp = this->LocalGenerator->MaybeConvertToRelativePath(
+      this->LocalGenerator->GetBinaryDirectory(),
+      cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"));
+  }
+
   // At the moment, it is assumed that C, C++, Fortran, and CUDA have both
   // assembly and preprocessor capabilities. The same is true for the
   // ability to export compile commands
   bool lang_has_preprocessor =
     ((lang == "C") || (lang == "CXX") || (lang == "OBJC") ||
      (lang == "OBJCXX") || (lang == "Fortran") || (lang == "CUDA") ||
-     lang == "ISPC");
+     lang == "ISPC" || lang == "ASM");
   bool const lang_has_assembly = lang_has_preprocessor;
   bool const lang_can_export_cmds = lang_has_preprocessor;
 
@@ -824,7 +917,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
       cmExpandList(compileRule, compileCommands);
     }
 
-    if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") &&
+    if (this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS") &&
         lang_can_export_cmds && compileCommands.size() == 1) {
       std::string compileCommand = compileCommands[0];
 
@@ -875,15 +968,21 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     }
 
     // Maybe insert an include-what-you-use runner.
-    if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) {
-      std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
-      cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+    if (!compileCommands.empty() &&
+        (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) {
       std::string const tidy_prop = lang + "_CLANG_TIDY";
       cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop);
-      std::string const cpplint_prop = lang + "_CPPLINT";
-      cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
-      std::string const cppcheck_prop = lang + "_CPPCHECK";
-      cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+      cmProp iwyu = nullptr;
+      cmProp cpplint = nullptr;
+      cmProp cppcheck = nullptr;
+      if (lang == "C" || lang == "CXX") {
+        std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE";
+        iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+        std::string const cpplint_prop = lang + "_CPPLINT";
+        cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
+        std::string const cppcheck_prop = lang + "_CPPCHECK";
+        cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+      }
       if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
           cmNonempty(cppcheck)) {
         std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile";
@@ -945,10 +1044,57 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
 
     std::string launcher;
     {
-      const char* val = this->LocalGenerator->GetRuleLauncher(
+      cmProp val = this->LocalGenerator->GetRuleLauncher(
         this->GeneratorTarget, "RULE_LAUNCH_COMPILE");
       if (cmNonempty(val)) {
-        launcher = cmStrCat(val, ' ');
+        launcher = cmStrCat(*val, ' ');
+      }
+    }
+
+    std::string flagsWithDeps(flags);
+
+    if (compilerGenerateDeps) {
+      // Injects dependency computation
+      auto depFlags = this->Makefile->GetSafeDefinition(
+        cmStrCat("CMAKE_DEPFILE_FLAGS_", lang));
+
+      if (!depFlags.empty()) {
+        // Add dependency flags
+        rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
+                                                     depFlags, vars);
+        flagsWithDeps.append(1, ' ');
+        flagsWithDeps.append(depFlags);
+      }
+      vars.Flags = flagsWithDeps.c_str();
+
+      const auto& extraCommands = this->Makefile->GetSafeDefinition(
+        cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
+      if (!extraCommands.empty()) {
+        auto commandList = cmExpandedList(extraCommands);
+        compileCommands.insert(compileCommands.end(), commandList.cbegin(),
+                               commandList.cend());
+      }
+
+      const auto& depFormat = this->Makefile->GetRequiredDefinition(
+        cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT"));
+
+      if (depFormat == "msvc"_s) {
+        // compiler must be launched through a wrapper to pick-up dependencies
+        std::string depFilter =
+          "$(CMAKE_COMMAND) -E cmake_cl_compile_depends ";
+        depFilter += cmStrCat("--dep-file=", shellDependencyFile);
+        depFilter +=
+          cmStrCat(" --working-dir=",
+                   this->LocalGenerator->ConvertToOutputFormat(
+                     this->LocalGenerator->GetCurrentBinaryDirectory(),
+                     cmOutputConverter::SHELL));
+        const auto& prefix = this->Makefile->GetSafeDefinition(
+          cmStrCat("CMAKE_", lang, "_CL_SHOWINCLUDES_PREFIX"));
+        depFilter += cmStrCat(" --filter-prefix=",
+                              this->LocalGenerator->ConvertToOutputFormat(
+                                prefix, cmOutputConverter::SHELL));
+        depFilter += " -- ";
+        compileCommands.front().insert(0, depFilter);
       }
     }
 
@@ -977,8 +1123,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
       cmExpandList(evaluated_outputs, outputs);
     }
   }
-  if (!ispcHeaderRelative
-         .empty()) { // can't move ispcHeader as vars is using it
+  if (!ispcHeaderRelative.empty()) {
+    // can't move ispcHeader as vars is using it
     outputs.emplace_back(ispcHeaderRelative);
   }
 
@@ -986,10 +1132,19 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
     this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
   }
 
+  if (compilerGenerateDeps) {
+    depends.push_back(dependencyTimestamp);
+  }
+
   // Write the rule.
   this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends,
                       commands);
 
+  if (compilerGenerateDeps) {
+    // set back flags without dependency generation
+    vars.Flags = flags.c_str();
+  }
+
   bool do_preprocess_rules = lang_has_preprocessor &&
     this->LocalGenerator->GetCreatePreprocessedSourceRules();
   bool do_assembly_rules =
@@ -1386,10 +1541,10 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule(
 
     std::string registerFileCmd;
 
-    // The generated register file contains macros that when expanded register
-    // the device routines. Because the routines are the same for all
-    // architectures the register file will be the same too. Thus generate it
-    // only on the first invocation to reduce overhead.
+    // The generated register file contains macros that when expanded
+    // register the device routines. Because the routines are the same for
+    // all architectures the register file will be the same too. Thus
+    // generate it only on the first invocation to reduce overhead.
     if (fatbinaryDepends.size() == 1) {
       std::string registerFileRel =
         this->LocalGenerator->MaybeConvertToRelativePath(
@@ -1424,7 +1579,8 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule(
                                       fatbinaryOutputRel, fatbinaryDepends,
                                       { fatbinaryCommand }, false);
 
-  // Compile the stub that registers the kernels and contains the fatbinaries.
+  // Compile the stub that registers the kernels and contains the
+  // fatbinaries.
   cmRulePlaceholderExpander::RuleVariables vars;
   vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
   vars.CMTargetType =
@@ -1481,6 +1637,16 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile(
   std::vector<std::string> depends;
   this->LocalGenerator->AppendCustomDepend(depends, ccg);
 
+  if (!ccg.GetCC().GetDepfile().empty()) {
+    // Add dependency over timestamp file for dependencies management
+    auto dependTimestamp = cmSystemTools::ConvertToOutputPath(
+      this->LocalGenerator->MaybeConvertToRelativePath(
+        this->LocalGenerator->GetBinaryDirectory(),
+        cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts")));
+
+    depends.push_back(dependTimestamp);
+  }
+
   // Write the rule.
   const std::vector<std::string>& outputs = ccg.GetOutputs();
   bool symbolic = this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs,
@@ -1517,6 +1683,15 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile(
                                              objFullPath, srcFullPath);
   }
 
+  // Setup implicit depend for depfile if any
+  if (!ccg.GetCC().GetDepfile().empty()) {
+    std::string objFullPath = cmSystemTools::CollapseFullPath(
+      outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory());
+    this->LocalGenerator->AddImplicitDepends(
+      this->GeneratorTarget, "CUSTOM", objFullPath, ccg.GetFullDepfile(),
+      cmDependencyScannerKind::Compiler);
+  }
+
   this->CustomCommandOutputs.insert(outputs.begin(), outputs.end());
 }
 
@@ -1542,12 +1717,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable(
                          << this->GeneratorTarget->GetName() << "\n"
                          << variableName << " =";
   std::string object;
-  std::string lineContinue;
-  if (cmProp p = this->Makefile->GetDefinition("CMAKE_MAKE_LINE_CONTINUE")) {
-    lineContinue = *p;
-  } else {
-    lineContinue = "\\";
-  }
+  const auto& lineContinue = this->GlobalGenerator->LineContinueDirective;
 
   cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
 
@@ -1555,7 +1725,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable(
     if (cmSystemTools::StringEndsWith(obj, cmToCStr(pchExtension))) {
       continue;
     }
-    *this->BuildFileStream << " " << lineContinue << "\n";
+    *this->BuildFileStream << " " << lineContinue;
     *this->BuildFileStream
       << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
            obj, useWatcomQuote);
@@ -1578,7 +1748,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable(
   for (std::string const& obj : this->ExternalObjects) {
     object =
       this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, obj);
-    *this->BuildFileStream << " " << lineContinue << "\n";
+    *this->BuildFileStream << " " << lineContinue;
     *this->BuildFileStream
       << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
            obj, useWatcomQuote);
@@ -1842,9 +2012,9 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
   if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) {
     // Compute the total length of our list of object files with room
     // for argument separation and quoting.  This does not convert paths
-    // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the
-    // actual list will likely be much shorter than this.  However, in the
-    // worst case all objects will remain as absolute paths.
+    // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so
+    // the actual list will likely be much shorter than this.  However, in
+    // the worst case all objects will remain as absolute paths.
     size_t length = 0;
     for (std::string const& obj : this->Objects) {
       length += obj.size() + 3;
index 6c18e48..a885b17 100644 (file)
@@ -15,6 +15,7 @@
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmOSXBundleGenerator.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
@@ -36,10 +37,42 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
   *this->BuildFileStream << "# Utility rule file for "
                          << this->GeneratorTarget->GetName() << ".\n\n";
 
+  const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
+                        ? "$(CMAKE_BINARY_DIR)/"
+                        : "");
+
+  // Include the dependencies for the target.
+  std::string dependFile =
+    cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make");
+  *this->BuildFileStream
+    << "# Include any custom commands dependencies for this target.\n"
+    << this->GlobalGenerator->IncludeDirective << " " << root
+    << cmSystemTools::ConvertToOutputPath(
+         this->LocalGenerator->MaybeConvertToRelativePath(
+           this->LocalGenerator->GetBinaryDirectory(), dependFile))
+    << "\n\n";
+  if (!cmSystemTools::FileExists(dependFile)) {
+    // Write an empty dependency file.
+    cmGeneratedFileStream depFileStream(
+      dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
+    depFileStream << "# Empty custom commands generated dependencies file for "
+                  << this->GeneratorTarget->GetName() << ".\n"
+                  << "# This may be replaced when dependencies are built.\n";
+  }
+
+  std::string dependTimestamp =
+    cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts");
+  if (!cmSystemTools::FileExists(dependTimestamp)) {
+    // Write a dependency timestamp file.
+    cmGeneratedFileStream depFileStream(
+      dependTimestamp, false, this->GlobalGenerator->GetMakefileEncoding());
+    depFileStream << "# CMAKE generated file: DO NOT EDIT!\n"
+                  << "# Timestamp file for custom commands dependencies "
+                     "management for "
+                  << this->GeneratorTarget->GetName() << ".\n";
+  }
+
   if (!this->NoRuleMessages) {
-    const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
-                          ? "$(CMAKE_BINARY_DIR)/"
-                          : "");
     // Include the progress variables for the target.
     *this->BuildFileStream
       << "# Include the progress variables for this target.\n"
index a121332..28baeb6 100644 (file)
@@ -8,13 +8,13 @@ cmNewLineStyle::cmNewLineStyle() = default;
 
 bool cmNewLineStyle::IsValid() const
 {
-  return NewLineStyle != Invalid;
+  return this->NewLineStyle != Invalid;
 }
 
 bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args,
                                        std::string& errorString)
 {
-  NewLineStyle = Invalid;
+  this->NewLineStyle = Invalid;
 
   for (size_t i = 0; i < args.size(); i++) {
     if (args[i] == "NEWLINE_STYLE") {
@@ -22,11 +22,11 @@ bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args,
       if (args.size() > styleIndex) {
         std::string const& eol = args[styleIndex];
         if (eol == "LF" || eol == "UNIX") {
-          NewLineStyle = LF;
+          this->NewLineStyle = LF;
           return true;
         }
         if (eol == "CRLF" || eol == "WIN32" || eol == "DOS") {
-          NewLineStyle = CRLF;
+          this->NewLineStyle = CRLF;
           return true;
         }
         errorString = "NEWLINE_STYLE sets an unknown style, only LF, "
@@ -43,7 +43,7 @@ bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args,
 
 std::string cmNewLineStyle::GetCharacters() const
 {
-  switch (NewLineStyle) {
+  switch (this->NewLineStyle) {
     case Invalid:
       return "";
     case LF:
@@ -56,10 +56,10 @@ std::string cmNewLineStyle::GetCharacters() const
 
 void cmNewLineStyle::SetStyle(Style style)
 {
-  NewLineStyle = style;
+  this->NewLineStyle = style;
 }
 
 cmNewLineStyle::Style cmNewLineStyle::GetStyle() const
 {
-  return NewLineStyle;
+  return this->NewLineStyle;
 }
index 7fbeeea..2304ad2 100644 (file)
@@ -18,5 +18,5 @@ cmNinjaLinkLineComputer::cmNinjaLinkLineComputer(
 std::string cmNinjaLinkLineComputer::ConvertToLinkReference(
   std::string const& lib) const
 {
-  return GG->ConvertToNinjaPath(lib);
+  return this->GG->ConvertToNinjaPath(lib);
 }
index 84c1b37..f66e2f5 100644 (file)
@@ -16,5 +16,5 @@ cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer(
 std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference(
   std::string const& lib) const
 {
-  return GG->ConvertToNinjaPath(lib);
+  return this->GG->ConvertToNinjaPath(lib);
 }
index ccb959b..49e5e4c 100644 (file)
@@ -12,6 +12,7 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/optional>
 #include <cm/vector>
 
 #include "cmComputeLinkInformation.h"
@@ -49,7 +50,7 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
     // on Windows the output dir is already needed at compile time
     // ensure the directory exists (OutDir test)
     for (auto const& config : this->GetConfigNames()) {
-      EnsureDirectoryExists(target->GetDirectory(config));
+      this->EnsureDirectoryExists(target->GetDirectory(config));
     }
   }
 
@@ -266,10 +267,10 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule(
     vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS";
 
     std::string launcher;
-    const char* val = this->GetLocalGenerator()->GetRuleLauncher(
+    cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
       this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
-      launcher = cmStrCat(val, ' ');
+      launcher = cmStrCat(*val, ' ');
     }
 
     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
@@ -306,7 +307,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules(
 {
   const cmMakefile* mf = this->GetMakefile();
 
-  cmNinjaRule rule(LanguageLinkerCudaDeviceRule(config));
+  cmNinjaRule rule(this->LanguageLinkerCudaDeviceRule(config));
   rule.Command = this->GetLocalGenerator()->BuildCommandLine(
     { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_DEVICE_LINKER"),
                " -arch=$ARCH $REGISTER -o=$out $in") });
@@ -334,13 +335,13 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules(
   rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
                                                compileCmd, vars);
 
-  rule.Name = LanguageLinkerCudaDeviceCompileRule(config);
+  rule.Name = this->LanguageLinkerCudaDeviceCompileRule(config);
   rule.Command = this->GetLocalGenerator()->BuildCommandLine({ compileCmd });
   rule.Comment = "Rule for compiling CUDA device stubs.";
   rule.Description = "Compiling CUDA device stub $out";
   this->GetGlobalGenerator()->AddRule(rule);
 
-  rule.Name = LanguageLinkerCudaFatbinaryRule(config);
+  rule.Name = this->LanguageLinkerCudaFatbinaryRule(config);
   rule.Command = this->GetLocalGenerator()->BuildCommandLine(
     { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_FATBINARY"),
                " -64 -cmdline=--compile-only -compress-all -link "
@@ -385,7 +386,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
 
     // build response file name
     std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
-    cmProp flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+    cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
 
     if (flag) {
       responseFlag = *flag;
@@ -452,10 +453,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
     }
 
     std::string launcher;
-    const char* val = this->GetLocalGenerator()->GetRuleLauncher(
+    cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
       this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
     if (cmNonempty(val)) {
-      launcher = cmStrCat(val, ' ');
+      launcher = cmStrCat(*val, ' ');
     }
 
     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
@@ -673,7 +674,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
   targetOutputDir = globalGen->ExpandCFGIntDir(targetOutputDir, config);
 
   std::string targetOutputReal =
-    ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt);
+    this->ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt);
 
   if (firstForConfig) {
     globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal);
@@ -730,7 +731,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements(
              this->GetGlobalGenerator()->ConfigDirectory(config));
   const std::string ninjaOutputDir = this->ConvertToNinjaPath(objectDir);
 
-  cmNinjaBuild fatbinary(LanguageLinkerCudaFatbinaryRule(config));
+  cmNinjaBuild fatbinary(this->LanguageLinkerCudaFatbinaryRule(config));
 
   // Link device code for each architecture.
   for (const std::string& architectureKind : architectures) {
@@ -744,7 +745,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements(
       cmStrCat(" -im=profile=sm_", architecture, ",file=", cubin);
     fatbinary.ExplicitDeps.emplace_back(cubin);
 
-    cmNinjaBuild dlink(LanguageLinkerCudaDeviceRule(config));
+    cmNinjaBuild dlink(this->LanguageLinkerCudaDeviceRule(config));
     dlink.ExplicitDeps = explicitDeps;
     dlink.Outputs = { cubin };
     dlink.Variables["ARCH"] = cmStrCat("sm_", architecture);
@@ -767,7 +768,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements(
                                          fatbinary);
 
   // Compile the stub that registers the kernels and contains the fatbinaries.
-  cmNinjaBuild dcompile(LanguageLinkerCudaDeviceCompileRule(config));
+  cmNinjaBuild dcompile(this->LanguageLinkerCudaDeviceCompileRule(config));
   dcompile.Outputs = { output };
   dcompile.ExplicitDeps = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") };
   dcompile.Variables["FATBIN"] =
@@ -787,7 +788,7 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
   cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
   cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
 
-  std::string targetOutputImplib = ConvertToNinjaPath(
+  std::string targetOutputImplib = this->ConvertToNinjaPath(
     genTarget->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
 
   if (config != fileConfig) {
@@ -806,7 +807,7 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
            ->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
            .empty() &&
         targetOutputImplib ==
-          ConvertToNinjaPath(genTarget->GetFullPath(
+          this->ConvertToNinjaPath(genTarget->GetFullPath(
             fileConfig, cmStateEnums::ImportLibraryArtifact))) {
       return;
     }
@@ -882,16 +883,16 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
-    EnsureParentDirectoryExists(impLibPath);
+    this->EnsureParentDirectoryExists(impLibPath);
   }
 
   const std::string objPath =
-    cmStrCat(GetGeneratorTarget()->GetSupportDirectory(),
+    cmStrCat(this->GetGeneratorTarget()->GetSupportDirectory(),
              globalGen->ConfigDirectory(config));
 
   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
-  EnsureDirectoryExists(objPath);
+  this->EnsureDirectoryExists(objPath);
 
   this->SetMsvcTargetPdbVariable(vars, config);
 
@@ -933,21 +934,22 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
   cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
   cmGeneratorTarget* gt = this->GetGeneratorTarget();
 
-  std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(config));
-  std::string targetOutputReal = ConvertToNinjaPath(
+  std::string targetOutput = this->ConvertToNinjaPath(gt->GetFullPath(config));
+  std::string targetOutputReal = this->ConvertToNinjaPath(
     gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
                     /*realname=*/true));
-  std::string targetOutputImplib = ConvertToNinjaPath(
+  std::string targetOutputImplib = this->ConvertToNinjaPath(
     gt->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
 
   if (config != fileConfig) {
-    if (targetOutput == ConvertToNinjaPath(gt->GetFullPath(fileConfig))) {
+    if (targetOutput ==
+        this->ConvertToNinjaPath(gt->GetFullPath(fileConfig))) {
       return;
     }
     if (targetOutputReal ==
-        ConvertToNinjaPath(gt->GetFullPath(fileConfig,
-                                           cmStateEnums::RuntimeBinaryArtifact,
-                                           /*realname=*/true))) {
+        this->ConvertToNinjaPath(
+          gt->GetFullPath(fileConfig, cmStateEnums::RuntimeBinaryArtifact,
+                          /*realname=*/true))) {
       return;
     }
     if (!gt->GetFullName(config, cmStateEnums::ImportLibraryArtifact)
@@ -955,7 +957,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
         !gt->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
            .empty() &&
         targetOutputImplib ==
-          ConvertToNinjaPath(gt->GetFullPath(
+          this->ConvertToNinjaPath(gt->GetFullPath(
             fileConfig, cmStateEnums::ImportLibraryArtifact))) {
       return;
     }
@@ -1095,7 +1097,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
   std::vector<std::string> extraISPCObjects =
     this->GetGeneratorTarget()->GetGeneratedISPCObjects(config);
   std::transform(extraISPCObjects.begin(), extraISPCObjects.end(),
-                 std::back_inserter(linkBuild.ExplicitDeps), MapToNinjaPath());
+                 std::back_inserter(linkBuild.ExplicitDeps),
+                 this->MapToNinjaPath());
 
   linkBuild.ImplicitDeps =
     this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
@@ -1189,7 +1192,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
-    EnsureParentDirectoryExists(impLibPath);
+    this->EnsureParentDirectoryExists(impLibPath);
     if (gt->HasImportLibrary(config)) {
       byproducts.push_back(targetOutputImplib);
       if (firstForConfig) {
@@ -1218,7 +1221,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     cmStrCat(gt->GetSupportDirectory(), globalGen->ConfigDirectory(config));
   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
-  EnsureDirectoryExists(objPath);
+  this->EnsureDirectoryExists(objPath);
 
   std::string& linkLibraries = vars["LINK_LIBRARIES"];
   std::string& link_path = vars["LINK_PATH"];
@@ -1236,22 +1239,25 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
   std::vector<std::string> preLinkCmdLines;
   std::vector<std::string> postBuildCmdLines;
 
-  if (config == fileConfig) {
-    std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
-                                                  &preLinkCmdLines,
-                                                  &postBuildCmdLines };
-
-    for (unsigned i = 0; i != 3; ++i) {
-      for (cmCustomCommand const& cc : *cmdLists[i]) {
-        cmCustomCommandGenerator ccg(cc, config, this->GetLocalGenerator());
+  std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
+                                                &preLinkCmdLines,
+                                                &postBuildCmdLines };
+
+  for (unsigned i = 0; i != 3; ++i) {
+    for (cmCustomCommand const& cc : *cmdLists[i]) {
+      if (config == fileConfig ||
+          this->GetLocalGenerator()->HasUniqueByproducts(cc.GetByproducts(),
+                                                         cc.GetBacktrace())) {
+        cmCustomCommandGenerator ccg(cc, fileConfig, this->GetLocalGenerator(),
+                                     true, config);
         localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
         std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
         std::transform(ccByproducts.begin(), ccByproducts.end(),
-                       std::back_inserter(byproducts), MapToNinjaPath());
+                       std::back_inserter(byproducts), this->MapToNinjaPath());
         std::transform(
           ccByproducts.begin(), ccByproducts.end(),
           std::back_inserter(globalGen->GetByproductsForCleanTarget()),
-          MapToNinjaPath());
+          this->MapToNinjaPath());
       }
     }
   }
@@ -1272,7 +1278,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
     cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
       obj_list_file, cmOutputConverter::SHELL);
 
-    cmProp nm_executable = GetMakefile()->GetDefinition("CMAKE_NM");
+    cmProp nm_executable = this->GetMakefile()->GetDefinition("CMAKE_NM");
     if (cmNonempty(nm_executable)) {
       cmd += " --nm=";
       cmd += this->LocalCommonGenerator->ConvertToOutputFormat(
@@ -1325,7 +1331,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
   // build response file name
   std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
 
-  cmProp flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+  cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
 
   bool const lang_supports_response =
     !(this->TargetLinkLanguage(config) == "RC" ||
index ffc405c..30127fe 100644 (file)
@@ -52,7 +52,6 @@ private:
   std::vector<std::string> ComputeLinkCmd(const std::string& config);
   std::vector<std::string> ComputeDeviceLinkCmd();
 
-private:
   // Target name info.
   cmGeneratorTarget::Names TargetNames(const std::string& config) const;
   std::string TargetLinkLanguage(const std::string& config) const;
index d41cbd2..672b579 100644 (file)
@@ -12,7 +12,9 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include <cm3p/json/value.h>
 #include <cm3p/json/writer.h>
@@ -33,6 +35,7 @@
 #include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
+#include "cmStandardLevelResolver.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -105,7 +108,7 @@ std::string cmNinjaTargetGenerator::LanguageCompilerRule(
     '_', config);
 }
 
-std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
+std::string cmNinjaTargetGenerator::LanguagePreprocessAndScanRule(
   std::string const& lang, const std::string& config) const
 {
   return cmStrCat(
@@ -114,7 +117,7 @@ std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
     '_', config);
 }
 
-std::string cmNinjaTargetGenerator::LanguageDependencyRule(
+std::string cmNinjaTargetGenerator::LanguageScanRule(
   std::string const& lang, const std::string& config) const
 {
   return cmStrCat(
@@ -129,14 +132,7 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
   return lang == "Fortran";
 }
 
-bool cmNinjaTargetGenerator::UsePreprocessedSource(
-  std::string const& lang) const
-{
-  return lang == "Fortran";
-}
-
-bool cmNinjaTargetGenerator::CompilePreprocessedSourceWithDefines(
-  std::string const& lang) const
+bool cmNinjaTargetGenerator::CompileWithDefines(std::string const& lang) const
 {
   return this->Makefile->IsOn(
     cmStrCat("CMAKE_", lang, "_COMPILE_WITH_DEFINES"));
@@ -151,9 +147,26 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule(
     '_', config);
 }
 
-bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
+bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
+  std::string const& lang, std::string const& config) const
 {
-  return lang == "Fortran";
+  if (lang != "CXX") {
+    return false;
+  }
+  if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
+    return false;
+  }
+  cmGeneratorTarget const* tgt = this->GetGeneratorTarget();
+  cmStandardLevelResolver standardResolver(this->Makefile);
+  bool const uses_cxx20 =
+    standardResolver.HaveStandardAvailable(tgt, "CXX", config, "cxx_std_20");
+  return uses_cxx20 && this->GetGlobalGenerator()->CheckCxxModuleSupport();
+}
+
+bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang,
+                                        std::string const& config) const
+{
+  return lang == "Fortran" || this->NeedCxxModuleSupport(lang, config);
 }
 
 std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget(
@@ -190,7 +203,15 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
     }
   }
 
-  std::string flags = this->GetFlags(language, config, filterArch);
+  std::string flags;
+  // Explicitly add the explicit language flag before any other flag
+  // so user flags can override it.
+  this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source);
+
+  if (!flags.empty()) {
+    flags += " ";
+  }
+  flags += this->GetFlags(language, config, filterArch);
 
   // Add Fortran format flags.
   if (language == "Fortran") {
@@ -252,32 +273,6 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
   this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
 }
 
-bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const
-{
-  std::string const& deptype = this->GetMakefile()->GetSafeDefinition(
-    cmStrCat("CMAKE_NINJA_DEPTYPE_", lang));
-  if (deptype == "msvc") {
-    return true;
-  }
-  if (deptype == "intel") {
-    // Ninja does not really define "intel", but we use it to switch based
-    // on whether this environment supports "gcc" or "msvc" deptype.
-    if (!this->GetGlobalGenerator()->SupportsMultilineDepfile()) {
-      // This ninja version is too old to support the Intel depfile format.
-      // Fall back to msvc deptype.
-      return true;
-    }
-    if ((this->Makefile->GetHomeDirectory().find(' ') != std::string::npos) ||
-        (this->Makefile->GetHomeOutputDirectory().find(' ') !=
-         std::string::npos)) {
-      // The Intel compiler does not properly escape spaces in a depfile.
-      // Fall back to msvc deptype.
-      return true;
-    }
-  }
-  return false;
-}
-
 // TODO: Refactor with
 // void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
 std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
@@ -355,7 +350,8 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps(
 
   const std::vector<std::string>& deps = cli->GetDepends();
   cmNinjaDeps result(deps.size());
-  std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath());
+  std::transform(deps.begin(), deps.end(), result.begin(),
+                 this->MapToNinjaPath());
 
   // Add a dependency on the link definitions file, if any.
   if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
@@ -376,7 +372,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps(
   std::vector<std::string> linkDeps;
   this->GeneratorTarget->GetLinkDepends(linkDeps, config, linkLanguage);
   std::transform(linkDeps.begin(), linkDeps.end(), std::back_inserter(result),
-                 MapToNinjaPath());
+                 this->MapToNinjaPath());
 
   return result;
 }
@@ -384,7 +380,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps(
 std::string cmNinjaTargetGenerator::GetSourceFilePath(
   cmSourceFile const* source) const
 {
-  return ConvertToNinjaPath(source->GetFullPath());
+  return this->ConvertToNinjaPath(source->GetFullPath());
 }
 
 std::string cmNinjaTargetGenerator::GetObjectFilePath(
@@ -465,7 +461,7 @@ std::string cmNinjaTargetGenerator::GetTargetOutputDir(
   const std::string& config) const
 {
   std::string dir = this->GeneratorTarget->GetDirectory(config);
-  return ConvertToNinjaPath(dir);
+  return this->ConvertToNinjaPath(dir);
 }
 
 std::string cmNinjaTargetGenerator::GetTargetFilePath(
@@ -502,13 +498,13 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(
     }
 
     vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-      ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL);
+      this->ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL);
     vars["TARGET_COMPILE_PDB"] =
       this->GetLocalGenerator()->ConvertToOutputFormat(
-        ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL);
+        this->ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL);
 
-    EnsureParentDirectoryExists(pdbPath);
-    EnsureParentDirectoryExists(compilePdbPath);
+    this->EnsureParentDirectoryExists(pdbPath);
+    this->EnsureParentDirectoryExists(compilePdbPath);
     return true;
   }
   return false;
@@ -527,82 +523,62 @@ namespace {
 // Create the command to run the dependency scanner
 std::string GetScanCommand(const std::string& cmakeCmd, const std::string& tdi,
                            const std::string& lang, const std::string& ppFile,
-                           bool needDyndep, const std::string& ddiFile)
+                           const std::string& ddiFile)
 {
-  std::string ccmd =
-    cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, " --lang=", lang,
-             " --pp=", ppFile, " --dep=$DEP_FILE");
-  if (needDyndep) {
-    ccmd = cmStrCat(ccmd, " --obj=$OBJ_FILE --ddi=", ddiFile);
-  }
-  return ccmd;
+  return cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi,
+                  " --lang=", lang, " --src=$in", " --pp=", ppFile,
+                  " --dep=$DEP_FILE --obj=$OBJ_FILE --ddi=", ddiFile);
 }
 
-// Helper function to create dependency scanning rule, with optional
-// explicit preprocessing step if preprocessCommand is non-empty
-cmNinjaRule GetPreprocessScanRule(
-  const std::string& ruleName, cmRulePlaceholderExpander::RuleVariables& vars,
+// Helper function to create dependency scanning rule that may or may
+// not perform explicit preprocessing too.
+cmNinjaRule GetScanRule(
+  const std::string& ruleName,
+  cmRulePlaceholderExpander::RuleVariables const& vars,
   const std::string& responseFlag, const std::string& flags,
-  const std::string& launcher,
   cmRulePlaceholderExpander* const rulePlaceholderExpander,
-  std::string scanCommand, cmLocalNinjaGenerator* generator,
-  const std::string& preprocessCommand = "")
+  cmLocalNinjaGenerator* generator, std::vector<std::string> scanCmds)
 {
   cmNinjaRule rule(ruleName);
-  // Explicit preprocessing always uses a depfile.
+  // Scanning always uses a depfile for preprocessor dependencies.
   rule.DepType = ""; // no deps= for multiple outputs
   rule.DepFile = "$DEP_FILE";
 
-  cmRulePlaceholderExpander::RuleVariables ppVars;
-  ppVars.CMTargetName = vars.CMTargetName;
-  ppVars.CMTargetType = vars.CMTargetType;
-  ppVars.Language = vars.Language;
-  ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
-  ppVars.PreprocessedSource = "$out";
-  ppVars.DependencyFile = rule.DepFile.c_str();
-
-  // Preprocessing uses the original source, compilation uses
-  // preprocessed output or original source
-  ppVars.Source = vars.Source;
-  vars.Source = "$in";
-
-  // Copy preprocessor definitions to the preprocessor rule.
-  ppVars.Defines = vars.Defines;
+  cmRulePlaceholderExpander::RuleVariables scanVars;
+  scanVars.CMTargetName = vars.CMTargetName;
+  scanVars.CMTargetType = vars.CMTargetType;
+  scanVars.Language = vars.Language;
+  scanVars.Object = "$OBJ_FILE";
+  scanVars.PreprocessedSource = "$out";
+  scanVars.DynDepFile = "$DYNDEP_INTERMEDIATE_FILE";
+  scanVars.DependencyFile = rule.DepFile.c_str();
+  scanVars.DependencyTarget = "$out";
 
-  // Copy include directories to the preprocessor rule.  The Fortran
-  // compilation rule still needs them for the INCLUDE directive.
-  ppVars.Includes = vars.Includes;
+  // Scanning needs the same preprocessor settings as direct compilation would.
+  scanVars.Source = vars.Source;
+  scanVars.Defines = vars.Defines;
+  scanVars.Includes = vars.Includes;
 
-  // Preprocessing and compilation use the same flags.
-  std::string ppFlags = flags;
+  // Scanning needs the compilation flags too.
+  std::string scanFlags = flags;
 
   // If using a response file, move defines, includes, and flags into it.
   if (!responseFlag.empty()) {
     rule.RspFile = "$RSP_FILE";
     rule.RspContent =
-      cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags);
-    ppFlags = cmStrCat(responseFlag, rule.RspFile);
-    ppVars.Defines = "";
-    ppVars.Includes = "";
+      cmStrCat(' ', scanVars.Defines, ' ', scanVars.Includes, ' ', scanFlags);
+    scanFlags = cmStrCat(responseFlag, rule.RspFile);
+    scanVars.Defines = "";
+    scanVars.Includes = "";
   }
 
-  ppVars.Flags = ppFlags.c_str();
-
-  // Rule for preprocessing source file.
-  std::vector<std::string> ppCmds;
+  scanVars.Flags = scanFlags.c_str();
 
-  if (!preprocessCommand.empty()) {
-    // Lookup the explicit preprocessing rule.
-    cmExpandList(preprocessCommand, ppCmds);
-    for (std::string& i : ppCmds) {
-      i = cmStrCat(launcher, i);
-      rulePlaceholderExpander->ExpandRuleVariables(generator, i, ppVars);
-    }
+  // Rule for scanning a source file.
+  for (std::string& scanCmd : scanCmds) {
+    rulePlaceholderExpander->ExpandRuleVariables(generator, scanCmd, scanVars);
   }
-
-  // Run CMake dependency scanner on either preprocessed output or source file
-  ppCmds.emplace_back(std::move(scanCommand));
-  rule.Command = generator->BuildCommandLine(ppCmds);
+  rule.Command = generator->BuildCommandLine(scanCmds);
 
   return rule;
 }
@@ -628,11 +604,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
 
   cmMakefile* mf = this->GetMakefile();
 
-  // For some cases we do an explicit preprocessor invocation.
-  bool const explicitPP = this->NeedExplicitPreprocessing(lang);
-  bool const compilePPWithDefines = this->UsePreprocessedSource(lang) &&
-    this->CompilePreprocessedSourceWithDefines(lang);
-  bool const needDyndep = this->NeedDyndep(lang);
+  // For some cases we scan to dynamically discover dependencies.
+  bool const needDyndep = this->NeedDyndep(lang, config);
+  bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang);
 
   std::string flags = "$FLAGS";
 
@@ -646,65 +620,97 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
       responseFlag = "@";
     }
   }
+  std::string const modmapFormatVar =
+    cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FORMAT");
+  std::string const modmapFormat =
+    this->Makefile->GetSafeDefinition(modmapFormatVar);
 
   std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
     this->GetLocalGenerator()->CreateRulePlaceholderExpander());
 
   std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
-    ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)),
+    this->ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)),
     cmLocalGenerator::SHELL);
 
   std::string launcher;
-  const char* val = this->GetLocalGenerator()->GetRuleLauncher(
+  cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
     this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE");
   if (cmNonempty(val)) {
-    launcher = cmStrCat(val, ' ');
+    launcher = cmStrCat(*val, ' ');
   }
 
   std::string const cmakeCmd =
     this->GetLocalGenerator()->ConvertToOutputFormat(
       cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
 
-  if (explicitPP) {
-    // Combined preprocessing and dependency scanning
-    const auto ppScanCommand = GetScanCommand(
-      cmakeCmd, tdi, lang, "$out", needDyndep, "$DYNDEP_INTERMEDIATE_FILE");
-    const auto ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE");
-
-    auto ppRule = GetPreprocessScanRule(
-      this->LanguagePreprocessRule(lang, config), vars, responseFlag, flags,
-      launcher, rulePlaceholderExpander.get(), ppScanCommand,
-      this->GetLocalGenerator(), mf->GetRequiredDefinition(ppVar));
-
-    // Write the rule for preprocessing file of the given language.
-    ppRule.Comment = cmStrCat("Rule for preprocessing ", lang, " files.");
-    ppRule.Description = cmStrCat("Building ", lang, " preprocessed $out");
+  if (needDyndep) {
+    // Rule to scan dependencies of sources that need preprocessing.
+    {
+      std::vector<std::string> scanCommands;
+      std::string scanRuleName;
+      if (compilationPreprocesses) {
+        scanRuleName = this->LanguageScanRule(lang, config);
+        std::string const& scanCommand = mf->GetRequiredDefinition(
+          cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE"));
+        cmExpandList(scanCommand, scanCommands);
+        for (std::string& i : scanCommands) {
+          i = cmStrCat(launcher, i);
+        }
+      } else {
+        scanRuleName = this->LanguagePreprocessAndScanRule(lang, config);
+        std::string const& ppCommmand = mf->GetRequiredDefinition(
+          cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"));
+        cmExpandList(ppCommmand, scanCommands);
+        for (std::string& i : scanCommands) {
+          i = cmStrCat(launcher, i);
+        }
+        scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out",
+                                                 "$DYNDEP_INTERMEDIATE_FILE"));
+      }
 
-    this->GetGlobalGenerator()->AddRule(ppRule);
+      auto scanRule = GetScanRule(
+        scanRuleName, vars, responseFlag, flags, rulePlaceholderExpander.get(),
+        this->GetLocalGenerator(), std::move(scanCommands));
+
+      scanRule.Comment =
+        cmStrCat("Rule for generating ", lang, " dependencies.");
+      if (compilationPreprocesses) {
+        scanRule.Description =
+          cmStrCat("Scanning $in for ", lang, " dependencies");
+      } else {
+        scanRule.Description =
+          cmStrCat("Building ", lang, " preprocessed $out");
+      }
 
-    if (!compilePPWithDefines) {
-      // Remove preprocessor definitions from compilation step
-      vars.Defines = "";
+      this->GetGlobalGenerator()->AddRule(scanRule);
     }
 
-    // Just dependency scanning for files that have preprocessing turned off
-    const auto scanCommand =
-      GetScanCommand(cmakeCmd, tdi, lang, "$in", needDyndep, "$out");
+    if (!compilationPreprocesses) {
+      // Compilation will not preprocess, so it does not need the defines
+      // unless the compiler wants them for some other purpose.
+      if (!this->CompileWithDefines(lang)) {
+        vars.Defines = "";
+      }
 
-    auto scanRule = GetPreprocessScanRule(
-      this->LanguageDependencyRule(lang, config), vars, "", flags, launcher,
-      rulePlaceholderExpander.get(), scanCommand, this->GetLocalGenerator());
+      // Rule to scan dependencies of sources that do not need preprocessing.
+      std::string const& scanRuleName = this->LanguageScanRule(lang, config);
+      std::vector<std::string> scanCommands;
+      scanCommands.emplace_back(
+        GetScanCommand(cmakeCmd, tdi, lang, "$in", "$out"));
 
-    // Write the rule for generating dependencies for the given language.
-    scanRule.Comment = cmStrCat("Rule for generating ", lang,
-                                " dependencies on non-preprocessed files.");
-    scanRule.Description =
-      cmStrCat("Generating ", lang, " dependencies for $in");
+      auto scanRule = GetScanRule(
+        scanRuleName, vars, "", flags, rulePlaceholderExpander.get(),
+        this->GetLocalGenerator(), std::move(scanCommands));
 
-    this->GetGlobalGenerator()->AddRule(scanRule);
-  }
+      // Write the rule for generating dependencies for the given language.
+      scanRule.Comment = cmStrCat("Rule for generating ", lang,
+                                  " dependencies on non-preprocessed files.");
+      scanRule.Description =
+        cmStrCat("Generating ", lang, " dependencies for $in");
+
+      this->GetGlobalGenerator()->AddRule(scanRule);
+    }
 
-  if (needDyndep) {
     // Write the rule for ninja dyndep file generation.
     cmNinjaRule rule(this->LanguageDyndepRule(lang, config));
     // Command line length is almost always limited -> use response file for
@@ -714,12 +720,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
 
     // Run CMake dependency scanner on the source file (using the preprocessed
     // source if that was performed).
+    std::string ddModmapArg;
+    if (!modmapFormat.empty()) {
+      ddModmapArg += cmStrCat(" --modmapfmt=", modmapFormat);
+    }
     {
       std::vector<std::string> ddCmds;
       {
-        std::string ccmd =
-          cmStrCat(cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi,
-                   " --lang=", lang, " --dd=$out @", rule.RspFile);
+        std::string ccmd = cmStrCat(
+          cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi, " --lang=", lang,
+          ddModmapArg, " --dd=$out @", rule.RspFile);
         ddCmds.emplace_back(std::move(ccmd));
       }
       rule.Command = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
@@ -743,12 +753,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
 
   // Tell ninja dependency format so all deps can be loaded into a database
   std::string cldeps;
-  if (explicitPP) {
-    // The explicit preprocessing step will handle dependency scanning.
-  } else if (this->NeedDepTypeMSVC(lang)) {
-    rule.DepType = "msvc";
-    rule.DepFile.clear();
-    flags += " /showIncludes";
+  if (!compilationPreprocesses) {
+    // The compiler will not do preprocessing, so it has no such dependencies.
   } else if (mf->IsOn(cmStrCat("CMAKE_NINJA_CMCLDEPS_", lang))) {
     // For the MS resource compiler we need cmcldeps, but skip dependencies
     // for source-file try_compile cases because they are always fresh.
@@ -764,20 +770,35 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
                         "\" \"", cl, "\" ");
     }
   } else {
-    rule.DepType = "gcc";
-    rule.DepFile = "$DEP_FILE";
+    const auto& depType = this->GetMakefile()->GetSafeDefinition(
+      cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT"));
+    if (depType == "msvc"_s) {
+      rule.DepType = "msvc";
+      rule.DepFile.clear();
+    } else {
+      rule.DepType = "gcc";
+      rule.DepFile = "$DEP_FILE";
+    }
+    vars.DependencyFile = rule.DepFile.c_str();
+    vars.DependencyTarget = "$out";
+
     const std::string flagsName = cmStrCat("CMAKE_DEPFILE_FLAGS_", lang);
     std::string depfileFlags = mf->GetSafeDefinition(flagsName);
     if (!depfileFlags.empty()) {
-      cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE");
-      cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out");
-      cmSystemTools::ReplaceString(
-        depfileFlags, "<CMAKE_C_COMPILER>",
-        cmToCStr(mf->GetDefinition("CMAKE_C_COMPILER")));
+      rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+                                                   depfileFlags, vars);
       flags += cmStrCat(' ', depfileFlags);
     }
   }
 
+  if (needDyndep && !modmapFormat.empty()) {
+    std::string modmapFlags = mf->GetRequiredDefinition(
+      cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG"));
+    cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>",
+                                 "$DYNDEP_MODULE_MAP_FILE");
+    flags += cmStrCat(' ', modmapFlags);
+  }
+
   vars.Flags = flags.c_str();
   vars.DependencyFile = rule.DepFile.c_str();
 
@@ -815,15 +836,21 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
   }
 
   // Maybe insert an include-what-you-use runner.
-  if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) {
-    std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE");
-    cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+  if (!compileCmds.empty() &&
+      (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) {
     std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY");
     cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop);
-    std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT");
-    cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
-    std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
-    cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+    cmProp iwyu = nullptr;
+    cmProp cpplint = nullptr;
+    cmProp cppcheck = nullptr;
+    if (lang == "C" || lang == "CXX") {
+      std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE");
+      iwyu = this->GeneratorTarget->GetProperty(iwyu_prop);
+      std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT");
+      cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
+      std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
+      cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
+    }
     if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
         cmNonempty(cppcheck)) {
       std::string run_iwyu = cmStrCat(cmakeCmd, " -E __run_co_compile");
@@ -887,6 +914,14 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
     compileCmds.front().insert(0, cldeps);
   }
 
+  const auto& extraCommands = this->GetMakefile()->GetSafeDefinition(
+    cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS"));
+  if (!extraCommands.empty()) {
+    auto commandList = cmExpandedList(extraCommands);
+    compileCmds.insert(compileCmds.end(), commandList.cbegin(),
+                       commandList.cend());
+  }
+
   for (std::string& i : compileCmds) {
     i = cmStrCat(launcher, i);
     rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i,
@@ -939,7 +974,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
       config);
   }
   if (firstForConfig) {
-    cmProp pchExtension = GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
+    cmProp pchExtension =
+      this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
 
     std::vector<cmSourceFile const*> externalObjects;
     this->GeneratorTarget->GetExternalObjects(externalObjects, config);
@@ -973,9 +1009,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
       const std::vector<std::string>& ccoutputs = ccg.GetOutputs();
       const std::vector<std::string>& ccbyproducts = ccg.GetByproducts();
       std::transform(ccoutputs.begin(), ccoutputs.end(),
-                     std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+                     std::back_inserter(orderOnlyDeps),
+                     this->MapToNinjaPath());
       std::transform(ccbyproducts.begin(), ccbyproducts.end(),
-                     std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+                     std::back_inserter(orderOnlyDeps),
+                     this->MapToNinjaPath());
     }
 
     std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
@@ -1062,78 +1100,91 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
 }
 
 namespace {
-cmNinjaBuild GetPreprocessOrScanBuild(
-  const std::string& ruleName, const std::string& ppFileName, bool compilePP,
-  bool compilePPWithDefines, cmNinjaBuild& objBuild, cmNinjaVars& vars,
-  const std::string& depFileName, bool needDyndep,
-  const std::string& objectFileName)
+cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
+                                   const std::string& ppFileName,
+                                   bool compilePP, bool compilePPWithDefines,
+                                   cmNinjaBuild& objBuild, cmNinjaVars& vars,
+                                   std::string const& modmapFormat,
+                                   const std::string& objectFileName,
+                                   cmLocalGenerator* lg)
 {
-  // Explicit preprocessing and dependency
-  cmNinjaBuild ppBuild(ruleName);
+  cmNinjaBuild scanBuild(ruleName);
 
   if (!ppFileName.empty()) {
-    ppBuild.Outputs.push_back(ppFileName);
-    ppBuild.RspFile = cmStrCat(ppFileName, ".rsp");
+    scanBuild.RspFile = cmStrCat(ppFileName, ".rsp");
   } else {
-    ppBuild.RspFile = "$out.rsp";
+    scanBuild.RspFile = "$out.rsp";
   }
 
   if (compilePP) {
-    // Move compilation dependencies to the preprocessing build statement.
-    std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps);
-    std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps);
-    std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
-    std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]);
+    // Move compilation dependencies to the scan/preprocessing build statement.
+    std::swap(scanBuild.ExplicitDeps, objBuild.ExplicitDeps);
+    std::swap(scanBuild.ImplicitDeps, objBuild.ImplicitDeps);
+    std::swap(scanBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
+    std::swap(scanBuild.Variables["IN_ABS"], vars["IN_ABS"]);
 
     // The actual compilation will now use the preprocessed source.
     objBuild.ExplicitDeps.push_back(ppFileName);
   } else {
-    // Copy compilation dependencies to the preprocessing build statement.
-    ppBuild.ExplicitDeps = objBuild.ExplicitDeps;
-    ppBuild.ImplicitDeps = objBuild.ImplicitDeps;
-    ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
-    ppBuild.Variables["IN_ABS"] = vars["IN_ABS"];
+    // Copy compilation dependencies to the scan/preprocessing build statement.
+    scanBuild.ExplicitDeps = objBuild.ExplicitDeps;
+    scanBuild.ImplicitDeps = objBuild.ImplicitDeps;
+    scanBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
+    scanBuild.Variables["IN_ABS"] = vars["IN_ABS"];
   }
 
-  // Preprocessing and compilation generally use the same flags.
-  ppBuild.Variables["FLAGS"] = vars["FLAGS"];
+  // Scanning and compilation generally use the same flags.
+  scanBuild.Variables["FLAGS"] = vars["FLAGS"];
 
   if (compilePP && !compilePPWithDefines) {
-    // Move preprocessor definitions to the preprocessor build statement.
-    std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]);
+    // Move preprocessor definitions to the scan/preprocessor build statement.
+    std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]);
   } else {
-    // Copy preprocessor definitions to the preprocessor build statement.
-    ppBuild.Variables["DEFINES"] = vars["DEFINES"];
+    // Copy preprocessor definitions to the scan/preprocessor build statement.
+    scanBuild.Variables["DEFINES"] = vars["DEFINES"];
   }
 
   // Copy include directories to the preprocessor build statement.  The
   // Fortran compilation build statement still needs them for the INCLUDE
   // directive.
-  ppBuild.Variables["INCLUDES"] = vars["INCLUDES"];
+  scanBuild.Variables["INCLUDES"] = vars["INCLUDES"];
 
-  // Explicit preprocessing always uses a depfile.
-  ppBuild.Variables["DEP_FILE"] = depFileName;
+  // Tell dependency scanner the object file that will result from
+  // compiling the source.
+  scanBuild.Variables["OBJ_FILE"] = objectFileName;
+
+  // Tell dependency scanner where to store dyndep intermediate results.
+  std::string const& ddiFile = cmStrCat(objectFileName, ".ddi");
+  scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+
+  // Outputs of the scan/preprocessor build statement.
+  if (!ppFileName.empty()) {
+    scanBuild.Outputs.push_back(ppFileName);
+    scanBuild.ImplicitOuts.push_back(ddiFile);
+  } else {
+    scanBuild.Outputs.push_back(ddiFile);
+  }
+
+  // Scanning always uses a depfile for preprocessor dependencies.
+  std::string const& depFileName = cmStrCat(scanBuild.Outputs.front(), ".d");
+  scanBuild.Variables["DEP_FILE"] =
+    lg->ConvertToOutputFormat(depFileName, cmOutputConverter::SHELL);
   if (compilePP) {
     // The actual compilation does not need a depfile because it
     // depends on the already-preprocessed source.
     vars.erase("DEP_FILE");
   }
 
-  if (needDyndep) {
-    // Tell dependency scanner the object file that will result from
-    // compiling the source.
-    ppBuild.Variables["OBJ_FILE"] = objectFileName;
-
-    // Tell dependency scanner where to store dyndep intermediate results.
-    std::string const ddiFile = cmStrCat(objectFileName, ".ddi");
-    if (ppFileName.empty()) {
-      ppBuild.Outputs.push_back(ddiFile);
-    } else {
-      ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
-      ppBuild.ImplicitOuts.push_back(ddiFile);
-    }
+  if (!modmapFormat.empty()) {
+    // XXX(modmap): If changing this path construction, change
+    // `cmGlobalNinjaGenerator::WriteDyndep` to expect the corresponding
+    // file path.
+    std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap");
+    scanBuild.Variables["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
+    scanBuild.ImplicitOuts.push_back(ddModmapFile);
   }
-  return ppBuild;
+
+  return scanBuild;
 }
 }
 
@@ -1157,7 +1208,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
   // build response file name
   std::string cmakeLinkVar = cmStrCat(cmakeVarLang, "_RESPONSE_FILE_FLAG");
 
-  cmProp flag = GetMakefile()->GetDefinition(cmakeLinkVar);
+  cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
 
   bool const lang_supports_response =
     !(language == "RC" || (language == "CUDA" && !flag));
@@ -1170,7 +1221,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
   vars["DEFINES"] = this->ComputeDefines(source, language, config);
   vars["INCLUDES"] = this->ComputeIncludes(source, language, config);
 
-  if (!this->NeedDepTypeMSVC(language)) {
+  if (this->GetMakefile()->GetSafeDefinition(
+        cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT")) != "msvc"_s) {
     bool replaceExt(false);
     if (!language.empty()) {
       std::string repVar =
@@ -1253,7 +1305,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
     }
     std::transform(depList.begin(), depList.end(),
                    std::back_inserter(objBuild.ImplicitDeps),
-                   MapToNinjaPath());
+                   this->MapToNinjaPath());
   }
 
   objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config));
@@ -1270,13 +1322,19 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       sourceFileName, objBuild.OrderOnlyDeps);
   }
 
-  // For some cases we need to generate a ninja dyndep file.
-  bool const needDyndep = this->NeedDyndep(language);
+  // For some cases we scan to dynamically discover dependencies.
+  bool const needDyndep = this->NeedDyndep(language, config);
+  bool const compilationPreprocesses =
+    !this->NeedExplicitPreprocessing(language);
 
-  // For some cases we do an explicit preprocessor invocation.
-  bool const explicitPP = this->NeedExplicitPreprocessing(language);
-  if (explicitPP) {
+  std::string modmapFormat;
+  if (needDyndep) {
+    std::string const modmapFormatVar =
+      cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT");
+    modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar);
+  }
 
+  if (needDyndep) {
     // If source/target has preprocessing turned off, we still need to
     // generate an explicit dependency step
     const auto srcpp = source->GetSafeProperty("Fortran_PREPROCESS");
@@ -1288,27 +1346,24 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
     }
 
-    bool const compilePP = this->UsePreprocessedSource(language) &&
+    bool const compilePP = !compilationPreprocesses &&
       (preprocess != cmOutputConverter::FortranPreprocess::NotNeeded);
     bool const compilePPWithDefines =
-      compilePP && this->CompilePreprocessedSourceWithDefines(language);
-
-    std::string const ppFileName = compilePP
-      ? this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config))
-      : "";
+      compilePP && this->CompileWithDefines(language);
 
-    std::string const buildName = compilePP
-      ? this->LanguagePreprocessRule(language, config)
-      : this->LanguageDependencyRule(language, config);
-
-    const auto depExtension = compilePP ? ".pp.d" : ".d";
-    const std::string depFileName =
-      this->GetLocalGenerator()->ConvertToOutputFormat(
-        cmStrCat(objectFileName, depExtension), cmOutputConverter::SHELL);
+    std::string scanRuleName;
+    std::string ppFileName;
+    if (compilePP) {
+      scanRuleName = this->LanguagePreprocessAndScanRule(language, config);
+      ppFileName = this->ConvertToNinjaPath(
+        this->GetPreprocessedFilePath(source, config));
+    } else {
+      scanRuleName = this->LanguageScanRule(language, config);
+    }
 
-    cmNinjaBuild ppBuild = GetPreprocessOrScanBuild(
-      buildName, ppFileName, compilePP, compilePPWithDefines, objBuild, vars,
-      depFileName, needDyndep, objectFileName);
+    cmNinjaBuild ppBuild = GetScanBuildStatement(
+      scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild,
+      vars, modmapFormat, objectFileName, this->LocalGenerator);
 
     if (compilePP) {
       // In case compilation requires flags that are incompatible with
@@ -1330,7 +1385,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]);
     }
 
-    if (firstForConfig && needDyndep) {
+    if (firstForConfig) {
       std::string const ddiFile = cmStrCat(objectFileName, ".ddi");
       this->Configs[config].DDIFiles[language].push_back(ddiFile);
     }
@@ -1340,14 +1395,19 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 
     this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
                                            ppBuild, commandLineLengthLimit);
-  }
-  if (needDyndep) {
+
     std::string const dyndep = this->GetDyndepFilePath(language, config);
     objBuild.OrderOnlyDeps.push_back(dyndep);
     vars["dyndep"] = dyndep;
+
+    if (!modmapFormat.empty()) {
+      std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap");
+      vars["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
+      objBuild.OrderOnlyDeps.push_back(ddModmapFile);
+    }
   }
 
-  EnsureParentDirectoryExists(objectFileName);
+  this->EnsureParentDirectoryExists(objectFileName);
 
   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     objectDir, cmOutputConverter::SHELL);
@@ -1420,7 +1480,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
     auto headers = this->GeneratorTarget->GetGeneratedISPCHeaders(config);
     if (!headers.empty()) {
       std::transform(headers.begin(), headers.end(), headers.begin(),
-                     MapToNinjaPath());
+                     this->MapToNinjaPath());
       objBuild.OrderOnlyDeps.insert(objBuild.OrderOnlyDeps.end(),
                                     headers.begin(), headers.end());
     }
@@ -1442,7 +1502,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
       build.Comment = "Additional output files.";
       build.Outputs = cmExpandedList(evaluatedObjectOutputs);
       std::transform(build.Outputs.begin(), build.Outputs.end(),
-                     build.Outputs.begin(), MapToNinjaPath());
+                     build.Outputs.begin(), this->MapToNinjaPath());
       build.ExplicitDeps = objBuild.Outputs;
       this->GetGlobalGenerator()->WriteBuild(
         this->GetImplFileStream(fileConfig), build);
@@ -1458,17 +1518,26 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
   tdi["compiler-id"] = this->Makefile->GetSafeDefinition(
     cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
 
+  std::string mod_dir;
   if (lang == "Fortran") {
-    std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
+    mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
       this->Makefile->GetHomeOutputDirectory());
-    if (mod_dir.empty()) {
-      mod_dir = this->Makefile->GetCurrentBinaryDirectory();
-    }
-    tdi["module-dir"] = mod_dir;
+  } else if (lang == "CXX") {
+    mod_dir =
+      cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory);
+  }
+  if (mod_dir.empty()) {
+    mod_dir = this->Makefile->GetCurrentBinaryDirectory();
+  }
+  tdi["module-dir"] = mod_dir;
+
+  if (lang == "Fortran") {
     tdi["submodule-sep"] =
       this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
     tdi["submodule-ext"] =
       this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
+  } else if (lang == "CXX") {
+    // No extra information necessary.
   }
 
   tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();
@@ -1550,7 +1619,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
   std::string const& objectFileDir, std::string const& flags,
   std::string const& defines, std::string const& includes)
 {
-  if (!this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS")) {
+  if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) {
     return;
   }
 
@@ -1662,7 +1731,7 @@ void cmNinjaTargetGenerator::EnsureDirectoryExists(
 void cmNinjaTargetGenerator::EnsureParentDirectoryExists(
   const std::string& path) const
 {
-  EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path));
+  this->EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path));
 }
 
 void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
index a27c9b4..79dc622 100644 (file)
@@ -42,8 +42,6 @@ public:
 
   std::string GetTargetName() const;
 
-  bool NeedDepTypeMSVC(const std::string& lang) const;
-
 protected:
   bool SetMsvcTargetPdbVariable(cmNinjaVars&, const std::string& config) const;
 
@@ -67,16 +65,17 @@ protected:
 
   std::string LanguageCompilerRule(const std::string& lang,
                                    const std::string& config) const;
-  std::string LanguagePreprocessRule(std::string const& lang,
-                                     const std::string& config) const;
-  std::string LanguageDependencyRule(std::string const& lang,
-                                     const std::string& config) const;
-  bool NeedExplicitPreprocessing(std::string const& lang) const;
+  std::string LanguagePreprocessAndScanRule(std::string const& lang,
+                                            const std::string& config) const;
+  std::string LanguageScanRule(std::string const& lang,
+                               const std::string& config) const;
   std::string LanguageDyndepRule(std::string const& lang,
                                  const std::string& config) const;
-  bool NeedDyndep(std::string const& lang) const;
-  bool UsePreprocessedSource(std::string const& lang) const;
-  bool CompilePreprocessedSourceWithDefines(std::string const& lang) const;
+  bool NeedDyndep(std::string const& lang, std::string const& config) const;
+  bool NeedExplicitPreprocessing(std::string const& lang) const;
+  bool CompileWithDefines(std::string const& lang) const;
+  bool NeedCxxModuleSupport(std::string const& lang,
+                            std::string const& config) const;
 
   std::string OrderDependsTargetForTarget(const std::string& config);
 
index ad1d5f1..a18ca20 100644 (file)
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <array>
 #include <iterator>
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -34,13 +35,35 @@ cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
 
 void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
 {
+  if (!this->GetGeneratorTarget()->Target->IsPerConfig()) {
+    this->WriteUtilBuildStatements(config, config);
+    return;
+  }
+
+  for (auto const& fileConfig : this->GetConfigNames()) {
+    if (!this->GetGlobalGenerator()
+           ->GetCrossConfigs(fileConfig)
+           .count(config)) {
+      continue;
+    }
+    if (fileConfig != config &&
+        this->GetGeneratorTarget()->GetType() == cmStateEnums::GLOBAL_TARGET) {
+      continue;
+    }
+    this->WriteUtilBuildStatements(config, fileConfig);
+  }
+}
+
+void cmNinjaUtilityTargetGenerator::WriteUtilBuildStatements(
+  std::string const& config, std::string const& fileConfig)
+{
   cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
   cmLocalNinjaGenerator* lg = this->GetLocalGenerator();
   cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
 
   std::string configDir;
   if (genTarget->Target->IsPerConfig()) {
-    configDir = gg->ConfigDirectory(config);
+    configDir = gg->ConfigDirectory(fileConfig);
   }
   std::string utilCommandName =
     cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles", configDir, "/",
@@ -60,12 +83,13 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
 
     for (std::vector<cmCustomCommand> const* cmdList : cmdLists) {
       for (cmCustomCommand const& ci : *cmdList) {
-        cmCustomCommandGenerator ccg(ci, config, lg);
-        lg->AppendCustomCommandDeps(ccg, deps, config);
+        cmCustomCommandGenerator ccg(ci, fileConfig, lg);
+        lg->AppendCustomCommandDeps(ccg, deps, fileConfig);
         lg->AppendCustomCommandLines(ccg, commands);
         std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
         std::transform(ccByproducts.begin(), ccByproducts.end(),
-                       std::back_inserter(util_outputs), MapToNinjaPath());
+                       std::back_inserter(util_outputs),
+                       this->MapToNinjaPath());
         if (ci.GetUsesTerminal()) {
           uses_terminal = true;
         }
@@ -85,9 +109,9 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
         const std::vector<std::string>& ccOutputs = ccg.GetOutputs();
         const std::vector<std::string>& ccByproducts = ccg.GetByproducts();
         std::transform(ccOutputs.begin(), ccOutputs.end(),
-                       std::back_inserter(deps), MapToNinjaPath());
+                       std::back_inserter(deps), this->MapToNinjaPath());
         std::transform(ccByproducts.begin(), ccByproducts.end(),
-                       std::back_inserter(deps), MapToNinjaPath());
+                       std::back_inserter(deps), this->MapToNinjaPath());
       }
     }
   }
@@ -103,13 +127,17 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
     std::copy(util_outputs.begin(), util_outputs.end(),
               std::back_inserter(gg->GetByproductsForCleanTarget()));
   }
-  lg->AppendTargetDepends(genTarget, deps, config, config,
+  lg->AppendTargetDepends(genTarget, deps, config, fileConfig,
                           DependOnTargetArtifact);
 
   if (commands.empty()) {
     phonyBuild.Comment = "Utility command for " + this->GetTargetName();
     phonyBuild.ExplicitDeps = std::move(deps);
-    gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+    if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+      gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild);
+    } else {
+      gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+    }
   } else {
     std::string command =
       lg->BuildCommandLine(commands, "utility", this->GeneratorTarget);
@@ -145,15 +173,22 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
     std::string ccConfig;
     if (genTarget->Target->IsPerConfig() &&
         genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
-      ccConfig = config;
+      ccConfig = fileConfig;
+    }
+    if (config == fileConfig ||
+        gg->GetPerConfigUtilityTargets().count(genTarget->GetName())) {
+      gg->WriteCustomCommandBuild(
+        command, desc, "Utility command for " + this->GetTargetName(),
+        /*depfile*/ "", /*job_pool*/ "", uses_terminal,
+        /*restat*/ true, util_outputs, ccConfig, deps);
     }
-    gg->WriteCustomCommandBuild(command, desc,
-                                "Utility command for " + this->GetTargetName(),
-                                /*depfile*/ "", /*job_pool*/ "", uses_terminal,
-                                /*restat*/ true, util_outputs, ccConfig, deps);
 
     phonyBuild.ExplicitDeps.push_back(utilCommandName);
-    gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+    if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+      gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild);
+    } else {
+      gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+    }
   }
 
   // Find ADDITIONAL_CLEAN_FILES
index 24b47f8..dbd3797 100644 (file)
@@ -17,4 +17,8 @@ public:
   ~cmNinjaUtilityTargetGenerator() override;
 
   void Generate(const std::string& config) override;
+
+private:
+  void WriteUtilBuildStatements(std::string const& config,
+                                std::string const& fileConfig);
 };
index 4c33fcc..a3b6f98 100644 (file)
@@ -62,7 +62,6 @@ public:
 private:
   bool MustSkip();
 
-private:
   cmGeneratorTarget* GT;
   cmMakefile* Makefile;
   cmLocalGenerator* LocalGenerator;
index 359e9f5..ec54537 100644 (file)
@@ -121,7 +121,7 @@ std::string cmOutputConverter::EscapeForShell(
     flags |= Shell_Flag_IsUnix;
   }
 
-  return Shell__GetArgument(str, flags);
+  return Shell_GetArgument(str, flags);
 }
 
 std::string cmOutputConverter::EscapeForCMake(cm::string_view str)
@@ -150,7 +150,7 @@ std::string cmOutputConverter::EscapeForCMake(cm::string_view str)
 std::string cmOutputConverter::EscapeWindowsShellArgument(cm::string_view arg,
                                                           int shell_flags)
 {
-  return Shell__GetArgument(arg, shell_flags);
+  return Shell_GetArgument(arg, shell_flags);
 }
 
 cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat(
@@ -226,12 +226,12 @@ use the caret character itself (^), use two in a row (^^).
 */
 
 /* Some helpers to identify character classes */
-static bool Shell__CharIsWhitespace(char c)
+static bool Shell_CharIsWhitespace(char c)
 {
   return ((c == ' ') || (c == '\t'));
 }
 
-static bool Shell__CharNeedsQuotesOnUnix(char c)
+static bool Shell_CharNeedsQuotesOnUnix(char c)
 {
   return ((c == '\'') || (c == '`') || (c == ';') || (c == '#') ||
           (c == '&') || (c == '$') || (c == '(') || (c == ')') || (c == '~') ||
@@ -239,18 +239,18 @@ static bool Shell__CharNeedsQuotesOnUnix(char c)
           (c == '\\'));
 }
 
-static bool Shell__CharNeedsQuotesOnWindows(char c)
+static bool Shell_CharNeedsQuotesOnWindows(char c)
 {
   return ((c == '\'') || (c == '#') || (c == '&') || (c == '<') ||
           (c == '>') || (c == '|') || (c == '^'));
 }
 
-static bool Shell__CharIsMakeVariableName(char c)
+static bool Shell_CharIsMakeVariableName(char c)
 {
   return c && (c == '_' || isalpha((static_cast<int>(c))));
 }
 
-bool cmOutputConverter::Shell__CharNeedsQuotes(char c, int flags)
+bool cmOutputConverter::Shell_CharNeedsQuotes(char c, int flags)
 {
   /* On Windows the built-in command shell echo never needs quotes.  */
   if (!(flags & Shell_Flag_IsUnix) && (flags & Shell_Flag_EchoWindows)) {
@@ -258,30 +258,30 @@ bool cmOutputConverter::Shell__CharNeedsQuotes(char c, int flags)
   }
 
   /* On all platforms quotes are needed to preserve whitespace.  */
-  if (Shell__CharIsWhitespace(c)) {
+  if (Shell_CharIsWhitespace(c)) {
     return true;
   }
 
   if (flags & Shell_Flag_IsUnix) {
     /* On UNIX several special characters need quotes to preserve them.  */
-    if (Shell__CharNeedsQuotesOnUnix(c)) {
+    if (Shell_CharNeedsQuotesOnUnix(c)) {
       return true;
     }
   } else {
     /* On Windows several special characters need quotes to preserve them.  */
-    if (Shell__CharNeedsQuotesOnWindows(c)) {
+    if (Shell_CharNeedsQuotesOnWindows(c)) {
       return true;
     }
   }
   return false;
 }
 
-cm::string_view::iterator cmOutputConverter::Shell__SkipMakeVariables(
+cm::string_view::iterator cmOutputConverter::Shell_SkipMakeVariables(
   cm::string_view::iterator c, cm::string_view::iterator end)
 {
   while ((c != end && (c + 1) != end) && (*c == '$' && *(c + 1) == '(')) {
     cm::string_view::iterator skip = c + 2;
-    while ((skip != end) && Shell__CharIsMakeVariableName(*skip)) {
+    while ((skip != end) && Shell_CharIsMakeVariableName(*skip)) {
       ++skip;
     }
     if ((skip != end) && *skip == ')') {
@@ -316,8 +316,8 @@ flag later when we understand applications of this better.
 */
 #define KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES 0
 
-bool cmOutputConverter::Shell__ArgumentNeedsQuotes(cm::string_view in,
-                                                   int flags)
+bool cmOutputConverter::Shell_ArgumentNeedsQuotes(cm::string_view in,
+                                                  int flags)
 {
   /* The empty string needs quotes.  */
   if (in.empty()) {
@@ -330,7 +330,7 @@ bool cmOutputConverter::Shell__ArgumentNeedsQuotes(cm::string_view in,
     /* Look for $(MAKEVAR) syntax if requested.  */
     if (flags & Shell_Flag_AllowMakeVariables) {
 #if KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES
-      cm::string_view::iterator skip = Shell__SkipMakeVariables(cit, cend);
+      cm::string_view::iterator skip = Shell_SkipMakeVariables(cit, cend);
       if (skip != cit) {
         /* We need to quote make variable references to preserve the
            string with contents substituted in its place.  */
@@ -338,7 +338,7 @@ bool cmOutputConverter::Shell__ArgumentNeedsQuotes(cm::string_view in,
       }
 #else
       /* Skip over the make variable references if any are present.  */
-      cit = Shell__SkipMakeVariables(cit, cend);
+      cit = Shell_SkipMakeVariables(cit, cend);
 
       /* Stop if we have reached the end of the string.  */
       if (cit == cend) {
@@ -348,7 +348,7 @@ bool cmOutputConverter::Shell__ArgumentNeedsQuotes(cm::string_view in,
     }
 
     /* Check whether this character needs quotes.  */
-    if (Shell__CharNeedsQuotes(*cit, flags)) {
+    if (Shell_CharNeedsQuotes(*cit, flags)) {
       return true;
     }
   }
@@ -364,8 +364,7 @@ bool cmOutputConverter::Shell__ArgumentNeedsQuotes(cm::string_view in,
   return false;
 }
 
-std::string cmOutputConverter::Shell__GetArgument(cm::string_view in,
-                                                  int flags)
+std::string cmOutputConverter::Shell_GetArgument(cm::string_view in, int flags)
 {
   /* Output will be at least as long as input string.  */
   std::string out;
@@ -375,7 +374,7 @@ std::string cmOutputConverter::Shell__GetArgument(cm::string_view in,
   int windows_backslashes = 0;
 
   /* Whether the argument must be quoted.  */
-  int needQuotes = Shell__ArgumentNeedsQuotes(in, flags);
+  int needQuotes = Shell_ArgumentNeedsQuotes(in, flags);
   if (needQuotes) {
     /* Add the opening quote for this argument.  */
     if (flags & Shell_Flag_WatcomQuote) {
@@ -393,7 +392,7 @@ std::string cmOutputConverter::Shell__GetArgument(cm::string_view in,
        cit != cend; ++cit) {
     /* Look for $(MAKEVAR) syntax if requested.  */
     if (flags & Shell_Flag_AllowMakeVariables) {
-      cm::string_view::iterator skip = Shell__SkipMakeVariables(cit, cend);
+      cm::string_view::iterator skip = Shell_SkipMakeVariables(cit, cend);
       if (skip != cit) {
         /* Copy to the end of the make variable references.  */
         while (cit != skip) {
index 655bc87..f1a8041 100644 (file)
@@ -105,13 +105,12 @@ public:
 private:
   cmState* GetState() const;
 
-  static bool Shell__CharNeedsQuotes(char c, int flags);
-  static cm::string_view::iterator Shell__SkipMakeVariables(
+  static bool Shell_CharNeedsQuotes(char c, int flags);
+  static cm::string_view::iterator Shell_SkipMakeVariables(
     cm::string_view::iterator begin, cm::string_view::iterator end);
-  static bool Shell__ArgumentNeedsQuotes(cm::string_view in, int flags);
-  static std::string Shell__GetArgument(cm::string_view in, int flags);
+  static bool Shell_ArgumentNeedsQuotes(cm::string_view in, int flags);
+  static std::string Shell_GetArgument(cm::string_view in, int flags);
 
-private:
   cmStateSnapshot StateSnapshot;
 
   bool LinkScriptShell;
index aa5abcb..d589614 100644 (file)
@@ -376,7 +376,7 @@ protected:
     }
     // Didn't find an instance.  Create a new one and save it.
     auto info = cm::make_unique<cmDependInformation>();
-    auto ptr = info.get();
+    auto* ptr = info.get();
     info->FullPath = fullPath;
     info->PathOnly = cmSystemTools::GetFilenamePath(fullPath);
     info->IncludeName = file;
diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx
deleted file mode 100644 (file)
index 1eede13..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmPipeConnection.h"
-
-#include <utility>
-
-#include "cmServer.h"
-
-cmPipeConnection::cmPipeConnection(std::string name,
-                                   cmConnectionBufferStrategy* bufferStrategy)
-  : cmEventBasedConnection(bufferStrategy)
-  , PipeName(std::move(name))
-{
-}
-
-void cmPipeConnection::Connect(uv_stream_t* server)
-{
-  if (this->WriteStream.get()) {
-    // Accept and close all pipes but the first:
-    cm::uv_pipe_ptr rejectPipe;
-
-    rejectPipe.init(*this->Server->GetLoop(), 0);
-    uv_accept(server, rejectPipe);
-
-    return;
-  }
-
-  cm::uv_pipe_ptr ClientPipe;
-  ClientPipe.init(*this->Server->GetLoop(), 0,
-                  static_cast<cmEventBasedConnection*>(this));
-
-  if (uv_accept(server, ClientPipe) != 0) {
-    return;
-  }
-
-  uv_read_start(ClientPipe, on_alloc_buffer, on_read);
-  WriteStream = std::move(ClientPipe);
-  Server->OnConnected(this);
-}
-
-bool cmPipeConnection::OnServeStart(std::string* errorMessage)
-{
-  this->ServerPipe.init(*this->Server->GetLoop(), 0,
-                        static_cast<cmEventBasedConnection*>(this));
-
-  int r;
-  if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) {
-    *errorMessage = std::string("Internal Error with ") + this->PipeName +
-      ": " + uv_err_name(r);
-    return false;
-  }
-
-  if ((r = uv_listen(this->ServerPipe, 1, on_new_connection)) != 0) {
-    *errorMessage = std::string("Internal Error listening on ") +
-      this->PipeName + ": " + uv_err_name(r);
-    return false;
-  }
-
-  return cmConnection::OnServeStart(errorMessage);
-}
-
-bool cmPipeConnection::OnConnectionShuttingDown()
-{
-  if (this->WriteStream.get()) {
-    this->WriteStream->data = nullptr;
-  }
-
-  this->ServerPipe.reset();
-
-  return cmEventBasedConnection::OnConnectionShuttingDown();
-}
diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h
deleted file mode 100644 (file)
index 1215716..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <string>
-
-#include <cm3p/uv.h>
-
-#include "cmConnection.h"
-#include "cmUVHandlePtr.h"
-
-class cmPipeConnection : public cmEventBasedConnection
-{
-public:
-  cmPipeConnection(std::string name,
-                   cmConnectionBufferStrategy* bufferStrategy = nullptr);
-
-  bool OnServeStart(std::string* pString) override;
-
-  bool OnConnectionShuttingDown() override;
-
-  void Connect(uv_stream_t* server) override;
-
-private:
-  const std::string PipeName;
-  cm::uv_pipe_ptr ServerPipe;
-};
index 18ce9c3..2194b0f 100644 (file)
@@ -340,6 +340,25 @@ class cmMakefile;
          3, 19, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0114,                                                     \
          "ExternalProject step targets fully adopt their steps.", 3, 19, 0,   \
+         cmPolicies::WARN)                                                    \
+  SELECT(POLICY, CMP0115, "Source file extensions must be explicit.", 3, 20,  \
+         0, cmPolicies::WARN)                                                 \
+  SELECT(POLICY, CMP0116,                                                     \
+         "Ninja generators transform DEPFILEs from add_custom_command().", 3, \
+         20, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0117,                                                     \
+         "MSVC RTTI flag /GR is not added to CMAKE_CXX_FLAGS by default.", 3, \
+         20, 0, cmPolicies::WARN)                                             \
+  SELECT(                                                                     \
+    POLICY, CMP0118,                                                          \
+    "The GENERATED source file property is now visible in all directories.",  \
+    3, 20, 0, cmPolicies::WARN)                                               \
+  SELECT(POLICY, CMP0119,                                                     \
+         "LANGUAGE source file property explicitly compiles as specified "    \
+         "language.",                                                         \
+         3, 20, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0120,                                                     \
+         "The WriteCompilerDetectionHeader module is removed.", 3, 20, 0,     \
          cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
@@ -375,7 +394,8 @@ class cmMakefile;
   F(CMP0105)                                                                  \
   F(CMP0108)                                                                  \
   F(CMP0112)                                                                  \
-  F(CMP0113)
+  F(CMP0113)                                                                  \
+  F(CMP0119)
 
 /** \class cmPolicies
  * \brief Handles changes in CMake behavior and policies
index 0fb4ff7..10c4215 100644 (file)
@@ -51,8 +51,6 @@ cmProcessOutput::cmProcessOutput(Encoding encoding, unsigned int maxSize)
 #endif
 }
 
-cmProcessOutput::~cmProcessOutput() = default;
-
 bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded,
                                  size_t id)
 {
@@ -126,7 +124,7 @@ bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded,
 bool cmProcessOutput::DecodeText(const char* data, size_t length,
                                  std::string& decoded, size_t id)
 {
-  return DecodeText(std::string(data, length), decoded, id);
+  return this->DecodeText(std::string(data, length), decoded, id);
 }
 
 bool cmProcessOutput::DecodeText(std::vector<char> raw,
@@ -134,7 +132,7 @@ bool cmProcessOutput::DecodeText(std::vector<char> raw,
 {
   std::string str;
   const bool success =
-    DecodeText(std::string(raw.begin(), raw.end()), str, id);
+    this->DecodeText(std::string(raw.begin(), raw.end()), str, id);
   decoded.assign(str.begin(), str.end());
   return success;
 }
index a1f73bd..8cee987 100644 (file)
@@ -47,7 +47,7 @@ public:
    * 0 as \a maxSize.
    */
   cmProcessOutput(Encoding encoding = Auto, unsigned int maxSize = 1024);
-  ~cmProcessOutput();
+  ~cmProcessOutput() = default;
   /**
    * Decode \a raw string using external encoding to internal
    * encoding in \a decoded.
index 0cfba63..ed32de9 100644 (file)
@@ -358,6 +358,17 @@ static bool IncludeByVariable(cmExecutionStatus& status,
     return true;
   }
 
+  std::string includeFile =
+    cmSystemTools::CollapseFullPath(*include, mf.GetCurrentSourceDirectory());
+  if (!cmSystemTools::FileExists(includeFile)) {
+    status.SetError(cmStrCat("could not find requested file:\n  ", *include));
+    return false;
+  }
+  if (cmSystemTools::FileIsDirectory(includeFile)) {
+    status.SetError(cmStrCat("requested file is a directory:\n  ", *include));
+    return false;
+  }
+
   const bool readit = mf.ReadDependentFile(*include);
   if (readit) {
     return true;
@@ -367,7 +378,7 @@ static bool IncludeByVariable(cmExecutionStatus& status,
     return true;
   }
 
-  status.SetError(cmStrCat("could not find file:\n  ", *include));
+  status.SetError(cmStrCat("could not load requested file:\n  ", *include));
   return false;
 }
 
index f22f36d..06e151a 100644 (file)
@@ -7,17 +7,17 @@
 
 void cmPropertyMap::Clear()
 {
-  Map_.clear();
+  this->Map_.clear();
 }
 
 void cmPropertyMap::SetProperty(const std::string& name, const char* value)
 {
   if (!value) {
-    Map_.erase(name);
+    this->Map_.erase(name);
     return;
   }
 
-  Map_[name] = value;
+  this->Map_[name] = value;
 }
 
 void cmPropertyMap::AppendProperty(const std::string& name,
@@ -29,7 +29,7 @@ void cmPropertyMap::AppendProperty(const std::string& name,
   }
 
   {
-    std::string& pVal = Map_[name];
+    std::string& pVal = this->Map_[name];
     if (!pVal.empty() && !asString) {
       pVal += ';';
     }
@@ -39,13 +39,13 @@ void cmPropertyMap::AppendProperty(const std::string& name,
 
 void cmPropertyMap::RemoveProperty(const std::string& name)
 {
-  Map_.erase(name);
+  this->Map_.erase(name);
 }
 
 cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const
 {
-  auto it = Map_.find(name);
-  if (it != Map_.end()) {
+  auto it = this->Map_.find(name);
+  if (it != this->Map_.end()) {
     return &it->second;
   }
   return nullptr;
@@ -54,8 +54,8 @@ cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const
 std::vector<std::string> cmPropertyMap::GetKeys() const
 {
   std::vector<std::string> keyList;
-  keyList.reserve(Map_.size());
-  for (auto const& item : Map_) {
+  keyList.reserve(this->Map_.size());
+  for (auto const& item : this->Map_) {
     keyList.push_back(item.first);
   }
   std::sort(keyList.begin(), keyList.end());
@@ -66,8 +66,8 @@ std::vector<std::pair<std::string, std::string>> cmPropertyMap::GetList() const
 {
   using StringPair = std::pair<std::string, std::string>;
   std::vector<StringPair> kvList;
-  kvList.reserve(Map_.size());
-  for (auto const& item : Map_) {
+  kvList.reserve(this->Map_.size());
+  for (auto const& item : this->Map_) {
     kvList.emplace_back(item.first, item.second);
   }
   std::sort(kvList.begin(), kvList.end(),
index de462db..e9670f9 100644 (file)
@@ -5,6 +5,7 @@
 #include "cmCustomCommandLines.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmPolicies.h"
 #include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
@@ -40,8 +41,7 @@ bool cmQTWrapCPPCommand(std::vector<std::string> const& args,
         cmStrCat(mf.GetCurrentBinaryDirectory(), "/moc_", srcName, ".cxx");
       cmSourceFile* sf = mf.GetOrCreateSource(newName, true);
       if (curr) {
-        cmProp p = curr->GetProperty("ABSTRACT");
-        sf->SetProperty("ABSTRACT", cmToCStr(p));
+        sf->SetProperty("ABSTRACT", cmToCStr(curr->GetProperty("ABSTRACT")));
       }
 
       // Compute the name of the header from which to generate the file.
@@ -74,9 +74,9 @@ bool cmQTWrapCPPCommand(std::vector<std::string> const& args,
 
       std::string no_main_dependency;
       const char* no_working_dir = nullptr;
-      mf.AddCustomCommandToOutput(newName, depends, no_main_dependency,
-                                  commandLines, "Qt Wrapped File",
-                                  no_working_dir);
+      mf.AddCustomCommandToOutput(
+        newName, depends, no_main_dependency, commandLines, "Qt Wrapped File",
+        no_working_dir, mf.GetPolicyStatus(cmPolicies::CMP0116));
     }
   }
 
index 66c0228..f98f0b3 100644 (file)
@@ -5,6 +5,7 @@
 #include "cmCustomCommandLines.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmPolicies.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
@@ -87,16 +88,19 @@ bool cmQTWrapUICommand(std::vector<std::string> const& args,
       const char* no_comment = nullptr;
       const char* no_working_dir = nullptr;
       mf.AddCustomCommandToOutput(hName, depends, no_main_dependency,
-                                  hCommandLines, no_comment, no_working_dir);
+                                  hCommandLines, no_comment, no_working_dir,
+                                  mf.GetPolicyStatus(cmPolicies::CMP0116));
 
       depends.push_back(hName);
       mf.AddCustomCommandToOutput(cxxName, depends, no_main_dependency,
-                                  cxxCommandLines, no_comment, no_working_dir);
+                                  cxxCommandLines, no_comment, no_working_dir,
+                                  mf.GetPolicyStatus(cmPolicies::CMP0116));
 
       depends.clear();
       depends.push_back(hName);
       mf.AddCustomCommandToOutput(mocName, depends, no_main_dependency,
-                                  mocCommandLines, no_comment, no_working_dir);
+                                  mocCommandLines, no_comment, no_working_dir,
+                                  mf.GetPolicyStatus(cmPolicies::CMP0116));
     }
   }
 
index cf90417..466a954 100644 (file)
@@ -29,13 +29,13 @@ public:
     {
     }
 
-    bool operator>(IntegerVersion const version)
+    bool operator>(IntegerVersion const version) const
     {
       return (this->Major > version.Major) ||
         ((this->Major == version.Major) && (this->Minor > version.Minor));
     }
 
-    bool operator>=(IntegerVersion const version)
+    bool operator>=(IntegerVersion const version) const
     {
       return (this->Major > version.Major) ||
         ((this->Major == version.Major) && (this->Minor >= version.Minor));
@@ -64,7 +64,6 @@ public:
   /// @brief Maximum number of parallel threads/processes in a generator
   static unsigned int const ParallelMax;
 
-public:
   /// @brief Returns the generator name
   static cm::string_view GeneratorName(GenT genType);
   /// @brief Returns the generator name in upper case
@@ -111,20 +110,20 @@ public:
     RccLister(std::string rccExecutable, std::vector<std::string> listOptions);
 
     //! The rcc executable
-    std::string const& RccExcutable() const { return RccExcutable_; }
+    std::string const& RccExcutable() const { return this->RccExcutable_; }
     void SetRccExecutable(std::string const& rccExecutable)
     {
-      RccExcutable_ = rccExecutable;
+      this->RccExcutable_ = rccExecutable;
     }
 
     //! The rcc executable list options
     std::vector<std::string> const& ListOptions() const
     {
-      return ListOptions_;
+      return this->ListOptions_;
     }
     void SetListOptions(std::vector<std::string> const& listOptions)
     {
-      ListOptions_ = listOptions;
+      this->ListOptions_ = listOptions;
     }
 
     /**
index fac2bbf..f79ffd4 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmQtAutoGenGlobalInitializer.h"
 
+#include <set>
 #include <utility>
 
 #include <cm/memory>
@@ -12,6 +13,7 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmProcessOutput.h"
 #include "cmProperty.h"
 #include "cmQtAutoGen.h"
@@ -56,7 +58,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
         if (targetName.empty()) {
           targetName = "autogen";
         }
-        GlobalAutoGenTargets_.emplace(localGen.get(), std::move(targetName));
+        this->GlobalAutoGenTargets_.emplace(localGen.get(),
+                                            std::move(targetName));
         globalAutoGenTarget = true;
       }
 
@@ -67,7 +70,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
         if (targetName.empty()) {
           targetName = "autorcc";
         }
-        GlobalAutoRccTargets_.emplace(localGen.get(), std::move(targetName));
+        this->GlobalAutoRccTargets_.emplace(localGen.get(),
+                                            std::move(targetName));
         globalAutoRccTarget = true;
       }
     }
@@ -91,17 +95,23 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
         // Don't process target
         continue;
       }
+      std::set<std::string> const& languages =
+        target->GetAllConfigCompileLanguages();
+      if (languages.count("CSharp")) {
+        // Don't process target if it's a CSharp target
+        continue;
+      }
 
-      bool const moc = target->GetPropertyAsBool(kw().AUTOMOC);
-      bool const uic = target->GetPropertyAsBool(kw().AUTOUIC);
-      bool const rcc = target->GetPropertyAsBool(kw().AUTORCC);
+      bool const moc = target->GetPropertyAsBool(this->kw().AUTOMOC);
+      bool const uic = target->GetPropertyAsBool(this->kw().AUTOUIC);
+      bool const rcc = target->GetPropertyAsBool(this->kw().AUTORCC);
       if (moc || uic || rcc) {
         std::string const& mocExec =
-          target->GetSafeProperty(kw().AUTOMOC_EXECUTABLE);
+          target->GetSafeProperty(this->kw().AUTOMOC_EXECUTABLE);
         std::string const& uicExec =
-          target->GetSafeProperty(kw().AUTOUIC_EXECUTABLE);
+          target->GetSafeProperty(this->kw().AUTOUIC_EXECUTABLE);
         std::string const& rccExec =
-          target->GetSafeProperty(kw().AUTORCC_EXECUTABLE);
+          target->GetSafeProperty(this->kw().AUTORCC_EXECUTABLE);
 
         // We support Qt4, Qt5 and Qt6
         auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target.get());
@@ -134,9 +144,10 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
         }
         if (mocIsValid || uicIsValid || rccIsValid) {
           // Create autogen target initializer
-          Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
-            this, target.get(), qtVersion.first, mocIsValid, uicIsValid,
-            rccIsValid, globalAutoGenTarget, globalAutoRccTarget));
+          this->Initializers_.emplace_back(
+            cm::make_unique<cmQtAutoGenInitializer>(
+              this, target.get(), qtVersion.first, mocIsValid, uicIsValid,
+              rccIsValid, globalAutoGenTarget, globalAutoRccTarget));
         }
       }
     }
@@ -157,9 +168,10 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
     std::vector<std::string> no_byproducts;
     std::vector<std::string> no_depends;
     cmCustomCommandLines no_commands;
+    const cmPolicies::PolicyStatus cmp0116_new = cmPolicies::NEW;
     cmTarget* target = localGen->AddUtilityCommand(
       name, true, makefile->GetHomeOutputDirectory().c_str(), no_byproducts,
-      no_depends, no_commands, false, comment.c_str());
+      no_depends, no_commands, cmp0116_new, false, comment.c_str());
     localGen->AddGeneratorTarget(
       cm::make_unique<cmGeneratorTarget>(target, localGen));
 
@@ -177,8 +189,8 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
 void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen(
   cmLocalGenerator* localGen, std::string const& targetName)
 {
-  auto it = GlobalAutoGenTargets_.find(localGen);
-  if (it != GlobalAutoGenTargets_.end()) {
+  auto it = this->GlobalAutoGenTargets_.find(localGen);
+  if (it != this->GlobalAutoGenTargets_.end()) {
     cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
     if (target != nullptr) {
       target->Target->AddUtility(targetName, false, localGen->GetMakefile());
@@ -189,8 +201,8 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen(
 void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
   cmLocalGenerator* localGen, std::string const& targetName)
 {
-  auto it = GlobalAutoRccTargets_.find(localGen);
-  if (it != GlobalAutoRccTargets_.end()) {
+  auto it = this->GlobalAutoRccTargets_.find(localGen);
+  if (it != this->GlobalAutoRccTargets_.end()) {
     cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
     if (target != nullptr) {
       target->Target->AddUtility(targetName, false, localGen->GetMakefile());
@@ -251,7 +263,7 @@ cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
 
 bool cmQtAutoGenGlobalInitializer::generate()
 {
-  return (InitializeCustomTargets() && SetupCustomTargets());
+  return (this->InitializeCustomTargets() && this->SetupCustomTargets());
 }
 
 bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets()
@@ -259,19 +271,19 @@ bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets()
   // Initialize global autogen targets
   {
     std::string const comment = "Global AUTOGEN target";
-    for (auto const& pair : GlobalAutoGenTargets_) {
-      GetOrCreateGlobalTarget(pair.first, pair.second, comment);
+    for (auto const& pair : this->GlobalAutoGenTargets_) {
+      this->GetOrCreateGlobalTarget(pair.first, pair.second, comment);
     }
   }
   // Initialize global autorcc targets
   {
     std::string const comment = "Global AUTORCC target";
-    for (auto const& pair : GlobalAutoRccTargets_) {
-      GetOrCreateGlobalTarget(pair.first, pair.second, comment);
+    for (auto const& pair : this->GlobalAutoRccTargets_) {
+      this->GetOrCreateGlobalTarget(pair.first, pair.second, comment);
     }
   }
   // Initialize per target autogen targets
-  for (auto& initializer : Initializers_) {
+  for (auto& initializer : this->Initializers_) {
     if (!initializer->InitCustomTargets()) {
       return false;
     }
@@ -281,7 +293,7 @@ bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets()
 
 bool cmQtAutoGenGlobalInitializer::SetupCustomTargets()
 {
-  for (auto& initializer : Initializers_) {
+  for (auto& initializer : this->Initializers_) {
     if (!initializer->SetupCustomTargets()) {
       return false;
     }
index cdae137..afcb4a2 100644 (file)
@@ -45,12 +45,11 @@ public:
     std::string ui;
   };
 
-public:
   cmQtAutoGenGlobalInitializer(
     std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators);
   ~cmQtAutoGenGlobalInitializer();
 
-  Keywords const& kw() const { return Keywords_; };
+  Keywords const& kw() const { return this->Keywords_; };
 
   bool generate();
 
@@ -73,7 +72,6 @@ private:
     std::string const& generator, std::string const& executable,
     std::string& error);
 
-private:
   std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_;
   std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_;
   std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_;
index 3b62e9c..d4138d9 100644 (file)
@@ -17,6 +17,7 @@
 #include <cm/iterator>
 #include <cm/memory>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include <cm3p/json/value.h>
 #include <cm3p/json/writer.h>
@@ -150,7 +151,8 @@ std::vector<std::string> SearchPathSanitizer::operator()(
   res.reserve(paths.size());
   for (std::string const& srcPath : paths) {
     // Collapse relative paths
-    std::string path = cmSystemTools::CollapseFullPath(srcPath, SourcePath_);
+    std::string path =
+      cmSystemTools::CollapseFullPath(srcPath, this->SourcePath_);
     // Remove suffix slashes
     while (cmHasSuffix(path, '/')) {
       path.pop_back();
@@ -170,14 +172,17 @@ public:
   // -- Single value
   void Set(std::string const& key, std::string const& value)
   {
-    Value_[key] = value;
+    this->Value_[key] = value;
   }
   void SetConfig(std::string const& key,
                  cmQtAutoGenInitializer::ConfigString const& cfgStr);
-  void SetBool(std::string const& key, bool value) { Value_[key] = value; }
+  void SetBool(std::string const& key, bool value)
+  {
+    this->Value_[key] = value;
+  }
   void SetUInt(std::string const& key, unsigned int value)
   {
-    Value_[key] = value;
+    this->Value_[key] = value;
   }
 
   // -- Array utility
@@ -209,9 +214,9 @@ private:
 void InfoWriter::SetConfig(std::string const& key,
                            cmQtAutoGenInitializer::ConfigString const& cfgStr)
 {
-  Set(key, cfgStr.Default);
+  this->Set(key, cfgStr.Default);
   for (auto const& item : cfgStr.Config) {
-    Set(cmStrCat(key, '_', item.first), item.second);
+    this->Set(cmStrCat(key, '_', item.first), item.second);
   }
 }
 
@@ -241,14 +246,14 @@ void InfoWriter::MakeStringArray(Json::Value& jval, CONT const& container)
 template <typename CONT>
 void InfoWriter::SetArray(std::string const& key, CONT const& container)
 {
-  MakeStringArray(Value_[key], container);
+  MakeStringArray(this->Value_[key], container);
 }
 
 template <typename CONT, typename FUNC>
 void InfoWriter::SetArrayArray(std::string const& key, CONT const& container,
                                FUNC func)
 {
-  Json::Value& jval = Value_[key];
+  Json::Value& jval = this->Value_[key];
   if (MakeArray(jval, container)) {
     Json::ArrayIndex ii = 0;
     for (auto const& citem : container) {
@@ -264,9 +269,9 @@ void InfoWriter::SetConfigArray(
   std::string const& key,
   cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr)
 {
-  SetArray(key, cfgStr.Default);
+  this->SetArray(key, cfgStr.Default);
   for (auto const& item : cfgStr.Config) {
-    SetArray(cmStrCat(key, '_', item.first), item.second);
+    this->SetArray(cmStrCat(key, '_', item.first), item.second);
   }
 }
 
@@ -281,7 +286,7 @@ bool InfoWriter::Save(std::string const& filename)
 
   Json::StyledStreamWriter jsonWriter;
   try {
-    jsonWriter.write(fileStream, Value_);
+    jsonWriter.write(fileStream, this->Value_);
   } catch (...) {
     return false;
   }
@@ -304,11 +309,11 @@ cmQtAutoGenInitializer::cmQtAutoGenInitializer(
   , PathCheckSum(genTarget->Makefile)
   , QtVersion(qtVersion)
 {
-  AutogenTarget.GlobalTarget = globalAutogenTarget;
-  Moc.Enabled = mocEnabled;
-  Uic.Enabled = uicEnabled;
-  Rcc.Enabled = rccEnabled;
-  Rcc.GlobalTarget = globalAutoRccTarget;
+  this->AutogenTarget.GlobalTarget = globalAutogenTarget;
+  this->Moc.Enabled = mocEnabled;
+  this->Uic.Enabled = uicEnabled;
+  this->Rcc.Enabled = rccEnabled;
+  this->Rcc.GlobalTarget = globalAutoRccTarget;
 }
 
 bool cmQtAutoGenInitializer::InitCustomTargets()
@@ -414,8 +419,8 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
     cmSystemTools::ConvertToUnixSlashes(this->Dir.Work);
 
     // Include directory
-    ConfigFileNames(this->Dir.Include, cmStrCat(this->Dir.Build, "/include"),
-                    "");
+    this->ConfigFileNames(this->Dir.Include,
+                          cmStrCat(this->Dir.Build, "/include"), "");
     this->Dir.IncludeGenExp = this->Dir.Include.Default;
     if (this->MultiConfig) {
       this->Dir.IncludeGenExp += "_$<CONFIG>";
@@ -425,12 +430,12 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
   // Moc, Uic and _autogen target settings
   if (this->MocOrUicEnabled()) {
     // Init moc specific settings
-    if (this->Moc.Enabled && !InitMoc()) {
+    if (this->Moc.Enabled && !this->InitMoc()) {
       return false;
     }
 
     // Init uic specific settings
-    if (this->Uic.Enabled && !InitUic()) {
+    if (this->Uic.Enabled && !this->InitUic()) {
       return false;
     }
 
@@ -457,14 +462,14 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
         cmStrCat(this->Dir.Info, "/AutogenInfo.json");
 
       // Used settings file
-      ConfigFileNames(this->AutogenTarget.SettingsFile,
-                      cmStrCat(this->Dir.Info, "/AutogenUsed"), ".txt");
-      ConfigFileClean(this->AutogenTarget.SettingsFile);
+      this->ConfigFileNames(this->AutogenTarget.SettingsFile,
+                            cmStrCat(this->Dir.Info, "/AutogenUsed"), ".txt");
+      this->ConfigFileClean(this->AutogenTarget.SettingsFile);
 
       // Parse cache file
-      ConfigFileNames(this->AutogenTarget.ParseCacheFile,
-                      cmStrCat(this->Dir.Info, "/ParseCache"), ".txt");
-      ConfigFileClean(this->AutogenTarget.ParseCacheFile);
+      this->ConfigFileNames(this->AutogenTarget.ParseCacheFile,
+                            cmStrCat(this->Dir.Info, "/ParseCache"), ".txt");
+      this->ConfigFileClean(this->AutogenTarget.ParseCacheFile);
     }
 
     // Autogen target: Compute user defined dependencies
@@ -533,7 +538,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
   }
 
   // Init rcc specific settings
-  if (this->Rcc.Enabled && !InitRcc()) {
+  if (this->Rcc.Enabled && !this->InitRcc()) {
     return false;
   }
 
@@ -563,8 +568,23 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
 bool cmQtAutoGenInitializer::InitMoc()
 {
   // Mocs compilation file
-  this->Moc.CompilationFile =
-    cmStrCat(this->Dir.Build, "/mocs_compilation.cpp");
+  if (this->GlobalGen->IsXcode()) {
+    // XXX(xcode-per-cfg-src): Drop this Xcode-specific code path
+    // when the Xcode generator supports per-config sources.
+    this->Moc.CompilationFile.Default =
+      cmStrCat(this->Dir.Build, "/mocs_compilation.cpp");
+    this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default;
+  } else {
+    this->ConfigFileNames(this->Moc.CompilationFile,
+                          cmStrCat(this->Dir.Build, "/mocs_compilation"),
+                          ".cpp");
+    if (this->MultiConfig) {
+      this->Moc.CompilationFileGenex =
+        cmStrCat(this->Dir.Build, "/mocs_compilation_$<CONFIG>.cpp"_s);
+    } else {
+      this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default;
+    }
+  }
 
   // Moc predefs
   if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") &&
@@ -574,8 +594,8 @@ bool cmQtAutoGenInitializer::InitMoc()
                                      this->Moc.PredefsCmd);
     // Header
     if (!this->Moc.PredefsCmd.empty()) {
-      ConfigFileNames(this->Moc.PredefsFile,
-                      cmStrCat(this->Dir.Build, "/moc_predefs"), ".h");
+      this->ConfigFileNames(this->Moc.PredefsFile,
+                            cmStrCat(this->Dir.Build, "/moc_predefs"), ".h");
     }
   }
 
@@ -730,10 +750,14 @@ bool cmQtAutoGenInitializer::InitScanFiles()
   auto const& kw = this->GlobalInitializer->kw();
 
   auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
+                                std::vector<size_t> const& configs,
                                 bool muIt) -> MUFileHandle {
     MUFileHandle muf = cm::make_unique<MUFile>();
     muf->FullPath = fullPath;
     muf->SF = sf;
+    if (!configs.empty() && configs.size() != this->ConfigsList.size()) {
+      muf->Configs = configs;
+    }
     muf->Generated = sf->GetIsGenerated();
     bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
     muf->SkipMoc = this->Moc.Enabled &&
@@ -772,42 +796,37 @@ bool cmQtAutoGenInitializer::InitScanFiles()
   // Scan through target files
   {
     // Scan through target files
-    std::vector<cmSourceFile*> srcFiles;
-    this->GenTarget->GetConfigCommonSourceFiles(srcFiles);
-    for (cmSourceFile* sf : srcFiles) {
-      // sf->GetExtension() is only valid after sf->ResolveFullPath() ...
-      // Since we're iterating over source files that might be not in the
-      // target we need to check for path errors (not existing files).
-      std::string pathError;
-      std::string const& fullPath = sf->ResolveFullPath(&pathError);
-      if (!pathError.empty() || fullPath.empty()) {
-        continue;
-      }
+    for (cmGeneratorTarget::AllConfigSource const& acs :
+         this->GenTarget->GetAllConfigSources()) {
+      std::string const& fullPath = acs.Source->GetFullPath();
       std::string const& extLower =
-        cmSystemTools::LowerCase(sf->GetExtension());
+        cmSystemTools::LowerCase(acs.Source->GetExtension());
 
       // Register files that will be scanned by moc or uic
       if (this->MocOrUicEnabled()) {
         if (cm->IsAHeaderExtension(extLower)) {
-          addMUHeader(makeMUFile(sf, fullPath, true), extLower);
+          addMUHeader(makeMUFile(acs.Source, fullPath, acs.Configs, true),
+                      extLower);
         } else if (cm->IsACLikeSourceExtension(extLower)) {
-          addMUSource(makeMUFile(sf, fullPath, true));
+          addMUSource(makeMUFile(acs.Source, fullPath, acs.Configs, true));
         }
       }
 
       // Register rcc enabled files
       if (this->Rcc.Enabled) {
-        if ((extLower == kw.qrc) && !sf->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
-            !sf->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
+        if ((extLower == kw.qrc) &&
+            !acs.Source->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
+            !acs.Source->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
           // Register qrc file
           Qrc qrc;
           qrc.QrcFile = fullPath;
           qrc.QrcName =
             cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
-          qrc.Generated = sf->GetIsGenerated();
+          qrc.Generated = acs.Source->GetIsGenerated();
           // RCC options
           {
-            std::string const opts = sf->GetSafeProperty(kw.AUTORCC_OPTIONS);
+            std::string const& opts =
+              acs.Source->GetSafeProperty(kw.AUTORCC_OPTIONS);
             if (!opts.empty()) {
               cmExpandList(opts, qrc.Options);
             }
@@ -817,7 +836,7 @@ bool cmQtAutoGenInitializer::InitScanFiles()
       }
     }
   }
-  // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's
+  // cmGeneratorTarget::GetAllConfigSources computes the target's
   // sources meta data cache. Clear it so that OBJECT library targets that
   // are AUTOGEN initialized after this target get their added
   // mocs_compilation.cpp source acknowledged by this target.
@@ -861,7 +880,7 @@ bool cmQtAutoGenInitializer::InitScanFiles()
             }
 
             if (sf != nullptr) {
-              auto eMuf = makeMUFile(sf, fullPath, true);
+              auto eMuf = makeMUFile(sf, fullPath, muf.Configs, true);
               // Only process moc/uic when the parent is processed as well
               if (!muf.MocIt) {
                 eMuf->MocIt = false;
@@ -896,14 +915,14 @@ bool cmQtAutoGenInitializer::InitScanFiles()
 
       if (cm->IsAHeaderExtension(extLower)) {
         if (!cm::contains(this->AutogenTarget.Headers, sf.get())) {
-          auto muf = makeMUFile(sf.get(), fullPath, false);
+          auto muf = makeMUFile(sf.get(), fullPath, {}, false);
           if (muf->SkipMoc || muf->SkipUic) {
             addMUHeader(std::move(muf), extLower);
           }
         }
       } else if (cm->IsACLikeSourceExtension(extLower)) {
         if (!cm::contains(this->AutogenTarget.Sources, sf.get())) {
-          auto muf = makeMUFile(sf.get(), fullPath, false);
+          auto muf = makeMUFile(sf.get(), fullPath, {}, false);
           if (muf->SkipMoc || muf->SkipUic) {
             addMUSource(std::move(muf));
           }
@@ -1020,7 +1039,7 @@ bool cmQtAutoGenInitializer::InitScanFiles()
                                         qrc.QrcName, '_', qrc.QrcPathChecksum);
       qrc.LockFile = cmStrCat(base, "_Lock.lock");
       qrc.InfoFile = cmStrCat(base, "_Info.json");
-      ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt");
+      this->ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt");
     }
     // rcc options
     for (Qrc& qrc : this->Rcc.Qrcs) {
@@ -1066,10 +1085,10 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
   this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile);
 
   // Files provided by the autogen target
-  std::vector<std::string> autogenProvides;
+  std::vector<std::string> autogenByproducts;
   if (this->Moc.Enabled) {
     this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true);
-    autogenProvides.push_back(this->Moc.CompilationFile);
+    autogenByproducts.push_back(this->Moc.CompilationFileGenex);
   }
 
   // Compose target comment
@@ -1090,8 +1109,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
   }
 
   // Compose command lines
-  // TODO: Refactor autogen to output a per-config mocs_compilation.cpp instead
-  // of fiddling with the include directories
+  // FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp
+  // instead of fiddling with the include directories
   std::vector<std::string> configs;
   this->GlobalGen->GetQtAutoGenConfigs(configs);
   bool stdPipesUTF8 = true;
@@ -1118,7 +1137,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
       usePRE_BUILD = false;
     }
     // Cannot use PRE_BUILD when a global autogen target is in place
-    if (AutogenTarget.GlobalTarget) {
+    if (this->AutogenTarget.GlobalTarget) {
       usePRE_BUILD = false;
     }
   }
@@ -1137,7 +1156,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
     // PRE_BUILD does not support file dependencies!
     const std::vector<std::string> no_output;
     const std::vector<std::string> no_deps;
-    cmCustomCommand cc(no_output, autogenProvides, no_deps, commandLines,
+    cmCustomCommand cc(no_output, autogenByproducts, no_deps, commandLines,
                        this->Makefile->GetBacktrace(), autogenComment.c_str(),
                        this->Dir.Work.c_str(), stdPipesUTF8);
     cc.SetEscapeOldStyle(false);
@@ -1206,7 +1225,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
       cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand(
         timestampTargetName, true, this->Dir.Work.c_str(),
         /*byproducts=*/timestampTargetProvides,
-        /*depends=*/dependencies, timestampTargetCommandLines, false, nullptr);
+        /*depends=*/dependencies, timestampTargetCommandLines, cmPolicies::NEW,
+        false, nullptr);
       this->LocalGen->AddGeneratorTarget(
         cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen));
 
@@ -1237,15 +1257,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
       const std::string outputFile =
         cmStrCat(this->Dir.Build, "/", timestampFileName);
       this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps");
-      auto relativeBinaryDir = cmSystemTools::RelativePath(
-        this->LocalGen->GetBinaryDirectory(),
-        this->LocalGen->GetCurrentBinaryDirectory());
-      if (!relativeBinaryDir.empty()) {
-        relativeBinaryDir = cmStrCat(relativeBinaryDir, "/");
-      }
       this->AutogenTarget.DepFileRuleName =
-        cmStrCat(relativeBinaryDir, this->GenTarget->GetName(), "_autogen/",
-                 timestampFileName);
+        cmStrCat(this->GenTarget->GetName(), "_autogen/", timestampFileName);
       commandLines.push_back(cmMakeCommandLine(
         { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
 
@@ -1253,7 +1266,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
       const std::string no_main_dependency;
       this->LocalGen->AddCustomCommandToOutput(
         outputFile, dependencies, no_main_dependency, commandLines,
-        autogenComment.c_str(), this->Dir.Work.c_str(), /*replace=*/false,
+        autogenComment.c_str(), this->Dir.Work.c_str(),
+        /*cmp0116=*/cmPolicies::NEW, /*replace=*/false,
         /*escapeOldStyle=*/false,
         /*uses_terminal=*/false,
         /*command_expand_lists=*/false, this->AutogenTarget.DepFile, "",
@@ -1270,8 +1284,9 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
     // Create autogen target
     cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand(
       this->AutogenTarget.Name, true, this->Dir.Work.c_str(),
-      /*byproducts=*/autogenProvides,
-      /*depends=*/dependencies, commandLines, false, autogenComment.c_str());
+      /*byproducts=*/autogenByproducts,
+      /*depends=*/dependencies, commandLines, cmPolicies::NEW, false,
+      autogenComment.c_str());
     // Create autogen generator target
     this->LocalGen->AddGeneratorTarget(
       cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen));
@@ -1357,8 +1372,8 @@ bool cmQtAutoGenInitializer::InitRccTargets()
 
         cmTarget* autoRccTarget = this->LocalGen->AddUtilityCommand(
           ccName, true, this->Dir.Work.c_str(), ccOutput, ccDepends,
-          commandLines, false, ccComment.c_str(), false, false, "",
-          stdPipesUTF8);
+          commandLines, cmPolicies::NEW, false, ccComment.c_str(), false,
+          false, "", stdPipesUTF8);
 
         // Create autogen generator target
         this->LocalGen->AddGeneratorTarget(
@@ -1398,8 +1413,8 @@ bool cmQtAutoGenInitializer::InitRccTargets()
         this->LocalGen->AddCustomCommandToOutput(
           ccOutput, ccByproducts, ccDepends, no_main_dependency,
           no_implicit_depends, commandLines, ccComment.c_str(),
-          this->Dir.Work.c_str(), false, true, false, false, "", "",
-          stdPipesUTF8);
+          this->Dir.Work.c_str(), cmPolicies::NEW, false, true, false, false,
+          "", "", stdPipesUTF8);
       }
       // Reconfigure when .qrc file changes
       this->Makefile->AddCMakeDependFile(qrc.QrcFile);
@@ -1520,18 +1535,31 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
   info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles());
   info.SetArray("HEADER_EXTENSIONS",
                 this->Makefile->GetCMakeInstance()->GetHeaderExtensions());
+  auto cfgArray = [this](std::vector<size_t> const& configs) -> Json::Value {
+    Json::Value value;
+    if (!configs.empty()) {
+      value = Json::arrayValue;
+      for (size_t ci : configs) {
+        value.append(this->ConfigsList[ci]);
+      }
+    }
+    return value;
+  };
+  info.SetArrayArray("HEADERS", headers,
+                     [this, &cfgArray](Json::Value& jval, MUFile const* muf) {
+                       jval.resize(4u);
+                       jval[0u] = muf->FullPath;
+                       jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm',
+                                           muf->UicIt ? 'U' : 'u');
+                       jval[2u] = this->GetMocBuildPath(*muf);
+                       jval[3u] = cfgArray(muf->Configs);
+                     });
   info.SetArrayArray(
-    "HEADERS", headers, [this](Json::Value& jval, MUFile const* muf) {
+    "SOURCES", sources, [&cfgArray](Json::Value& jval, MUFile const* muf) {
       jval.resize(3u);
       jval[0u] = muf->FullPath;
       jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u');
-      jval[2u] = this->GetMocBuildPath(*muf);
-    });
-  info.SetArrayArray(
-    "SOURCES", sources, [](Json::Value& jval, MUFile const* muf) {
-      jval.resize(2u);
-      jval[0u] = muf->FullPath;
-      jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u');
+      jval[2u] = cfgArray(muf->Configs);
     });
 
   // Write moc settings
@@ -1550,7 +1578,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
         jval[0u] = pair.first;
         jval[1u] = pair.second;
       });
-    info.Set("MOC_COMPILATION_FILE", this->Moc.CompilationFile);
+    info.SetConfig("MOC_COMPILATION_FILE", this->Moc.CompilationFile);
     info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd);
     info.SetConfig("MOC_PREDEFS_FILE", this->Moc.PredefsFile);
   }
@@ -1624,7 +1652,7 @@ cmSourceFile* cmQtAutoGenInitializer::RegisterGeneratedSource(
   std::string const& filename)
 {
   cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true);
-  gFile->SetProperty("GENERATED", "1");
+  gFile->MarkAsGenerated();
   gFile->SetProperty("SKIP_AUTOGEN", "1");
   return gFile;
 }
@@ -1643,6 +1671,28 @@ cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource(
   return gFile;
 }
 
+void cmQtAutoGenInitializer::AddGeneratedSource(ConfigString const& filename,
+                                                GenVarsT const& genVars,
+                                                bool prepend)
+{
+  // XXX(xcode-per-cfg-src): Drop the Xcode-specific part of the condition
+  // when the Xcode generator supports per-config sources.
+  if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
+    this->AddGeneratedSource(filename.Default, genVars, prepend);
+    return;
+  }
+  for (auto const& cfg : this->ConfigsList) {
+    std::string const& filenameCfg = filename.Config.at(cfg);
+    // Register source at makefile
+    this->RegisterGeneratedSource(filenameCfg);
+    // Add source file to target for this configuration.
+    this->GenTarget->AddSource(
+      cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, filenameCfg, ">"_s), prepend);
+    // Add source file to source group
+    this->AddToSourceGroup(filenameCfg, genVars.GenNameUpper);
+  }
+}
+
 void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
                                               cm::string_view genNameUpper)
 {
index 3ab303a..f7e126d 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <cstddef>
 #include <memory>
 #include <set>
 #include <string>
@@ -70,6 +71,7 @@ public:
   {
     std::string FullPath;
     cmSourceFile* SF = nullptr;
+    std::vector<size_t> Configs;
     bool Generated = false;
     bool SkipMoc = false;
     bool SkipUic = false;
@@ -96,7 +98,6 @@ public:
       , GenNameUpper(cmQtAutoGen::GeneratorNameUpper(gen)){};
   };
 
-public:
   /** @return The detected Qt version and the required Qt major version.  */
   static std::pair<IntegerVersion, unsigned int> GetQtVersion(
     cmGeneratorTarget const* genTarget);
@@ -132,6 +133,8 @@ private:
   cmSourceFile* AddGeneratedSource(std::string const& filename,
                                    GenVarsT const& genVars,
                                    bool prepend = false);
+  void AddGeneratedSource(ConfigString const& filename,
+                          GenVarsT const& genVars, bool prepend = false);
   void AddToSourceGroup(std::string const& fileName,
                         cm::string_view genNameUpper);
   void AddCleanFile(std::string const& fileName);
@@ -145,7 +148,6 @@ private:
   bool GetQtExecutable(GenVarsT& genVars, const std::string& executable,
                        bool ignoreMissingTarget) const;
 
-private:
   cmQtAutoGenGlobalInitializer* GlobalInitializer = nullptr;
   cmGeneratorTarget* GenTarget = nullptr;
   cmGlobalGenerator* GlobalGen = nullptr;
@@ -207,7 +209,8 @@ private:
 
     bool RelaxedMode = false;
     bool PathPrefix = false;
-    std::string CompilationFile;
+    ConfigString CompilationFile;
+    std::string CompilationFileGenex;
     // Compiler implicit pre defines
     std::vector<std::string> PredefsCmd;
     ConfigString PredefsFile;
index ee2bc09..6e88e26 100644 (file)
@@ -18,10 +18,10 @@ cmQtAutoGenerator::Logger::Logger()
     if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
       unsigned long iVerbose = 0;
       if (cmStrToULong(verbose, &iVerbose)) {
-        SetVerbosity(static_cast<unsigned int>(iVerbose));
+        this->SetVerbosity(static_cast<unsigned int>(iVerbose));
       } else {
         // Non numeric verbosity
-        SetVerbose(cmIsOn(verbose));
+        this->SetVerbose(cmIsOn(verbose));
       }
     }
   }
@@ -29,15 +29,13 @@ cmQtAutoGenerator::Logger::Logger()
     std::string colorEnv;
     cmSystemTools::GetEnv("COLOR", colorEnv);
     if (!colorEnv.empty()) {
-      SetColorOutput(cmIsOn(colorEnv));
+      this->SetColorOutput(cmIsOn(colorEnv));
     } else {
-      SetColorOutput(true);
+      this->SetColorOutput(true);
     }
   }
 }
 
-cmQtAutoGenerator::Logger::~Logger() = default;
-
 void cmQtAutoGenerator::Logger::RaiseVerbosity(unsigned int value)
 {
   if (this->Verbosity_ < value) {
@@ -47,7 +45,7 @@ void cmQtAutoGenerator::Logger::RaiseVerbosity(unsigned int value)
 
 void cmQtAutoGenerator::Logger::SetColorOutput(bool value)
 {
-  ColorOutput_ = value;
+  this->ColorOutput_ = value;
 }
 
 std::string cmQtAutoGenerator::Logger::HeadLine(cm::string_view title)
@@ -61,7 +59,7 @@ void cmQtAutoGenerator::Logger::Info(GenT genType,
   std::string msg = cmStrCat(GeneratorName(genType), ": ", message,
                              cmHasSuffix(message, '\n') ? "" : "\n");
   {
-    std::lock_guard<std::mutex> lock(Mutex_);
+    std::lock_guard<std::mutex> lock(this->Mutex_);
     cmSystemTools::Stdout(msg);
   }
 }
@@ -80,7 +78,7 @@ void cmQtAutoGenerator::Logger::Warning(GenT genType,
                    message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
   }
   {
-    std::lock_guard<std::mutex> lock(Mutex_);
+    std::lock_guard<std::mutex> lock(this->Mutex_);
     cmSystemTools::Stdout(msg);
   }
 }
@@ -92,7 +90,7 @@ void cmQtAutoGenerator::Logger::Error(GenT genType,
     cmStrCat('\n', HeadLine(cmStrCat(GeneratorName(genType), " error")),
              message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
   {
-    std::lock_guard<std::mutex> lock(Mutex_);
+    std::lock_guard<std::mutex> lock(this->Mutex_);
     cmSystemTools::Stderr(msg);
   }
 }
@@ -108,7 +106,7 @@ void cmQtAutoGenerator::Logger::ErrorCommand(
   msg += cmStrCat(HeadLine("Output"), output,
                   cmHasSuffix(output, '\n') ? "\n" : "\n\n");
   {
-    std::lock_guard<std::mutex> lock(Mutex_);
+    std::lock_guard<std::mutex> lock(this->Mutex_);
     cmSystemTools::Stderr(msg);
   }
 }
@@ -215,7 +213,7 @@ cmQtAutoGenerator::~cmQtAutoGenerator() = default;
 bool cmQtAutoGenerator::InfoT::Read(std::istream& istr)
 {
   try {
-    istr >> Json_;
+    istr >> this->Json_;
   } catch (...) {
     return false;
   }
@@ -264,22 +262,22 @@ bool cmQtAutoGenerator::InfoT::GetJsonArray(
 
 std::string cmQtAutoGenerator::InfoT::ConfigKey(cm::string_view key) const
 {
-  return cmStrCat(key, '_', Gen_.InfoConfig());
+  return cmStrCat(key, '_', this->Gen_.InfoConfig());
 }
 
 bool cmQtAutoGenerator::InfoT::GetString(std::string const& key,
                                          std::string& value,
                                          bool required) const
 {
-  Json::Value const& jval = Json_[key];
+  Json::Value const& jval = this->Json_[key];
   if (!jval.isString()) {
     if (!jval.isNull() || required) {
-      return LogError(cmStrCat(key, " is not a string."));
+      return this->LogError(cmStrCat(key, " is not a string."));
     }
   } else {
     value = jval.asString();
     if (value.empty() && required) {
-      return LogError(cmStrCat(key, " is empty."));
+      return this->LogError(cmStrCat(key, " is empty."));
     }
   }
   return true;
@@ -290,32 +288,32 @@ bool cmQtAutoGenerator::InfoT::GetStringConfig(std::string const& key,
                                                bool required) const
 {
   { // Try config
-    std::string const configKey = ConfigKey(key);
-    Json::Value const& jval = Json_[configKey];
+    std::string const configKey = this->ConfigKey(key);
+    Json::Value const& jval = this->Json_[configKey];
     if (!jval.isNull()) {
       if (!jval.isString()) {
-        return LogError(cmStrCat(configKey, " is not a string."));
+        return this->LogError(cmStrCat(configKey, " is not a string."));
       }
       value = jval.asString();
       if (required && value.empty()) {
-        return LogError(cmStrCat(configKey, " is empty."));
+        return this->LogError(cmStrCat(configKey, " is empty."));
       }
       return true;
     }
   }
   // Try plain
-  return GetString(key, value, required);
+  return this->GetString(key, value, required);
 }
 
 bool cmQtAutoGenerator::InfoT::GetBool(std::string const& key, bool& value,
                                        bool required) const
 {
-  Json::Value const& jval = Json_[key];
+  Json::Value const& jval = this->Json_[key];
   if (jval.isBool()) {
     value = jval.asBool();
   } else {
     if (!jval.isNull() || required) {
-      return LogError(cmStrCat(key, " is not a boolean."));
+      return this->LogError(cmStrCat(key, " is not a boolean."));
     }
   }
   return true;
@@ -325,12 +323,12 @@ bool cmQtAutoGenerator::InfoT::GetUInt(std::string const& key,
                                        unsigned int& value,
                                        bool required) const
 {
-  Json::Value const& jval = Json_[key];
+  Json::Value const& jval = this->Json_[key];
   if (jval.isUInt()) {
     value = jval.asUInt();
   } else {
     if (!jval.isNull() || required) {
-      return LogError(cmStrCat(key, " is not an unsigned integer."));
+      return this->LogError(cmStrCat(key, " is not an unsigned integer."));
     }
   }
   return true;
@@ -340,10 +338,10 @@ bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key,
                                         std::vector<std::string>& list,
                                         bool required) const
 {
-  Json::Value const& jval = Json_[key];
+  Json::Value const& jval = this->Json_[key];
   if (!jval.isArray()) {
     if (!jval.isNull() || required) {
-      return LogError(cmStrCat(key, " is not an array."));
+      return this->LogError(cmStrCat(key, " is not an array."));
     }
   }
   return GetJsonArray(list, jval) || !required;
@@ -353,10 +351,10 @@ bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key,
                                         std::unordered_set<std::string>& list,
                                         bool required) const
 {
-  Json::Value const& jval = Json_[key];
+  Json::Value const& jval = this->Json_[key];
   if (!jval.isArray()) {
     if (!jval.isNull() || required) {
-      return LogError(cmStrCat(key, " is not an array."));
+      return this->LogError(cmStrCat(key, " is not an array."));
     }
   }
   return GetJsonArray(list, jval) || !required;
@@ -367,34 +365,35 @@ bool cmQtAutoGenerator::InfoT::GetArrayConfig(std::string const& key,
                                               bool required) const
 {
   { // Try config
-    std::string const configKey = ConfigKey(key);
-    Json::Value const& jval = Json_[configKey];
+    std::string const configKey = this->ConfigKey(key);
+    Json::Value const& jval = this->Json_[configKey];
     if (!jval.isNull()) {
       if (!jval.isArray()) {
-        return LogError(cmStrCat(configKey, " is not an array string."));
+        return this->LogError(cmStrCat(configKey, " is not an array string."));
       }
       if (!GetJsonArray(list, jval) && required) {
-        return LogError(cmStrCat(configKey, " is empty."));
+        return this->LogError(cmStrCat(configKey, " is empty."));
       }
       return true;
     }
   }
   // Try plain
-  return GetArray(key, list, required);
+  return this->GetArray(key, list, required);
 }
 
 bool cmQtAutoGenerator::InfoT::LogError(GenT genType,
                                         cm::string_view message) const
 {
-  Gen_.Log().Error(genType,
-                   cmStrCat("Info error in info file\n",
-                            Quoted(Gen_.InfoFile()), ":\n", message));
+  this->Gen_.Log().Error(genType,
+                         cmStrCat("Info error in info file\n",
+                                  Quoted(this->Gen_.InfoFile()), ":\n",
+                                  message));
   return false;
 }
 
 bool cmQtAutoGenerator::InfoT::LogError(cm::string_view message) const
 {
-  return LogError(Gen_.GenType_, message);
+  return this->LogError(this->Gen_.GenType_, message);
 }
 
 std::string cmQtAutoGenerator::SettingsFind(cm::string_view content,
@@ -418,10 +417,10 @@ std::string cmQtAutoGenerator::SettingsFind(cm::string_view content,
 std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const
 {
   std::string res;
-  if (cmHasPrefix(path, ProjectDirs().Source)) {
-    res = cmStrCat("SRC:", path.substr(ProjectDirs().Source.size()));
-  } else if (cmHasPrefix(path, ProjectDirs().Binary)) {
-    res = cmStrCat("BIN:", path.substr(ProjectDirs().Binary.size()));
+  if (cmHasPrefix(path, this->ProjectDirs().Source)) {
+    res = cmStrCat("SRC:", path.substr(this->ProjectDirs().Source.size()));
+  } else if (cmHasPrefix(path, this->ProjectDirs().Binary)) {
+    res = cmStrCat("BIN:", path.substr(this->ProjectDirs().Binary.size()));
   } else {
     res = std::string(path);
   }
@@ -431,17 +430,18 @@ std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const
 bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config)
 {
   // Info config
-  InfoConfig_ = std::string(config);
+  this->InfoConfig_ = std::string(config);
 
   // Info file
-  InfoFile_ = std::string(infoFile);
-  cmSystemTools::CollapseFullPath(InfoFile_);
-  InfoDir_ = cmSystemTools::GetFilenamePath(InfoFile_);
+  this->InfoFile_ = std::string(infoFile);
+  cmSystemTools::CollapseFullPath(this->InfoFile_);
+  this->InfoDir_ = cmSystemTools::GetFilenamePath(this->InfoFile_);
 
   // Load info file time
-  if (!InfoFileTime_.Load(InfoFile_)) {
+  if (!this->InfoFileTime_.Load(this->InfoFile_)) {
     cmSystemTools::Stderr(cmStrCat("AutoGen: The info file ",
-                                   Quoted(InfoFile_), " is not readable\n"));
+                                   Quoted(this->InfoFile_),
+                                   " is not readable\n"));
     return false;
   }
 
@@ -450,17 +450,18 @@ bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config)
 
     // Read info file
     {
-      cmsys::ifstream ifs(InfoFile_.c_str(),
+      cmsys::ifstream ifs(this->InfoFile_.c_str(),
                           (std::ios::in | std::ios::binary));
       if (!ifs) {
-        Log().Error(
-          GenType_,
-          cmStrCat("Could not to open info file ", Quoted(InfoFile_)));
+        this->Log().Error(
+          this->GenType_,
+          cmStrCat("Could not to open info file ", Quoted(this->InfoFile_)));
         return false;
       }
       if (!info.Read(ifs)) {
-        Log().Error(GenType_,
-                    cmStrCat("Could not read info file ", Quoted(InfoFile_)));
+        this->Log().Error(
+          this->GenType_,
+          cmStrCat("Could not read info file ", Quoted(this->InfoFile_)));
         return false;
       }
     }
@@ -470,15 +471,17 @@ bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config)
       unsigned int verbosity = 0;
       // Info: setup project directories
       if (!info.GetUInt("VERBOSITY", verbosity, false) ||
-          !info.GetString("CMAKE_SOURCE_DIR", ProjectDirs_.Source, true) ||
-          !info.GetString("CMAKE_BINARY_DIR", ProjectDirs_.Binary, true) ||
+          !info.GetString("CMAKE_SOURCE_DIR", this->ProjectDirs_.Source,
+                          true) ||
+          !info.GetString("CMAKE_BINARY_DIR", this->ProjectDirs_.Binary,
+                          true) ||
           !info.GetString("CMAKE_CURRENT_SOURCE_DIR",
-                          ProjectDirs_.CurrentSource, true) ||
+                          this->ProjectDirs_.CurrentSource, true) ||
           !info.GetString("CMAKE_CURRENT_BINARY_DIR",
-                          ProjectDirs_.CurrentBinary, true)) {
+                          this->ProjectDirs_.CurrentBinary, true)) {
         return false;
       }
-      Logger_.RaiseVerbosity(verbosity);
+      this->Logger_.RaiseVerbosity(verbosity);
     }
 
     // -- Call virtual init from info method.
index b4f057d..5c3a8ad 100644 (file)
@@ -31,7 +31,7 @@ public:
   public:
     // -- Construction
     Logger();
-    ~Logger();
+    ~Logger() = default;
     // -- Verbosity
     unsigned int Verbosity() const { return this->Verbosity_; }
     void SetVerbosity(unsigned int value) { this->Verbosity_ = value; }
@@ -54,7 +54,6 @@ public:
   private:
     static std::string HeadLine(cm::string_view title);
 
-  private:
     mutable std::mutex Mutex_;
     unsigned int Verbosity_ = 0;
     bool ColorOutput_ = false;
@@ -79,7 +78,6 @@ public:
   static bool FileDiffers(std::string const& filename,
                           std::string const& content);
 
-public:
   // -- Constructors
   cmQtAutoGenerator(GenT genType);
   virtual ~cmQtAutoGenerator();
@@ -88,10 +86,10 @@ public:
   cmQtAutoGenerator& operator=(cmQtAutoGenerator const&) = delete;
 
   // -- Info options
-  std::string const& InfoFile() const { return InfoFile_; }
-  std::string const& InfoDir() const { return InfoDir_; }
-  cmFileTime const& InfoFileTime() const { return InfoFileTime_; }
-  std::string const& InfoConfig() const { return InfoConfig_; }
+  std::string const& InfoFile() const { return this->InfoFile_; }
+  std::string const& InfoDir() const { return this->InfoDir_; }
+  cmFileTime const& InfoFileTime() const { return this->InfoFileTime_; }
+  std::string const& InfoConfig() const { return this->InfoConfig_; }
 
   // -- Info file parsing
   /** Info file reader class. */
@@ -124,7 +122,7 @@ public:
 
     Json::Value const& GetValue(std::string const& key) const
     {
-      return Json_[key];
+      return this->Json_[key];
     }
 
     /** Returns true if strings were appended to the list.  */
@@ -140,7 +138,6 @@ public:
   private:
     std::string ConfigKey(cm::string_view key) const;
 
-  private:
     Json::Value Json_;
     cmQtAutoGenerator& Gen_;
   };
@@ -150,7 +147,7 @@ public:
                                   cm::string_view key);
 
   // -- Directories
-  ProjectDirsT const& ProjectDirs() const { return ProjectDirs_; }
+  ProjectDirsT const& ProjectDirs() const { return this->ProjectDirs_; }
   std::string MessagePath(cm::string_view path) const;
 
   // -- Run
@@ -161,7 +158,7 @@ protected:
   virtual bool InitFromInfo(InfoT const& info) = 0;
   virtual bool Process() = 0;
   // - Utility classes
-  Logger const& Log() const { return Logger_; }
+  Logger const& Log() const { return this->Logger_; }
 
 private:
   // -- Generator type
index 9cb172b..1e3bf06 100644 (file)
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cm/optional>
 #include <cm/string_view>
 #include <cmext/algorithm>
 
@@ -26,7 +27,6 @@
 #include "cmCryptoHash.h"
 #include "cmFileTime.h"
 #include "cmGccDepfileReader.h"
-#include "cmGccDepfileReaderTypes.h"
 #include "cmGeneratedFileStream.h"
 #include "cmQtAutoGen.h"
 #include "cmQtAutoGenerator.h"
@@ -55,7 +55,6 @@ public:
   cmQtAutoMocUicT(cmQtAutoMocUicT const&) = delete;
   cmQtAutoMocUicT& operator=(cmQtAutoMocUicT const&) = delete;
 
-public:
   // -- Types
 
   /** Include string with sub parts.  */
@@ -112,7 +111,6 @@ public:
     using FileHandleT = std::shared_ptr<FileT>;
     using GetOrInsertT = std::pair<FileHandleT, bool>;
 
-  public:
     ParseCacheT();
     ~ParseCacheT();
 
@@ -135,7 +133,6 @@ public:
     {
     }
 
-  public:
     std::string FileName;
     cmFileTime FileTime;
     ParseCacheT::FileHandleT ParseData;
@@ -266,7 +263,6 @@ public:
       std::vector<std::string> Options;
     };
 
-  public:
     UicSettingsT();
     ~UicSettingsT();
 
@@ -313,22 +309,22 @@ public:
     //! Get the generator. Only valid during Process() call!
     cmQtAutoMocUicT* Gen() const
     {
-      return static_cast<cmQtAutoMocUicT*>(UserData());
+      return static_cast<cmQtAutoMocUicT*>(this->UserData());
     };
 
     // -- Accessors. Only valid during Process() call!
-    Logger const& Log() const { return Gen()->Log(); }
-    BaseSettingsT const& BaseConst() const { return Gen()->BaseConst(); }
-    BaseEvalT& BaseEval() const { return Gen()->BaseEval(); }
-    MocSettingsT const& MocConst() const { return Gen()->MocConst(); }
-    MocEvalT& MocEval() const { return Gen()->MocEval(); }
-    UicSettingsT const& UicConst() const { return Gen()->UicConst(); }
-    UicEvalT& UicEval() const { return Gen()->UicEval(); }
+    Logger const& Log() const { return this->Gen()->Log(); }
+    BaseSettingsT const& BaseConst() const { return this->Gen()->BaseConst(); }
+    BaseEvalT& BaseEval() const { return this->Gen()->BaseEval(); }
+    MocSettingsT const& MocConst() const { return this->Gen()->MocConst(); }
+    MocEvalT& MocEval() const { return this->Gen()->MocEval(); }
+    UicSettingsT const& UicConst() const { return this->Gen()->UicConst(); }
+    UicEvalT& UicEval() const { return this->Gen()->UicEval(); }
 
     // -- Logging
     std::string MessagePath(cm::string_view path) const
     {
-      return Gen()->MessagePath(path);
+      return this->Gen()->MessagePath(path);
     }
     // - Error logging with automatic abort
     void LogError(GenT genType, cm::string_view message) const;
@@ -379,7 +375,6 @@ public:
     void MocIncludes();
     void UicIncludes();
 
-  protected:
     SourceFileHandleT FileHandle;
     std::string Content;
   };
@@ -522,6 +517,7 @@ public:
   class JobDepFilesMergeT : public JobFenceT
   {
   private:
+    std::vector<std::string> initialDependencies() const;
     void Process() override;
   };
 
@@ -541,9 +537,9 @@ public:
   UicEvalT& UicEval() { return this->UicEval_; }
 
   // -- Parallel job processing interface
-  cmWorkerPool& WorkerPool() { return WorkerPool_; }
-  void AbortError() { Abort(true); }
-  void AbortSuccess() { Abort(false); }
+  cmWorkerPool& WorkerPool() { return this->WorkerPool_; }
+  void AbortError() { this->Abort(true); }
+  void AbortSuccess() { this->Abort(false); }
 
   // -- Utility
   std::string AbsoluteBuildPath(cm::string_view relativePath) const;
@@ -571,7 +567,6 @@ private:
   static std::vector<std::string> dependenciesFromDepFile(
     const char* filePath);
 
-private:
   // -- Settings
   BaseSettingsT BaseConst_;
   BaseEvalT BaseEval_;
@@ -597,19 +592,19 @@ cmQtAutoMocUicT::IncludeKeyT::IncludeKeyT(std::string const& key,
   , Base(cmSystemTools::GetFilenameWithoutLastExtension(key))
 {
   if (basePrefixLength != 0) {
-    Base = Base.substr(basePrefixLength);
+    this->Base = this->Base.substr(basePrefixLength);
   }
 }
 
 void cmQtAutoMocUicT::ParseCacheT::FileT::Clear()
 {
-  Moc.Macro.clear();
-  Moc.Include.Underscore.clear();
-  Moc.Include.Dot.clear();
-  Moc.Depends.clear();
+  this->Moc.Macro.clear();
+  this->Moc.Include.Underscore.clear();
+  this->Moc.Include.Dot.clear();
+  this->Moc.Depends.clear();
 
-  Uic.Include.clear();
-  Uic.Depends.clear();
+  this->Uic.Include.clear();
+  this->Uic.Depends.clear();
 }
 
 cmQtAutoMocUicT::ParseCacheT::GetOrInsertT
@@ -617,15 +612,15 @@ cmQtAutoMocUicT::ParseCacheT::GetOrInsert(std::string const& fileName)
 {
   // Find existing entry
   {
-    auto it = Map_.find(fileName);
-    if (it != Map_.end()) {
+    auto it = this->Map_.find(fileName);
+    if (it != this->Map_.end()) {
       return GetOrInsertT{ it->second, false };
     }
   }
 
   // Insert new entry
   return GetOrInsertT{
-    Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true
+    this->Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true
   };
 }
 
@@ -655,7 +650,7 @@ bool cmQtAutoMocUicT::ParseCacheT::ReadFromFile(std::string const& fileName)
     }
     // Check if this a file name line
     if (line.front() != ' ') {
-      fileHandle = GetOrInsert(line).first;
+      fileHandle = this->GetOrInsert(line).first;
       continue;
     }
 
@@ -702,7 +697,7 @@ bool cmQtAutoMocUicT::ParseCacheT::WriteToFile(std::string const& fileName)
     return false;
   }
   ofs << "# Generated by CMake. Changes will be overwritten.\n";
-  for (auto const& pair : Map_) {
+  for (auto const& pair : this->Map_) {
     ofs << pair.first << '\n';
     FileT const& file = *pair.second;
     if (!file.Moc.Macro.empty()) {
@@ -732,7 +727,7 @@ cmQtAutoMocUicT::BaseSettingsT::~BaseSettingsT() = default;
 
 cmQtAutoMocUicT::MocSettingsT::MocSettingsT()
 {
-  RegExpInclude.compile(
+  this->RegExpInclude.compile(
     "(^|\n)[ \t]*#[ \t]*include[ \t]+"
     "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
 }
@@ -741,14 +736,15 @@ cmQtAutoMocUicT::MocSettingsT::~MocSettingsT() = default;
 
 bool cmQtAutoMocUicT::MocSettingsT::skipped(std::string const& fileName) const
 {
-  return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+  return (!this->Enabled ||
+          (this->SkipList.find(fileName) != this->SkipList.end()));
 }
 
 std::string cmQtAutoMocUicT::MocSettingsT::MacrosString() const
 {
   std::string res;
-  const auto itB = MacroFilters.cbegin();
-  const auto itE = MacroFilters.cend();
+  const auto itB = this->MacroFilters.cbegin();
+  const auto itE = this->MacroFilters.cend();
   const auto itL = itE - 1;
   auto itC = itB;
   for (; itC != itE; ++itC) {
@@ -768,30 +764,31 @@ std::string cmQtAutoMocUicT::MocSettingsT::MacrosString() const
 
 cmQtAutoMocUicT::UicSettingsT::UicSettingsT()
 {
-  RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
-                        "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
+  this->RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+"
+                              "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]");
 }
 
 cmQtAutoMocUicT::UicSettingsT::~UicSettingsT() = default;
 
 bool cmQtAutoMocUicT::UicSettingsT::skipped(std::string const& fileName) const
 {
-  return (!Enabled || (SkipList.find(fileName) != SkipList.end()));
+  return (!this->Enabled ||
+          (this->SkipList.find(fileName) != this->SkipList.end()));
 }
 
 void cmQtAutoMocUicT::JobT::LogError(GenT genType,
                                      cm::string_view message) const
 {
-  Gen()->AbortError();
-  Gen()->Log().Error(genType, message);
+  this->Gen()->AbortError();
+  this->Gen()->Log().Error(genType, message);
 }
 
 void cmQtAutoMocUicT::JobT::LogCommandError(
   GenT genType, cm::string_view message,
   std::vector<std::string> const& command, std::string const& output) const
 {
-  Gen()->AbortError();
-  Gen()->Log().ErrorCommand(genType, message, command, output);
+  this->Gen()->AbortError();
+  this->Gen()->Log().ErrorCommand(genType, message, command, output);
 }
 
 bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType,
@@ -800,48 +797,48 @@ bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType,
                                        std::string* infoMessage)
 {
   // Log command
-  if (Log().Verbose()) {
+  if (this->Log().Verbose()) {
     cm::string_view info;
     if (infoMessage != nullptr) {
       info = *infoMessage;
     }
-    Log().Info(genType,
-               cmStrCat(info,
-                        info.empty() || cmHasSuffix(info, '\n') ? "" : "\n",
-                        QuotedCommand(command), '\n'));
+    this->Log().Info(
+      genType,
+      cmStrCat(info, info.empty() || cmHasSuffix(info, '\n') ? "" : "\n",
+               QuotedCommand(command), '\n'));
   }
   // Run command
-  return cmWorkerPool::JobT::RunProcess(result, command,
-                                        BaseConst().AutogenBuildDir);
+  return this->cmWorkerPool::JobT::RunProcess(
+    result, command, this->BaseConst().AutogenBuildDir);
 }
 
 void cmQtAutoMocUicT::JobMocPredefsT::Process()
 {
   // (Re)generate moc_predefs.h on demand
   std::unique_ptr<std::string> reason;
-  if (Log().Verbose()) {
+  if (this->Log().Verbose()) {
     reason = cm::make_unique<std::string>();
   }
-  if (!Update(reason.get())) {
+  if (!this->Update(reason.get())) {
     return;
   }
-  std::string const& predefsFileAbs = MocConst().PredefsFileAbs;
+  std::string const& predefsFileAbs = this->MocConst().PredefsFileAbs;
   {
     cmWorkerPool::ProcessResultT result;
     {
       // Compose command
-      std::vector<std::string> cmd = MocConst().PredefsCmd;
+      std::vector<std::string> cmd = this->MocConst().PredefsCmd;
       // Add definitions
-      cm::append(cmd, MocConst().OptionsDefinitions);
+      cm::append(cmd, this->MocConst().OptionsDefinitions);
       // Add includes
-      cm::append(cmd, MocConst().OptionsIncludes);
+      cm::append(cmd, this->MocConst().OptionsIncludes);
       // Execute command
-      if (!RunProcess(GenT::MOC, result, cmd, reason.get())) {
-        LogCommandError(GenT::MOC,
-                        cmStrCat("The content generation command for ",
-                                 MessagePath(predefsFileAbs), " failed.\n",
-                                 result.ErrorMessage),
-                        cmd, result.StdOut);
+      if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) {
+        this->LogCommandError(GenT::MOC,
+                              cmStrCat("The content generation command for ",
+                                       this->MessagePath(predefsFileAbs),
+                                       " failed.\n", result.ErrorMessage),
+                              cmd, result.StdOut);
         return;
       }
     }
@@ -849,30 +846,31 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process()
     // (Re)write predefs file only on demand
     if (cmQtAutoGenerator::FileDiffers(predefsFileAbs, result.StdOut)) {
       if (!cmQtAutoGenerator::FileWrite(predefsFileAbs, result.StdOut)) {
-        LogError(
+        this->LogError(
           GenT::MOC,
-          cmStrCat("Writing ", MessagePath(predefsFileAbs), " failed."));
+          cmStrCat("Writing ", this->MessagePath(predefsFileAbs), " failed."));
         return;
       }
     } else {
       // Touch to update the time stamp
-      if (Log().Verbose()) {
-        Log().Info(GenT::MOC, "Touching " + MessagePath(predefsFileAbs));
+      if (this->Log().Verbose()) {
+        this->Log().Info(GenT::MOC,
+                         "Touching " + this->MessagePath(predefsFileAbs));
       }
       if (!cmSystemTools::Touch(predefsFileAbs, false)) {
-        LogError(
-          GenT::MOC,
-          cmStrCat("Touching ", MessagePath(predefsFileAbs), " failed."));
+        this->LogError(GenT::MOC,
+                       cmStrCat("Touching ", this->MessagePath(predefsFileAbs),
+                                " failed."));
         return;
       }
     }
   }
 
   // Read file time afterwards
-  if (!MocEval().PredefsTime.Load(predefsFileAbs)) {
-    LogError(GenT::MOC,
-             cmStrCat("Reading the file time of ", MessagePath(predefsFileAbs),
-                      " failed."));
+  if (!this->MocEval().PredefsTime.Load(predefsFileAbs)) {
+    this->LogError(GenT::MOC,
+                   cmStrCat("Reading the file time of ",
+                            this->MessagePath(predefsFileAbs), " failed."));
     return;
   }
 }
@@ -880,18 +878,20 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process()
 bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const
 {
   // Test if the file exists
-  if (!MocEval().PredefsTime.Load(MocConst().PredefsFileAbs)) {
+  if (!this->MocEval().PredefsTime.Load(this->MocConst().PredefsFileAbs)) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs),
+      *reason = cmStrCat("Generating ",
+                         this->MessagePath(this->MocConst().PredefsFileAbs),
                          ", because it doesn't exist.");
     }
     return true;
   }
 
   // Test if the settings changed
-  if (MocConst().SettingsChanged) {
+  if (this->MocConst().SettingsChanged) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs),
+      *reason = cmStrCat("Generating ",
+                         this->MessagePath(this->MocConst().PredefsFileAbs),
                          ", because the moc settings changed.");
     }
     return true;
@@ -899,14 +899,14 @@ bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const
 
   // Test if the executable is newer
   {
-    std::string const& exec = MocConst().PredefsCmd.at(0);
+    std::string const& exec = this->MocConst().PredefsCmd.at(0);
     cmFileTime execTime;
     if (execTime.Load(exec)) {
-      if (MocEval().PredefsTime.Older(execTime)) {
+      if (this->MocEval().PredefsTime.Older(execTime)) {
         if (reason != nullptr) {
-          *reason =
-            cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs),
-                     " because it is older than ", MessagePath(exec), '.');
+          *reason = cmStrCat(
+            "Generating ", this->MessagePath(this->MocConst().PredefsFileAbs),
+            " because it is older than ", this->MessagePath(exec), '.');
         }
         return true;
       }
@@ -919,25 +919,27 @@ bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const
 bool cmQtAutoMocUicT::JobParseT::ReadFile()
 {
   // Clear old parse information
-  FileHandle->ParseData->Clear();
-  std::string const& fileName = FileHandle->FileName;
+  this->FileHandle->ParseData->Clear();
+  std::string const& fileName = this->FileHandle->FileName;
   // Write info
-  if (Log().Verbose()) {
-    Log().Info(GenT::GEN, cmStrCat("Parsing ", MessagePath(fileName)));
+  if (this->Log().Verbose()) {
+    this->Log().Info(GenT::GEN,
+                     cmStrCat("Parsing ", this->MessagePath(fileName)));
   }
   // Read file content
   {
     std::string error;
-    if (!cmQtAutoGenerator::FileRead(Content, fileName, &error)) {
-      LogError(
-        GenT::GEN,
-        cmStrCat("Could not read ", MessagePath(fileName), ".\n", error));
+    if (!cmQtAutoGenerator::FileRead(this->Content, fileName, &error)) {
+      this->LogError(GenT::GEN,
+                     cmStrCat("Could not read ", this->MessagePath(fileName),
+                              ".\n", error));
       return false;
     }
   }
   // Warn if empty
-  if (Content.empty()) {
-    Log().Warning(GenT::GEN, cmStrCat(MessagePath(fileName), " is empty."));
+  if (this->Content.empty()) {
+    this->Log().Warning(GenT::GEN,
+                        cmStrCat(this->MessagePath(fileName), " is empty."));
     return false;
   }
   return true;
@@ -958,16 +960,16 @@ void cmQtAutoMocUicT::JobParseT::CreateKeys(
 
 void cmQtAutoMocUicT::JobParseT::MocMacro()
 {
-  for (KeyExpT const& filter : MocConst().MacroFilters) {
+  for (KeyExpT const& filter : this->MocConst().MacroFilters) {
     // Run a simple find string check
-    if (Content.find(filter.Key) == std::string::npos) {
+    if (this->Content.find(filter.Key) == std::string::npos) {
       continue;
     }
     // Run the expensive regular expression check loop
     cmsys::RegularExpressionMatch match;
-    if (filter.Exp.find(Content.c_str(), match)) {
+    if (filter.Exp.find(this->Content.c_str(), match)) {
       // Keep detected macro name
-      FileHandle->ParseData->Moc.Macro = filter.Key;
+      this->FileHandle->ParseData->Moc.Macro = filter.Key;
       return;
     }
   }
@@ -975,19 +977,20 @@ void cmQtAutoMocUicT::JobParseT::MocMacro()
 
 void cmQtAutoMocUicT::JobParseT::MocDependecies()
 {
-  if (MocConst().DependFilters.empty() || MocConst().CanOutputDependencies) {
+  if (this->MocConst().DependFilters.empty() ||
+      this->MocConst().CanOutputDependencies) {
     return;
   }
 
   // Find dependency strings
   std::set<std::string> parseDepends;
-  for (KeyExpT const& filter : MocConst().DependFilters) {
+  for (KeyExpT const& filter : this->MocConst().DependFilters) {
     // Run a simple find string check
-    if (Content.find(filter.Key) == std::string::npos) {
+    if (this->Content.find(filter.Key) == std::string::npos) {
       continue;
     }
     // Run the expensive regular expression check loop
-    const char* contentChars = Content.c_str();
+    const char* contentChars = this->Content.c_str();
     cmsys::RegularExpressionMatch match;
     while (filter.Exp.find(contentChars, match)) {
       {
@@ -1002,7 +1005,7 @@ void cmQtAutoMocUicT::JobParseT::MocDependecies()
 
   // Store dependency strings
   {
-    auto& Depends = FileHandle->ParseData->Moc.Depends;
+    auto& Depends = this->FileHandle->ParseData->Moc.Depends;
     Depends.reserve(parseDepends.size());
     for (std::string const& item : parseDepends) {
       Depends.emplace_back(item);
@@ -1016,15 +1019,15 @@ void cmQtAutoMocUicT::JobParseT::MocDependecies()
 
 void cmQtAutoMocUicT::JobParseT::MocIncludes()
 {
-  if (Content.find("moc") == std::string::npos) {
+  if (this->Content.find("moc") == std::string::npos) {
     return;
   }
 
   std::set<std::string> underscore;
   std::set<std::string> dot;
   {
-    const char* contentChars = Content.c_str();
-    cmsys::RegularExpression const& regExp = MocConst().RegExpInclude;
+    const char* contentChars = this->Content.c_str();
+    cmsys::RegularExpression const& regExp = this->MocConst().RegExpInclude;
     cmsys::RegularExpressionMatch match;
     while (regExp.find(contentChars, match)) {
       std::string incString = match.match(2);
@@ -1042,21 +1045,21 @@ void cmQtAutoMocUicT::JobParseT::MocIncludes()
       contentChars += match.end();
     }
   }
-  auto& Include = FileHandle->ParseData->Moc.Include;
-  CreateKeys(Include.Underscore, underscore, MocUnderscoreLength);
-  CreateKeys(Include.Dot, dot, 0);
+  auto& Include = this->FileHandle->ParseData->Moc.Include;
+  this->CreateKeys(Include.Underscore, underscore, MocUnderscoreLength);
+  this->CreateKeys(Include.Dot, dot, 0);
 }
 
 void cmQtAutoMocUicT::JobParseT::UicIncludes()
 {
-  if (Content.find("ui_") == std::string::npos) {
+  if (this->Content.find("ui_") == std::string::npos) {
     return;
   }
 
   std::set<std::string> includes;
   {
-    const char* contentChars = Content.c_str();
-    cmsys::RegularExpression const& regExp = UicConst().RegExpInclude;
+    const char* contentChars = this->Content.c_str();
+    cmsys::RegularExpression const& regExp = this->UicConst().RegExpInclude;
     cmsys::RegularExpressionMatch match;
     while (regExp.find(contentChars, match)) {
       includes.emplace(match.match(2));
@@ -1064,39 +1067,40 @@ void cmQtAutoMocUicT::JobParseT::UicIncludes()
       contentChars += match.end();
     }
   }
-  CreateKeys(FileHandle->ParseData->Uic.Include, includes, UiUnderscoreLength);
+  this->CreateKeys(this->FileHandle->ParseData->Uic.Include, includes,
+                   UiUnderscoreLength);
 }
 
 void cmQtAutoMocUicT::JobParseHeaderT::Process()
 {
-  if (!ReadFile()) {
+  if (!this->ReadFile()) {
     return;
   }
   // Moc parsing
-  if (FileHandle->Moc) {
-    MocMacro();
-    MocDependecies();
+  if (this->FileHandle->Moc) {
+    this->MocMacro();
+    this->MocDependecies();
   }
   // Uic parsing
-  if (FileHandle->Uic) {
-    UicIncludes();
+  if (this->FileHandle->Uic) {
+    this->UicIncludes();
   }
 }
 
 void cmQtAutoMocUicT::JobParseSourceT::Process()
 {
-  if (!ReadFile()) {
+  if (!this->ReadFile()) {
     return;
   }
   // Moc parsing
-  if (FileHandle->Moc) {
-    MocMacro();
-    MocDependecies();
-    MocIncludes();
+  if (this->FileHandle->Moc) {
+    this->MocMacro();
+    this->MocDependecies();
+    this->MocIncludes();
   }
   // Uic parsing
-  if (FileHandle->Uic) {
-    UicIncludes();
+  if (this->FileHandle->Uic) {
+    this->UicIncludes();
   }
 }
 
@@ -1104,9 +1108,9 @@ std::string cmQtAutoMocUicT::JobEvalCacheT::MessageSearchLocations() const
 {
   std::string res;
   res.reserve(512);
-  for (std::string const& path : SearchLocations) {
+  for (std::string const& path : this->SearchLocations) {
     res += "  ";
-    res += MessagePath(path);
+    res += this->MessagePath(path);
     res += '\n';
   }
   return res;
@@ -1115,14 +1119,14 @@ std::string cmQtAutoMocUicT::JobEvalCacheT::MessageSearchLocations() const
 void cmQtAutoMocUicT::JobEvalCacheMocT::Process()
 {
   // Evaluate headers
-  for (auto const& pair : BaseEval().Headers) {
-    if (!EvalHeader(pair.second)) {
+  for (auto const& pair : this->BaseEval().Headers) {
+    if (!this->EvalHeader(pair.second)) {
       return;
     }
   }
   // Evaluate sources
-  for (auto const& pair : BaseEval().Sources) {
-    if (!EvalSource(pair.second)) {
+  for (auto const& pair : this->BaseEval().Sources) {
+    if (!this->EvalSource(pair.second)) {
       return;
     }
   }
@@ -1142,14 +1146,16 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalHeader(SourceFileHandleT source)
     handle->SourceFile = std::move(source);
 
     // Absolute build path
-    if (BaseConst().MultiConfig) {
-      handle->OutputFile = Gen()->AbsoluteIncludePath(sourceFile.BuildPath);
+    if (this->BaseConst().MultiConfig) {
+      handle->OutputFile =
+        this->Gen()->AbsoluteIncludePath(sourceFile.BuildPath);
     } else {
-      handle->OutputFile = Gen()->AbsoluteBuildPath(sourceFile.BuildPath);
+      handle->OutputFile =
+        this->Gen()->AbsoluteBuildPath(sourceFile.BuildPath);
     }
 
     // Register mapping in headers map
-    RegisterMapping(handle);
+    this->RegisterMapping(handle);
   }
 
   return true;
@@ -1171,7 +1177,7 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
     cmSystemTools::GetFilenameWithoutLastExtension(sourceFile.FileName);
 
   // For relaxed mode check if the own "moc_" or ".moc" file is included
-  bool const relaxedMode = MocConst().RelaxedMode;
+  bool const relaxedMode = this->MocConst().RelaxedMode;
   bool sourceIncludesMocUnderscore = false;
   bool sourceIncludesDotMoc = false;
   // Check if the sources own "moc_" or ".moc" file is included
@@ -1193,12 +1199,13 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
   // Check if this source needs to be moc processed but doesn't.
   if (!sourceIncludesDotMoc && !parseData.Macro.empty() &&
       !(relaxedMode && sourceIncludesMocUnderscore)) {
-    LogError(GenT::MOC,
-             cmStrCat(MessagePath(sourceFile.FileName), "\ncontains a ",
-                      Quoted(parseData.Macro), " macro, but does not include ",
-                      MessagePath(sourceBase + ".moc"),
-                      "!\nConsider to\n  - add #include \"", sourceBase,
-                      ".moc\"\n  - enable SKIP_AUTOMOC for this file"));
+    this->LogError(GenT::MOC,
+                   cmStrCat(this->MessagePath(sourceFile.FileName),
+                            "\ncontains a ", Quoted(parseData.Macro),
+                            " macro, but does not include ",
+                            this->MessagePath(sourceBase + ".moc"),
+                            "!\nConsider to\n  - add #include \"", sourceBase,
+                            ".moc\"\n  - enable SKIP_AUTOMOC for this file"));
     return false;
   }
 
@@ -1207,14 +1214,16 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
     SourceFileHandleT headerHandle;
     {
       std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base);
-      if (!FindIncludedHeader(headerHandle, sourceDirPrefix, headerBase)) {
-        LogError(GenT::MOC,
-                 cmStrCat(MessagePath(sourceFile.FileName),
-                          "\nincludes the moc file ", MessagePath(incKey.Key),
-                          ",\nbut a header ", MessageHeader(headerBase),
-                          "\ncould not be found "
-                          "in the following directories\n",
-                          MessageSearchLocations()));
+      if (!this->FindIncludedHeader(headerHandle, sourceDirPrefix,
+                                    headerBase)) {
+        this->LogError(
+          GenT::MOC,
+          cmStrCat(this->MessagePath(sourceFile.FileName),
+                   "\nincludes the moc file ", this->MessagePath(incKey.Key),
+                   ",\nbut a header ", this->MessageHeader(headerBase),
+                   "\ncould not be found "
+                   "in the following directories\n",
+                   this->MessageSearchLocations()));
         return false;
       }
     }
@@ -1228,30 +1237,31 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
       // used. This is for KDE4 compatibility.
 
       // Issue a warning
-      Log().Warning(
+      this->Log().Warning(
         GenT::MOC,
-        cmStrCat(MessagePath(sourceFile.FileName), "\ncontains a ",
+        cmStrCat(this->MessagePath(sourceFile.FileName), "\ncontains a ",
                  Quoted(parseData.Macro), " macro, but does not include ",
-                 MessagePath(sourceBase + ".moc"), ".\nInstead it includes ",
-                 MessagePath(incKey.Key), ".\nRunning moc on the source\n  ",
-                 MessagePath(sourceFile.FileName), "!\nBetter include ",
-                 MessagePath(sourceBase + ".moc"),
+                 this->MessagePath(sourceBase + ".moc"),
+                 ".\nInstead it includes ", this->MessagePath(incKey.Key),
+                 ".\nRunning moc on the source\n  ",
+                 this->MessagePath(sourceFile.FileName), "!\nBetter include ",
+                 this->MessagePath(sourceBase + ".moc"),
                  " for compatibility with regular mode.\n",
                  "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
 
       // Create mapping
-      if (!RegisterIncluded(incKey.Key, source, source)) {
+      if (!this->RegisterIncluded(incKey.Key, source, source)) {
         return false;
       }
       continue;
     }
 
     // Check if header is skipped
-    if (MocConst().skipped(headerHandle->FileName)) {
+    if (this->MocConst().skipped(headerHandle->FileName)) {
       continue;
     }
     // Create mapping
-    if (!RegisterIncluded(incKey.Key, source, std::move(headerHandle))) {
+    if (!this->RegisterIncluded(incKey.Key, source, std::move(headerHandle))) {
       return false;
     }
   }
@@ -1264,7 +1274,7 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
       bool const ownMoc = (incKey.Base == sourceBase);
       if (ownMoc && !parseData.Macro.empty()) {
         // Create mapping for the regular use case
-        if (!RegisterIncluded(incKey.Key, source, source)) {
+        if (!this->RegisterIncluded(incKey.Key, source, source)) {
           return false;
         }
         continue;
@@ -1274,50 +1284,54 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
       SourceFileHandleT headerHandle;
       {
         std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base);
-        if (!FindIncludedHeader(headerHandle, sourceDirPrefix, headerBase)) {
-          LogError(
+        if (!this->FindIncludedHeader(headerHandle, sourceDirPrefix,
+                                      headerBase)) {
+          this->LogError(
             GenT::MOC,
             cmStrCat(
-              MessagePath(sourceFile.FileName), "\nincludes the moc file ",
-              MessagePath(incKey.Key),
+              this->MessagePath(sourceFile.FileName),
+              "\nincludes the moc file ", this->MessagePath(incKey.Key),
               ",\nwhich seems to be the moc file from a different source "
               "file.\nCMAKE_AUTOMOC_RELAXED_MODE:\nAlso a matching header ",
-              MessageHeader(headerBase),
+              this->MessageHeader(headerBase),
               "\ncould not be found in the following directories\n",
-              MessageSearchLocations()));
+              this->MessageSearchLocations()));
           return false;
         }
       }
       // Check if header is skipped
-      if (MocConst().skipped(headerHandle->FileName)) {
+      if (this->MocConst().skipped(headerHandle->FileName)) {
         continue;
       }
       // Issue a warning
       if (ownMoc && parseData.Macro.empty()) {
-        Log().Warning(
+        this->Log().Warning(
           GenT::MOC,
-          cmStrCat(MessagePath(sourceFile.FileName),
-                   "\nincludes the moc file ", MessagePath(incKey.Key),
-                   ", but does not contain a\n", MocConst().MacrosString(),
-                   " macro.\nRunning moc on the header\n  ",
-                   MessagePath(headerHandle->FileName), "!\nBetter include ",
-                   MessagePath("moc_" + incKey.Base + ".cpp"),
-                   " for a compatibility with regular mode.\n",
-                   "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
+          cmStrCat(
+            this->MessagePath(sourceFile.FileName), "\nincludes the moc file ",
+            this->MessagePath(incKey.Key), ", but does not contain a\n",
+            this->MocConst().MacrosString(),
+            " macro.\nRunning moc on the header\n  ",
+            this->MessagePath(headerHandle->FileName), "!\nBetter include ",
+            this->MessagePath("moc_" + incKey.Base + ".cpp"),
+            " for a compatibility with regular mode.\n",
+            "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
       } else {
-        Log().Warning(
+        this->Log().Warning(
           GenT::MOC,
-          cmStrCat(MessagePath(sourceFile.FileName),
-                   "\nincludes the moc file ", MessagePath(incKey.Key),
-                   " instead of ", MessagePath("moc_" + incKey.Base + ".cpp"),
-                   ".\nRunning moc on the header\n  ",
-                   MessagePath(headerHandle->FileName), "!\nBetter include ",
-                   MessagePath("moc_" + incKey.Base + ".cpp"),
-                   " for compatibility with regular mode.\n",
-                   "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
+          cmStrCat(
+            this->MessagePath(sourceFile.FileName), "\nincludes the moc file ",
+            this->MessagePath(incKey.Key), " instead of ",
+            this->MessagePath("moc_" + incKey.Base + ".cpp"),
+            ".\nRunning moc on the header\n  ",
+            this->MessagePath(headerHandle->FileName), "!\nBetter include ",
+            this->MessagePath("moc_" + incKey.Base + ".cpp"),
+            " for compatibility with regular mode.\n",
+            "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n"));
       }
       // Create mapping
-      if (!RegisterIncluded(incKey.Key, source, std::move(headerHandle))) {
+      if (!this->RegisterIncluded(incKey.Key, source,
+                                  std::move(headerHandle))) {
         return false;
       }
     }
@@ -1328,26 +1342,27 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource(
       bool const ownMoc = (incKey.Base == sourceBase);
       if (!ownMoc) {
         // Don't allow <BASE>.moc include other than own in regular mode
-        LogError(GenT::MOC,
-                 cmStrCat(MessagePath(sourceFile.FileName),
-                          "\nincludes the moc file ", MessagePath(incKey.Key),
-                          ",\nwhich seems to be the moc file from a different "
-                          "source file.\nThis is not supported.  Include ",
-                          MessagePath(sourceBase + ".moc"),
-                          " to run moc on this source file."));
+        this->LogError(
+          GenT::MOC,
+          cmStrCat(this->MessagePath(sourceFile.FileName),
+                   "\nincludes the moc file ", this->MessagePath(incKey.Key),
+                   ",\nwhich seems to be the moc file from a different "
+                   "source file.\nThis is not supported.  Include ",
+                   this->MessagePath(sourceBase + ".moc"),
+                   " to run moc on this source file."));
         return false;
       }
       // Accept but issue a warning if moc isn't required
       if (parseData.Macro.empty()) {
-        Log().Warning(GenT::MOC,
-                      cmStrCat(MessagePath(sourceFile.FileName),
-                               "\nincludes the moc file ",
-                               MessagePath(incKey.Key),
-                               ", but does not contain a ",
-                               MocConst().MacrosString(), " macro."));
+        this->Log().Warning(
+          GenT::MOC,
+          cmStrCat(this->MessagePath(sourceFile.FileName),
+                   "\nincludes the moc file ", this->MessagePath(incKey.Key),
+                   ", but does not contain a ",
+                   this->MocConst().MacrosString(), " macro."));
       }
       // Create mapping
-      if (!RegisterIncluded(incKey.Key, source, source)) {
+      if (!this->RegisterIncluded(incKey.Key, source, source)) {
         return false;
       }
     }
@@ -1361,7 +1376,7 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader(
   cm::string_view includeBase)
 {
   // Clear search locations
-  SearchLocations.clear();
+  this->SearchLocations.clear();
 
   auto findHeader = [this,
                      &headerHandle](std::string const& basePath) -> bool {
@@ -1377,8 +1392,8 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader(
 
       // Return a known file if it exists already
       {
-        auto it = BaseEval().Headers.find(testPath);
-        if (it != BaseEval().Headers.end()) {
+        auto it = this->BaseEval().Headers.find(testPath);
+        if (it != this->BaseEval().Headers.end()) {
           headerHandle = it->second;
           found = true;
           break;
@@ -1387,7 +1402,8 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader(
 
       // Created and return discovered file entry
       {
-        SourceFileHandleT& handle = MocEval().HeadersDiscovered[testPath];
+        SourceFileHandleT& handle =
+          this->MocEval().HeadersDiscovered[testPath];
         if (!handle) {
           handle = std::make_shared<SourceFileT>(testPath);
           handle->FileTime = fileTime;
@@ -1410,13 +1426,12 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader(
     return true;
   }
   // Search in include directories
-  for (std::string const& path : MocConst().IncludePaths) {
-    if (findHeader(cmStrCat(path, '/', includeBase))) {
-      return true;
-    }
-  }
-  // Return without success
-  return false;
+  auto const& includePaths = this->MocConst().IncludePaths;
+  return std::any_of(
+    includePaths.begin(), includePaths.end(),
+    [&findHeader, &includeBase](std::string const& path) -> bool {
+      return findHeader(cmStrCat(path, '/', includeBase));
+    });
 }
 
 bool cmQtAutoMocUicT::JobEvalCacheMocT::RegisterIncluded(
@@ -1424,24 +1439,24 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::RegisterIncluded(
   SourceFileHandleT sourceFileHandle) const
 {
   // Check if this file is already included
-  MappingHandleT& handle = MocEval().Includes[includeString];
+  MappingHandleT& handle = this->MocEval().Includes[includeString];
   if (handle) {
     // Check if the output file would be generated from different source files
     if (handle->SourceFile != sourceFileHandle) {
       std::string files =
-        cmStrCat("  ", MessagePath(includerFileHandle->FileName), '\n');
+        cmStrCat("  ", this->MessagePath(includerFileHandle->FileName), '\n');
       for (auto const& item : handle->IncluderFiles) {
-        files += cmStrCat("  ", MessagePath(item->FileName), '\n');
+        files += cmStrCat("  ", this->MessagePath(item->FileName), '\n');
       }
-      LogError(
+      this->LogError(
         GenT::MOC,
         cmStrCat("The source files\n", files,
                  "contain the same include string ",
-                 MessagePath(includeString),
+                 this->MessagePath(includeString),
                  ", but\nthe moc file would be generated from different "
                  "source files\n  ",
-                 MessagePath(sourceFileHandle->FileName), " and\n  ",
-                 MessagePath(handle->SourceFile->FileName),
+                 this->MessagePath(sourceFileHandle->FileName), " and\n  ",
+                 this->MessagePath(handle->SourceFile->FileName),
                  ".\nConsider to\n"
                  "  - not include the \"moc_<NAME>.cpp\" file\n"
                  "  - add a directory prefix to a \"<NAME>.moc\" include "
@@ -1460,10 +1475,10 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::RegisterIncluded(
   handle->IncludeString = includeString;
   handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
   handle->SourceFile = std::move(sourceFileHandle);
-  handle->OutputFile = Gen()->AbsoluteIncludePath(includeString);
+  handle->OutputFile = this->Gen()->AbsoluteIncludePath(includeString);
 
   // Register mapping in sources/headers map
-  RegisterMapping(handle);
+  this->RegisterMapping(handle);
   return true;
 }
 
@@ -1471,8 +1486,8 @@ void cmQtAutoMocUicT::JobEvalCacheMocT::RegisterMapping(
   MappingHandleT mappingHandle) const
 {
   auto& regMap = mappingHandle->SourceFile->IsHeader
-    ? MocEval().HeaderMappings
-    : MocEval().SourceMappings;
+    ? this->MocEval().HeaderMappings
+    : this->MocEval().SourceMappings;
   // Check if source file already gets mapped
   auto& regHandle = regMap[mappingHandle->SourceFile->FileName];
   if (!regHandle) {
@@ -1489,24 +1504,24 @@ void cmQtAutoMocUicT::JobEvalCacheMocT::RegisterMapping(
 std::string cmQtAutoMocUicT::JobEvalCacheMocT::MessageHeader(
   cm::string_view headerBase) const
 {
-  return MessagePath(cmStrCat(
+  return this->MessagePath(cmStrCat(
     headerBase, ".{", cmJoin(this->BaseConst().HeaderExtensions, ","), '}'));
 }
 
 void cmQtAutoMocUicT::JobEvalCacheUicT::Process()
 {
   // Prepare buffers
-  SearchLocations.reserve((UicConst().SearchPaths.size() + 1) * 2);
+  this->SearchLocations.reserve((this->UicConst().SearchPaths.size() + 1) * 2);
 
   // Evaluate headers
-  for (auto const& pair : BaseEval().Headers) {
-    if (!EvalFile(pair.second)) {
+  for (auto const& pair : this->BaseEval().Headers) {
+    if (!this->EvalFile(pair.second)) {
       return;
     }
   }
   // Evaluate sources
-  for (auto const& pair : BaseEval().Sources) {
-    if (!EvalFile(pair.second)) {
+  for (auto const& pair : this->BaseEval().Sources) {
+    if (!this->EvalFile(pair.second)) {
       return;
     }
   }
@@ -1522,36 +1537,37 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::EvalFile(
   }
 
   std::string const sourceDirPrefix = SubDirPrefix(sourceFile.FileName);
-  for (IncludeKeyT const& incKey : Include) {
-    // Find .ui file
-    UiName = cmStrCat(incKey.Base, ".ui");
-    if (!FindIncludedUi(sourceDirPrefix, incKey.Dir)) {
-      LogError(GenT::UIC,
-               cmStrCat(MessagePath(sourceFile.FileName),
-                        "\nincludes the uic file ", MessagePath(incKey.Key),
-                        ",\nbut the user interface file ", MessagePath(UiName),
-                        "\ncould not be found in the following directories\n",
-                        MessageSearchLocations()));
-      return false;
-    }
-    // Check if the file is skipped
-    if (UicConst().skipped(UiFileHandle->FileName)) {
-      continue;
-    }
-    // Register mapping
-    if (!RegisterMapping(incKey.Key, sourceFileHandle)) {
-      return false;
-    }
-  }
-
-  return true;
+  return std::all_of(
+    Include.begin(), Include.end(),
+    [this, &sourceDirPrefix, &sourceFile,
+     &sourceFileHandle](IncludeKeyT const& incKey) -> bool {
+      // Find .ui file
+      this->UiName = cmStrCat(incKey.Base, ".ui");
+      if (!this->FindIncludedUi(sourceDirPrefix, incKey.Dir)) {
+        this->LogError(
+          GenT::UIC,
+          cmStrCat(this->MessagePath(sourceFile.FileName),
+                   "\nincludes the uic file ", this->MessagePath(incKey.Key),
+                   ",\nbut the user interface file ",
+                   this->MessagePath(this->UiName),
+                   "\ncould not be found in the following directories\n",
+                   this->MessageSearchLocations()));
+        return false;
+      }
+      // Check if the file is skipped
+      if (this->UicConst().skipped(this->UiFileHandle->FileName)) {
+        return true;
+      }
+      // Register mapping
+      return this->RegisterMapping(incKey.Key, sourceFileHandle);
+    });
 }
 
 bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi(
   cm::string_view sourceDirPrefix, cm::string_view includePrefix)
 {
   // Clear locations buffer
-  SearchLocations.clear();
+  this->SearchLocations.clear();
 
   auto findUi = [this](std::string const& testPath) -> bool {
     std::string const fullPath = this->Gen()->CollapseFullPathTS(testPath);
@@ -1573,25 +1589,25 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi(
   };
 
   // Vicinity of the source
-  if (findUi(cmStrCat(sourceDirPrefix, UiName))) {
+  if (findUi(cmStrCat(sourceDirPrefix, this->UiName))) {
     return true;
   }
   if (!includePrefix.empty()) {
-    if (findUi(cmStrCat(sourceDirPrefix, includePrefix, UiName))) {
+    if (findUi(cmStrCat(sourceDirPrefix, includePrefix, this->UiName))) {
       return true;
     }
   }
   // Additional AUTOUIC search paths
-  auto const& searchPaths = UicConst().SearchPaths;
+  auto const& searchPaths = this->UicConst().SearchPaths;
   if (!searchPaths.empty()) {
     for (std::string const& sPath : searchPaths) {
-      if (findUi(cmStrCat(sPath, '/', UiName))) {
+      if (findUi(cmStrCat(sPath, '/', this->UiName))) {
         return true;
       }
     }
     if (!includePrefix.empty()) {
       for (std::string const& sPath : searchPaths) {
-        if (findUi(cmStrCat(sPath, '/', includePrefix, UiName))) {
+        if (findUi(cmStrCat(sPath, '/', includePrefix, this->UiName))) {
           return true;
         }
       }
@@ -1604,26 +1620,26 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi(
 bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping(
   std::string const& includeString, SourceFileHandleT includerFileHandle)
 {
-  auto& Includes = Gen()->UicEval().Includes;
+  auto& Includes = this->Gen()->UicEval().Includes;
   auto it = Includes.find(includeString);
   if (it != Includes.end()) {
     MappingHandleT const& handle = it->second;
-    if (handle->SourceFile != UiFileHandle) {
+    if (handle->SourceFile != this->UiFileHandle) {
       // The output file already gets generated - from a different .ui file!
       std::string files =
-        cmStrCat("  ", MessagePath(includerFileHandle->FileName), '\n');
+        cmStrCat("  ", this->MessagePath(includerFileHandle->FileName), '\n');
       for (auto const& item : handle->IncluderFiles) {
-        files += cmStrCat("  ", MessagePath(item->FileName), '\n');
+        files += cmStrCat("  ", this->MessagePath(item->FileName), '\n');
       }
-      LogError(
+      this->LogError(
         GenT::UIC,
         cmStrCat(
           "The source files\n", files, "contain the same include string ",
           Quoted(includeString),
           ", but\nthe uic file would be generated from different "
           "user interface files\n  ",
-          MessagePath(UiFileHandle->FileName), " and\n  ",
-          MessagePath(handle->SourceFile->FileName),
+          this->MessagePath(this->UiFileHandle->FileName), " and\n  ",
+          this->MessagePath(handle->SourceFile->FileName),
           ".\nConsider to\n"
           "  - add a directory prefix to a \"ui_<NAME>.h\" include "
           "(e.g \"sub/ui_<NAME>.h\")\n"
@@ -1638,8 +1654,8 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping(
     MappingHandleT handle = std::make_shared<MappingT>();
     handle->IncludeString = includeString;
     handle->IncluderFiles.emplace_back(std::move(includerFileHandle));
-    handle->SourceFile = UiFileHandle;
-    handle->OutputFile = Gen()->AbsoluteIncludePath(includeString);
+    handle->SourceFile = this->UiFileHandle;
+    handle->OutputFile = this->Gen()->AbsoluteIncludePath(includeString);
     // Register mapping
     Includes.emplace(includeString, std::move(handle));
   }
@@ -1649,40 +1665,42 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping(
 void cmQtAutoMocUicT::JobEvalCacheFinishT::Process()
 {
   // Add discovered header parse jobs
-  Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered);
+  this->Gen()->CreateParseJobs<JobParseHeaderT>(
+    this->MocEval().HeadersDiscovered);
 
   // Add dependency probing jobs
   {
     // Add fence job to ensure all parsing has finished
-    Gen()->WorkerPool().EmplaceJob<JobFenceT>();
-    if (MocConst().Enabled) {
-      Gen()->WorkerPool().EmplaceJob<JobProbeDepsMocT>();
+    this->Gen()->WorkerPool().EmplaceJob<JobFenceT>();
+    if (this->MocConst().Enabled) {
+      this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsMocT>();
     }
-    if (UicConst().Enabled) {
-      Gen()->WorkerPool().EmplaceJob<JobProbeDepsUicT>();
+    if (this->UicConst().Enabled) {
+      this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsUicT>();
     }
     // Add probe finish job
-    Gen()->WorkerPool().EmplaceJob<JobProbeDepsFinishT>();
+    this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsFinishT>();
   }
 }
 
 void cmQtAutoMocUicT::JobProbeDepsMocT::Process()
 {
   // Create moc header jobs
-  for (auto const& pair : MocEval().HeaderMappings) {
+  for (auto const& pair : this->MocEval().HeaderMappings) {
     // Register if this mapping is a candidate for mocs_compilation.cpp
     bool const compFile = pair.second->IncludeString.empty();
     if (compFile) {
-      MocEval().CompFiles.emplace_back(pair.second->SourceFile->BuildPath);
+      this->MocEval().CompFiles.emplace_back(
+        pair.second->SourceFile->BuildPath);
     }
-    if (!Generate(pair.second, compFile)) {
+    if (!this->Generate(pair.second, compFile)) {
       return;
     }
   }
 
   // Create moc source jobs
-  for (auto const& pair : MocEval().SourceMappings) {
-    if (!Generate(pair.second, false)) {
+  for (auto const& pair : this->MocEval().SourceMappings) {
+    if (!this->Generate(pair.second, false)) {
       return;
     }
   }
@@ -1692,22 +1710,23 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Generate(MappingHandleT const& mapping,
                                                  bool compFile) const
 {
   std::unique_ptr<std::string> reason;
-  if (Log().Verbose()) {
+  if (this->Log().Verbose()) {
     reason = cm::make_unique<std::string>();
   }
-  if (Probe(*mapping, reason.get())) {
+  if (this->Probe(*mapping, reason.get())) {
     // Register the parent directory for creation
-    MocEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile));
+    this->MocEval().OutputDirs.emplace(
+      cmQtAutoGen::ParentDir(mapping->OutputFile));
     // Fetch the cache entry for the source file
     std::string const& sourceFile = mapping->SourceFile->FileName;
     ParseCacheT::GetOrInsertT cacheEntry =
-      BaseEval().ParseCache.GetOrInsert(sourceFile);
+      this->BaseEval().ParseCache.GetOrInsert(sourceFile);
     // Add moc job
-    Gen()->WorkerPool().EmplaceJob<JobCompileMocT>(
+    this->Gen()->WorkerPool().EmplaceJob<JobCompileMocT>(
       mapping, std::move(reason), std::move(cacheEntry.first));
     // Check if a moc job for a mocs_compilation.cpp entry was generated
     if (compFile) {
-      MocEval().CompUpdated = true;
+      this->MocEval().CompUpdated = true;
     }
   }
   return true;
@@ -1723,19 +1742,19 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping,
   cmFileTime outputFileTime;
   if (!outputFileTime.Load(outputFile)) {
     if (reason != nullptr) {
-      *reason =
-        cmStrCat("Generating ", MessagePath(outputFile),
-                 ", because it doesn't exist, from ", MessagePath(sourceFile));
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+                         ", because it doesn't exist, from ",
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
 
   // Test if any setting changed
-  if (MocConst().SettingsChanged) {
+  if (this->MocConst().SettingsChanged) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(outputFile),
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                          ", because the uic settings changed, from ",
-                         MessagePath(sourceFile));
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
@@ -1743,32 +1762,32 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping,
   // Test if the source file is newer
   if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(outputFile),
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                          ", because it's older than its source file, from ",
-                         MessagePath(sourceFile));
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
 
   // Test if the moc_predefs file is newer
-  if (!MocConst().PredefsFileAbs.empty()) {
-    if (outputFileTime.Older(MocEval().PredefsTime)) {
+  if (!this->MocConst().PredefsFileAbs.empty()) {
+    if (outputFileTime.Older(this->MocEval().PredefsTime)) {
       if (reason != nullptr) {
-        *reason = cmStrCat("Generating ", MessagePath(outputFile),
+        *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                            ", because it's older than ",
-                           MessagePath(MocConst().PredefsFileAbs), ", from ",
-                           MessagePath(sourceFile));
+                           this->MessagePath(this->MocConst().PredefsFileAbs),
+                           ", from ", this->MessagePath(sourceFile));
       }
       return true;
     }
   }
 
   // Test if the moc executable is newer
-  if (outputFileTime.Older(MocConst().ExecutableTime)) {
+  if (outputFileTime.Older(this->MocConst().ExecutableTime)) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(outputFile),
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                          ", because it's older than the moc executable, from ",
-                         MessagePath(sourceFile));
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
@@ -1782,26 +1801,26 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping,
       auto& dep = *it;
 
       // Find dependency file
-      auto const depMatch = FindDependency(sourceDir, dep);
+      auto const depMatch = this->FindDependency(sourceDir, dep);
       if (depMatch.first.empty()) {
         if (reason != nullptr) {
-          *reason =
-            cmStrCat("Generating ", MessagePath(outputFile), " from ",
-                     MessagePath(sourceFile), ", because its dependency ",
-                     MessagePath(dep), " vanished.");
+          *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+                             " from ", this->MessagePath(sourceFile),
+                             ", because its dependency ",
+                             this->MessagePath(dep), " vanished.");
         }
         dependencies.erase(it);
-        BaseEval().ParseCacheChanged = true;
+        this->BaseEval().ParseCacheChanged = true;
         return true;
       }
 
       // Test if dependency file is older
       if (outputFileTime.Older(depMatch.second)) {
         if (reason != nullptr) {
-          *reason = cmStrCat("Generating ", MessagePath(outputFile),
+          *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                              ", because it's older than its dependency file ",
-                             MessagePath(depMatch.first), ", from ",
-                             MessagePath(sourceFile));
+                             this->MessagePath(depMatch.first), ", from ",
+                             this->MessagePath(sourceFile));
         }
         return true;
       }
@@ -1817,7 +1836,7 @@ cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency(
 {
   using ResPair = std::pair<std::string, cmFileTime>;
   // moc's dependency file contains absolute paths
-  if (MocConst().CanOutputDependencies) {
+  if (this->MocConst().CanOutputDependencies) {
     ResPair res{ includeString, {} };
     if (res.second.Load(res.first)) {
       return res;
@@ -1832,7 +1851,7 @@ cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency(
     }
   }
   // Search in include directories
-  for (std::string const& includePath : MocConst().IncludePaths) {
+  for (std::string const& includePath : this->MocConst().IncludePaths) {
     ResPair res{ cmStrCat(includePath, '/', includeString), {} };
     if (res.second.Load(res.first)) {
       return res;
@@ -1844,20 +1863,22 @@ cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency(
 
 void cmQtAutoMocUicT::JobProbeDepsUicT::Process()
 {
-  for (auto const& pair : Gen()->UicEval().Includes) {
+  for (auto const& pair : this->Gen()->UicEval().Includes) {
     MappingHandleT const& mapping = pair.second;
     std::unique_ptr<std::string> reason;
-    if (Log().Verbose()) {
+    if (this->Log().Verbose()) {
       reason = cm::make_unique<std::string>();
     }
-    if (!Probe(*mapping, reason.get())) {
+    if (!this->Probe(*mapping, reason.get())) {
       continue;
     }
 
     // Register the parent directory for creation
-    UicEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile));
+    this->UicEval().OutputDirs.emplace(
+      cmQtAutoGen::ParentDir(mapping->OutputFile));
     // Add uic job
-    Gen()->WorkerPool().EmplaceJob<JobCompileUicT>(mapping, std::move(reason));
+    this->Gen()->WorkerPool().EmplaceJob<JobCompileUicT>(mapping,
+                                                         std::move(reason));
   }
 }
 
@@ -1871,19 +1892,19 @@ bool cmQtAutoMocUicT::JobProbeDepsUicT::Probe(MappingT const& mapping,
   cmFileTime outputFileTime;
   if (!outputFileTime.Load(outputFile)) {
     if (reason != nullptr) {
-      *reason =
-        cmStrCat("Generating ", MessagePath(outputFile),
-                 ", because it doesn't exist, from ", MessagePath(sourceFile));
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
+                         ", because it doesn't exist, from ",
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
 
   // Test if the uic settings changed
-  if (UicConst().SettingsChanged) {
+  if (this->UicConst().SettingsChanged) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(outputFile),
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                          ", because the uic settings changed, from ",
-                         MessagePath(sourceFile));
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
@@ -1891,19 +1912,19 @@ bool cmQtAutoMocUicT::JobProbeDepsUicT::Probe(MappingT const& mapping,
   // Test if the source file is newer
   if (outputFileTime.Older(mapping.SourceFile->FileTime)) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(outputFile),
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                          " because it's older than the source file ",
-                         MessagePath(sourceFile));
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
 
   // Test if the uic executable is newer
-  if (outputFileTime.Older(UicConst().ExecutableTime)) {
+  if (outputFileTime.Older(this->UicConst().ExecutableTime)) {
     if (reason != nullptr) {
-      *reason = cmStrCat("Generating ", MessagePath(outputFile),
+      *reason = cmStrCat("Generating ", this->MessagePath(outputFile),
                          ", because it's older than the uic executable, from ",
-                         MessagePath(sourceFile));
+                         this->MessagePath(sourceFile));
     }
     return true;
   }
@@ -1919,64 +1940,64 @@ void cmQtAutoMocUicT::JobProbeDepsFinishT::Process()
     auto createDirs = [this](GenT genType, StringSet const& dirSet) {
       for (std::string const& dirName : dirSet) {
         if (!cmSystemTools::MakeDirectory(dirName)) {
-          this->LogError(
-            genType,
-            cmStrCat("Creating directory ", MessagePath(dirName), " failed."));
+          this->LogError(genType,
+                         cmStrCat("Creating directory ",
+                                  this->MessagePath(dirName), " failed."));
           return;
         }
       }
     };
-    if (MocConst().Enabled && UicConst().Enabled) {
-      StringSet outputDirs = MocEval().OutputDirs;
-      outputDirs.insert(UicEval().OutputDirs.begin(),
-                        UicEval().OutputDirs.end());
+    if (this->MocConst().Enabled && this->UicConst().Enabled) {
+      StringSet outputDirs = this->MocEval().OutputDirs;
+      outputDirs.insert(this->UicEval().OutputDirs.begin(),
+                        this->UicEval().OutputDirs.end());
       createDirs(GenT::GEN, outputDirs);
-    } else if (MocConst().Enabled) {
-      createDirs(GenT::MOC, MocEval().OutputDirs);
-    } else if (UicConst().Enabled) {
-      createDirs(GenT::UIC, UicEval().OutputDirs);
+    } else if (this->MocConst().Enabled) {
+      createDirs(GenT::MOC, this->MocEval().OutputDirs);
+    } else if (this->UicConst().Enabled) {
+      createDirs(GenT::UIC, this->UicEval().OutputDirs);
     }
   }
 
-  if (MocConst().Enabled) {
+  if (this->MocConst().Enabled) {
     // Add mocs compilations job
-    Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>();
+    this->Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>();
   }
 
-  if (!BaseConst().DepFile.empty()) {
+  if (!this->BaseConst().DepFile.empty()) {
     // Add job to merge dep files
-    Gen()->WorkerPool().EmplaceJob<JobDepFilesMergeT>();
+    this->Gen()->WorkerPool().EmplaceJob<JobDepFilesMergeT>();
   }
 
   // Add finish job
-  Gen()->WorkerPool().EmplaceJob<JobFinishT>();
+  this->Gen()->WorkerPool().EmplaceJob<JobFinishT>();
 }
 
 void cmQtAutoMocUicT::JobCompileMocT::Process()
 {
-  std::string const& sourceFile = Mapping->SourceFile->FileName;
-  std::string const& outputFile = Mapping->OutputFile;
+  std::string const& sourceFile = this->Mapping->SourceFile->FileName;
+  std::string const& outputFile = this->Mapping->OutputFile;
 
   // Compose moc command
   std::vector<std::string> cmd;
   {
     // Reserve large enough
-    cmd.reserve(MocConst().OptionsDefinitions.size() +
-                MocConst().OptionsIncludes.size() +
-                MocConst().OptionsExtra.size() + 16);
-    cmd.push_back(MocConst().Executable);
+    cmd.reserve(this->MocConst().OptionsDefinitions.size() +
+                this->MocConst().OptionsIncludes.size() +
+                this->MocConst().OptionsExtra.size() + 16);
+    cmd.push_back(this->MocConst().Executable);
     // Add definitions
-    cm::append(cmd, MocConst().OptionsDefinitions);
+    cm::append(cmd, this->MocConst().OptionsDefinitions);
     // Add includes
-    cm::append(cmd, MocConst().OptionsIncludes);
+    cm::append(cmd, this->MocConst().OptionsIncludes);
     // Add predefs include
-    if (!MocConst().PredefsFileAbs.empty()) {
+    if (!this->MocConst().PredefsFileAbs.empty()) {
       cmd.emplace_back("--include");
-      cmd.push_back(MocConst().PredefsFileAbs);
+      cmd.push_back(this->MocConst().PredefsFileAbs);
     }
     // Add path prefix on demand
-    if (MocConst().PathPrefix && Mapping->SourceFile->IsHeader) {
-      for (std::string const& dir : MocConst().IncludePaths) {
+    if (this->MocConst().PathPrefix && this->Mapping->SourceFile->IsHeader) {
+      for (std::string const& dir : this->MocConst().IncludePaths) {
         cm::string_view prefix = sourceFile;
         if (cmHasPrefix(prefix, dir)) {
           prefix.remove_prefix(dir.size());
@@ -1996,8 +2017,8 @@ void cmQtAutoMocUicT::JobCompileMocT::Process()
       }
     }
     // Add extra options
-    cm::append(cmd, MocConst().OptionsExtra);
-    if (MocConst().CanOutputDependencies) {
+    cm::append(cmd, this->MocConst().OptionsExtra);
+    if (this->MocConst().CanOutputDependencies) {
       cmd.emplace_back("--output-dep-file");
     }
     // Add output file
@@ -2009,60 +2030,60 @@ void cmQtAutoMocUicT::JobCompileMocT::Process()
 
   // Execute moc command
   cmWorkerPool::ProcessResultT result;
-  if (!RunProcess(GenT::MOC, result, cmd, Reason.get())) {
+  if (!this->RunProcess(GenT::MOC, result, cmd, this->Reason.get())) {
     // Moc command failed
     std::string includers;
-    if (!Mapping->IncluderFiles.empty()) {
+    if (!this->Mapping->IncluderFiles.empty()) {
       includers = "included by\n";
-      for (auto const& item : Mapping->IncluderFiles) {
-        includers += cmStrCat("  ", MessagePath(item->FileName), '\n');
+      for (auto const& item : this->Mapping->IncluderFiles) {
+        includers += cmStrCat("  ", this->MessagePath(item->FileName), '\n');
       }
     }
-    LogCommandError(GenT::MOC,
-                    cmStrCat("The moc process failed to compile\n  ",
-                             MessagePath(sourceFile), "\ninto\n  ",
-                             MessagePath(outputFile), '\n', includers,
-                             result.ErrorMessage),
-                    cmd, result.StdOut);
+    this->LogCommandError(GenT::MOC,
+                          cmStrCat("The moc process failed to compile\n  ",
+                                   this->MessagePath(sourceFile), "\ninto\n  ",
+                                   this->MessagePath(outputFile), '\n',
+                                   includers, result.ErrorMessage),
+                          cmd, result.StdOut);
     return;
   }
 
   // Moc command success. Print moc output.
   if (!result.StdOut.empty()) {
-    Log().Info(GenT::MOC, result.StdOut);
+    this->Log().Info(GenT::MOC, result.StdOut);
   }
 
   // Extract dependencies from the dep file moc generated for us
-  if (MocConst().CanOutputDependencies) {
+  if (this->MocConst().CanOutputDependencies) {
     const std::string depfile = outputFile + ".d";
-    if (Log().Verbose()) {
-      Log().Info(GenT::MOC,
-                 "Reading dependencies from " + MessagePath(depfile));
+    if (this->Log().Verbose()) {
+      this->Log().Info(
+        GenT::MOC, "Reading dependencies from " + this->MessagePath(depfile));
     }
     if (!cmSystemTools::FileExists(depfile)) {
-      Log().Warning(GenT::MOC,
-                    "Dependency file " + MessagePath(depfile) +
-                      " does not exist.");
+      this->Log().Warning(GenT::MOC,
+                          "Dependency file " + this->MessagePath(depfile) +
+                            " does not exist.");
       return;
     }
-    CacheEntry->Moc.Depends = dependenciesFromDepFile(depfile.c_str());
+    this->CacheEntry->Moc.Depends = dependenciesFromDepFile(depfile.c_str());
   }
 }
 
 void cmQtAutoMocUicT::JobCompileUicT::Process()
 {
-  std::string const& sourceFile = Mapping->SourceFile->FileName;
-  std::string const& outputFile = Mapping->OutputFile;
+  std::string const& sourceFile = this->Mapping->SourceFile->FileName;
+  std::string const& outputFile = this->Mapping->OutputFile;
 
   // Compose uic command
   std::vector<std::string> cmd;
-  cmd.push_back(UicConst().Executable);
+  cmd.push_back(this->UicConst().Executable);
   {
-    std::vector<std::string> allOpts = UicConst().Options;
-    auto optionIt = UicConst().UiFiles.find(sourceFile);
-    if (optionIt != UicConst().UiFiles.end()) {
+    std::vector<std::string> allOpts = this->UicConst().Options;
+    auto optionIt = this->UicConst().UiFiles.find(sourceFile);
+    if (optionIt != this->UicConst().UiFiles.end()) {
       UicMergeOptions(allOpts, optionIt->second.Options,
-                      (BaseConst().QtVersion.Major == 5));
+                      (this->BaseConst().QtVersion.Major == 5));
     }
     cm::append(cmd, allOpts);
   }
@@ -2071,24 +2092,25 @@ void cmQtAutoMocUicT::JobCompileUicT::Process()
   cmd.emplace_back(sourceFile);
 
   cmWorkerPool::ProcessResultT result;
-  if (RunProcess(GenT::UIC, result, cmd, Reason.get())) {
+  if (this->RunProcess(GenT::UIC, result, cmd, this->Reason.get())) {
     // Uic command success
     // Print uic output
     if (!result.StdOut.empty()) {
-      Log().Info(GenT::UIC, result.StdOut);
+      this->Log().Info(GenT::UIC, result.StdOut);
     }
   } else {
     // Uic command failed
     std::string includers;
-    for (auto const& item : Mapping->IncluderFiles) {
-      includers += cmStrCat("  ", MessagePath(item->FileName), '\n');
+    for (auto const& item : this->Mapping->IncluderFiles) {
+      includers += cmStrCat("  ", this->MessagePath(item->FileName), '\n');
     }
-    LogCommandError(GenT::UIC,
-                    cmStrCat("The uic process failed to compile\n  ",
-                             MessagePath(sourceFile), "\ninto\n  ",
-                             MessagePath(outputFile), "\nincluded by\n",
-                             includers, result.ErrorMessage),
-                    cmd, result.StdOut);
+    this->LogCommandError(GenT::UIC,
+                          cmStrCat("The uic process failed to compile\n  ",
+                                   this->MessagePath(sourceFile), "\ninto\n  ",
+                                   this->MessagePath(outputFile),
+                                   "\nincluded by\n", includers,
+                                   result.ErrorMessage),
+                          cmd, result.StdOut);
   }
 }
 
@@ -2098,41 +2120,41 @@ void cmQtAutoMocUicT::JobMocsCompilationT::Process()
   std::string content =
     "// This file is autogenerated. Changes will be overwritten.\n";
 
-  if (MocEval().CompFiles.empty()) {
+  if (this->MocEval().CompFiles.empty()) {
     // Placeholder content
     content += "// No files found that require moc or the moc files are "
                "included\n"
                "enum some_compilers { need_more_than_nothing };\n";
   } else {
     // Valid content
-    const bool mc = BaseConst().MultiConfig;
+    const bool mc = this->BaseConst().MultiConfig;
     cm::string_view const wrapFront = mc ? "#include <" : "#include \"";
     cm::string_view const wrapBack = mc ? ">\n" : "\"\n";
-    content += cmWrap(wrapFront, MocEval().CompFiles, wrapBack, "");
+    content += cmWrap(wrapFront, this->MocEval().CompFiles, wrapBack, "");
   }
 
-  std::string const& compAbs = MocConst().CompFileAbs;
+  std::string const& compAbs = this->MocConst().CompFileAbs;
   if (cmQtAutoGenerator::FileDiffers(compAbs, content)) {
     // Actually write mocs compilation file
-    if (Log().Verbose()) {
-      Log().Info(GenT::MOC,
-                 "Generating MOC compilation " + MessagePath(compAbs));
+    if (this->Log().Verbose()) {
+      this->Log().Info(
+        GenT::MOC, "Generating MOC compilation " + this->MessagePath(compAbs));
     }
     if (!FileWrite(compAbs, content)) {
-      LogError(GenT::MOC,
-               cmStrCat("Writing MOC compilation ", MessagePath(compAbs),
-                        " failed."));
+      this->LogError(GenT::MOC,
+                     cmStrCat("Writing MOC compilation ",
+                              this->MessagePath(compAbs), " failed."));
     }
-  } else if (MocEval().CompUpdated) {
+  } else if (this->MocEval().CompUpdated) {
     // Only touch mocs compilation file
-    if (Log().Verbose()) {
-      Log().Info(GenT::MOC,
-                 "Touching MOC compilation " + MessagePath(compAbs));
+    if (this->Log().Verbose()) {
+      this->Log().Info(
+        GenT::MOC, "Touching MOC compilation " + this->MessagePath(compAbs));
     }
     if (!cmSystemTools::Touch(compAbs, false)) {
-      LogError(GenT::MOC,
-               cmStrCat("Touching MOC compilation ", MessagePath(compAbs),
-                        " failed."));
+      this->LogError(GenT::MOC,
+                     cmStrCat("Touching MOC compilation ",
+                              this->MessagePath(compAbs), " failed."));
     }
   }
 }
@@ -2169,12 +2191,36 @@ std::string escapeDependencyPath(cm::string_view path)
   return escapedPath;
 }
 
+/*
+ * Return the initial dependencies of the merged depfile.
+ * Those are dependencies from the project files, not from moc runs.
+ */
+std::vector<std::string>
+cmQtAutoMocUicT::JobDepFilesMergeT::initialDependencies() const
+{
+  std::vector<std::string> dependencies;
+  dependencies.reserve(this->BaseConst().ListFiles.size() +
+                       this->BaseEval().Headers.size() +
+                       this->BaseEval().Sources.size());
+  cm::append(dependencies, this->BaseConst().ListFiles);
+  auto append_file_path =
+    [&dependencies](const SourceFileMapT::value_type& p) {
+      dependencies.push_back(p.first);
+    };
+  std::for_each(this->BaseEval().Headers.begin(),
+                this->BaseEval().Headers.end(), append_file_path);
+  std::for_each(this->BaseEval().Sources.begin(),
+                this->BaseEval().Sources.end(), append_file_path);
+  return dependencies;
+}
+
 void cmQtAutoMocUicT::JobDepFilesMergeT::Process()
 {
-  if (Log().Verbose()) {
-    Log().Info(GenT::MOC,
-               cmStrCat("Merging MOC dependencies into ",
-                        MessagePath(BaseConst().DepFile.c_str())));
+  if (this->Log().Verbose()) {
+    this->Log().Info(
+      GenT::MOC,
+      cmStrCat("Merging MOC dependencies into ",
+               this->MessagePath(this->BaseConst().DepFile.c_str())));
   }
   auto processDepFile =
     [](const std::string& mocOutputFile) -> std::vector<std::string> {
@@ -2185,8 +2231,8 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process()
     return dependenciesFromDepFile(f.c_str());
   };
 
-  std::vector<std::string> dependencies = BaseConst().ListFiles;
-  ParseCacheT& parseCache = BaseEval().ParseCache;
+  std::vector<std::string> dependencies = this->initialDependencies();
+  ParseCacheT& parseCache = this->BaseEval().ParseCache;
   auto processMappingEntry = [&](const MappingMapT::value_type& m) {
     auto cacheEntry = parseCache.GetOrInsert(m.first);
     if (cacheEntry.first->Moc.Depends.empty()) {
@@ -2197,10 +2243,10 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process()
                         cacheEntry.first->Moc.Depends.end());
   };
 
-  std::for_each(MocEval().HeaderMappings.begin(),
-                MocEval().HeaderMappings.end(), processMappingEntry);
-  std::for_each(MocEval().SourceMappings.begin(),
-                MocEval().SourceMappings.end(), processMappingEntry);
+  std::for_each(this->MocEval().HeaderMappings.begin(),
+                this->MocEval().HeaderMappings.end(), processMappingEntry);
+  std::for_each(this->MocEval().SourceMappings.begin(),
+                this->MocEval().SourceMappings.end(), processMappingEntry);
 
   // Remove duplicates to make the depfile smaller
   std::sort(dependencies.begin(), dependencies.end());
@@ -2208,39 +2254,42 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process()
                      dependencies.end());
 
   // Add form files
-  for (const auto& uif : UicEval().UiFiles) {
+  for (const auto& uif : this->UicEval().UiFiles) {
     dependencies.push_back(uif.first);
   }
 
   // Write the file
   cmsys::ofstream ofs;
-  ofs.open(BaseConst().DepFile.c_str(),
+  ofs.open(this->BaseConst().DepFile.c_str(),
            (std::ios::out | std::ios::binary | std::ios::trunc));
   if (!ofs) {
-    LogError(GenT::GEN,
-             cmStrCat("Cannot open ", MessagePath(BaseConst().DepFile),
-                      " for writing."));
+    this->LogError(GenT::GEN,
+                   cmStrCat("Cannot open ",
+                            this->MessagePath(this->BaseConst().DepFile),
+                            " for writing."));
     return;
   }
-  ofs << BaseConst().DepFileRuleName << ": \\\n";
+  ofs << this->BaseConst().DepFileRuleName << ": \\\n";
   for (const std::string& file : dependencies) {
     ofs << '\t' << escapeDependencyPath(file) << " \\\n";
     if (!ofs.good()) {
-      LogError(GenT::GEN,
-               cmStrCat("Writing depfile", MessagePath(BaseConst().DepFile),
-                        " failed."));
+      this->LogError(GenT::GEN,
+                     cmStrCat("Writing depfile",
+                              this->MessagePath(this->BaseConst().DepFile),
+                              " failed."));
       return;
     }
   }
 
   // Add the CMake executable to re-new cache data if necessary.
   // Also, this is the last entry, so don't add a backslash.
-  ofs << '\t' << escapeDependencyPath(BaseConst().CMakeExecutable) << '\n';
+  ofs << '\t' << escapeDependencyPath(this->BaseConst().CMakeExecutable)
+      << '\n';
 }
 
 void cmQtAutoMocUicT::JobFinishT::Process()
 {
-  Gen()->AbortSuccess();
+  this->Gen()->AbortSuccess();
 }
 
 cmQtAutoMocUicT::cmQtAutoMocUicT()
@@ -2252,42 +2301,51 @@ cmQtAutoMocUicT::~cmQtAutoMocUicT() = default;
 bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
 {
   // -- Required settings
-  if (!info.GetBool("MULTI_CONFIG", BaseConst_.MultiConfig, true) ||
-      !info.GetUInt("QT_VERSION_MAJOR", BaseConst_.QtVersion.Major, true) ||
-      !info.GetUInt("QT_VERSION_MINOR", BaseConst_.QtVersion.Minor, true) ||
-      !info.GetUInt("PARALLEL", BaseConst_.ThreadCount, false) ||
-      !info.GetString("BUILD_DIR", BaseConst_.AutogenBuildDir, true) ||
-      !info.GetStringConfig("INCLUDE_DIR", BaseConst_.AutogenIncludeDir,
+  if (!info.GetBool("MULTI_CONFIG", this->BaseConst_.MultiConfig, true) ||
+      !info.GetUInt("QT_VERSION_MAJOR", this->BaseConst_.QtVersion.Major,
+                    true) ||
+      !info.GetUInt("QT_VERSION_MINOR", this->BaseConst_.QtVersion.Minor,
+                    true) ||
+      !info.GetUInt("PARALLEL", this->BaseConst_.ThreadCount, false) ||
+      !info.GetString("BUILD_DIR", this->BaseConst_.AutogenBuildDir, true) ||
+      !info.GetStringConfig("INCLUDE_DIR", this->BaseConst_.AutogenIncludeDir,
                             true) ||
-      !info.GetString("CMAKE_EXECUTABLE", BaseConst_.CMakeExecutable, true) ||
-      !info.GetStringConfig("PARSE_CACHE_FILE", BaseConst_.ParseCacheFile,
-                            true) ||
-      !info.GetString("DEP_FILE", BaseConst_.DepFile, false) ||
-      !info.GetString("DEP_FILE_RULE_NAME", BaseConst_.DepFileRuleName,
+      !info.GetString("CMAKE_EXECUTABLE", this->BaseConst_.CMakeExecutable,
+                      true) ||
+      !info.GetStringConfig("PARSE_CACHE_FILE",
+                            this->BaseConst_.ParseCacheFile, true) ||
+      !info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) ||
+      !info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName,
+                      false) ||
+      !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) ||
+      !info.GetArray("CMAKE_LIST_FILES", this->BaseConst_.ListFiles, true) ||
+      !info.GetArray("HEADER_EXTENSIONS", this->BaseConst_.HeaderExtensions,
+                     true) ||
+      !info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable,
                       false) ||
-      !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) ||
-      !info.GetArray("CMAKE_LIST_FILES", BaseConst_.ListFiles, true) ||
-      !info.GetArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) ||
-      !info.GetString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) ||
-      !info.GetString("QT_UIC_EXECUTABLE", UicConst_.Executable, false)) {
+      !info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable,
+                      false)) {
     return false;
   }
 
   // -- Checks
-  if (!BaseConst_.CMakeExecutableTime.Load(BaseConst_.CMakeExecutable)) {
-    return info.LogError(cmStrCat("The CMake executable ",
-                                  MessagePath(BaseConst_.CMakeExecutable),
-                                  " does not exist."));
+  if (!this->BaseConst_.CMakeExecutableTime.Load(
+        this->BaseConst_.CMakeExecutable)) {
+    return info.LogError(
+      cmStrCat("The CMake executable ",
+               this->MessagePath(this->BaseConst_.CMakeExecutable),
+               " does not exist."));
   }
 
   // -- Evaluate values
-  BaseConst_.ThreadCount = std::min(BaseConst_.ThreadCount, ParallelMax);
-  WorkerPool_.SetThreadCount(BaseConst_.ThreadCount);
+  this->BaseConst_.ThreadCount =
+    std::min(this->BaseConst_.ThreadCount, ParallelMax);
+  this->WorkerPool_.SetThreadCount(this->BaseConst_.ThreadCount);
 
   // -- Moc
-  if (!MocConst_.Executable.empty()) {
+  if (!this->MocConst_.Executable.empty()) {
     // -- Moc is enabled
-    MocConst_.Enabled = true;
+    this->MocConst_.Enabled = true;
 
     // -- Temporary buffers
     struct
@@ -2297,18 +2355,21 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
     } tmp;
 
     // -- Required settings
-    if (!info.GetBool("MOC_RELAXED_MODE", MocConst_.RelaxedMode, false) ||
-        !info.GetBool("MOC_PATH_PREFIX", MocConst_.PathPrefix, true) ||
-        !info.GetArray("MOC_SKIP", MocConst_.SkipList, false) ||
-        !info.GetArrayConfig("MOC_DEFINITIONS", MocConst_.Definitions,
+    if (!info.GetBool("MOC_RELAXED_MODE", this->MocConst_.RelaxedMode,
+                      false) ||
+        !info.GetBool("MOC_PATH_PREFIX", this->MocConst_.PathPrefix, true) ||
+        !info.GetArray("MOC_SKIP", this->MocConst_.SkipList, false) ||
+        !info.GetArrayConfig("MOC_DEFINITIONS", this->MocConst_.Definitions,
+                             false) ||
+        !info.GetArrayConfig("MOC_INCLUDES", this->MocConst_.IncludePaths,
                              false) ||
-        !info.GetArrayConfig("MOC_INCLUDES", MocConst_.IncludePaths, false) ||
-        !info.GetArray("MOC_OPTIONS", MocConst_.OptionsExtra, false) ||
-        !info.GetStringConfig("MOC_COMPILATION_FILE", MocConst_.CompFileAbs,
-                              true) ||
-        !info.GetArray("MOC_PREDEFS_CMD", MocConst_.PredefsCmd, false) ||
-        !info.GetStringConfig("MOC_PREDEFS_FILE", MocConst_.PredefsFileAbs,
-                              !MocConst_.PredefsCmd.empty()) ||
+        !info.GetArray("MOC_OPTIONS", this->MocConst_.OptionsExtra, false) ||
+        !info.GetStringConfig("MOC_COMPILATION_FILE",
+                              this->MocConst_.CompFileAbs, true) ||
+        !info.GetArray("MOC_PREDEFS_CMD", this->MocConst_.PredefsCmd, false) ||
+        !info.GetStringConfig("MOC_PREDEFS_FILE",
+                              this->MocConst_.PredefsFileAbs,
+                              !this->MocConst_.PredefsCmd.empty()) ||
         !info.GetArray("MOC_MACRO_NAMES", tmp.MacroNames, true) ||
         !info.GetArray("MOC_DEPEND_FILTERS", tmp.DependFilters, false)) {
       return false;
@@ -2316,12 +2377,12 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
 
     // -- Evaluate settings
     for (std::string const& item : tmp.MacroNames) {
-      MocConst_.MacroFilters.emplace_back(
+      this->MocConst_.MacroFilters.emplace_back(
         item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
     }
     // Can moc output dependencies or do we need to setup dependency filters?
-    if (BaseConst_.QtVersion >= IntegerVersion(5, 15)) {
-      MocConst_.CanOutputDependencies = true;
+    if (this->BaseConst_.QtVersion >= IntegerVersion(5, 15)) {
+      this->MocConst_.CanOutputDependencies = true;
     } else {
       Json::Value const& val = info.GetValue("MOC_DEPEND_FILTERS");
       if (!val.isArray()) {
@@ -2371,22 +2432,23 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
       }
     }
     // Check if moc executable exists (by reading the file time)
-    if (!MocConst_.ExecutableTime.Load(MocConst_.Executable)) {
-      return info.LogError(cmStrCat("The moc executable ",
-                                    MessagePath(MocConst_.Executable),
-                                    " does not exist."));
+    if (!this->MocConst_.ExecutableTime.Load(this->MocConst_.Executable)) {
+      return info.LogError(cmStrCat(
+        "The moc executable ", this->MessagePath(this->MocConst_.Executable),
+        " does not exist."));
     }
   }
 
   // -- Uic
-  if (!UicConst_.Executable.empty()) {
+  if (!this->UicConst_.Executable.empty()) {
     // Uic is enabled
-    UicConst_.Enabled = true;
+    this->UicConst_.Enabled = true;
 
     // -- Required settings
-    if (!info.GetArray("UIC_SKIP", UicConst_.SkipList, false) ||
-        !info.GetArray("UIC_SEARCH_PATHS", UicConst_.SearchPaths, false) ||
-        !info.GetArrayConfig("UIC_OPTIONS", UicConst_.Options, false)) {
+    if (!info.GetArray("UIC_SKIP", this->UicConst_.SkipList, false) ||
+        !info.GetArray("UIC_SEARCH_PATHS", this->UicConst_.SearchPaths,
+                       false) ||
+        !info.GetArrayConfig("UIC_OPTIONS", this->UicConst_.Options, false)) {
       return false;
     }
     // .ui files
@@ -2420,17 +2482,17 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
           return false;
         }
 
-        auto& uiFile = UicConst_.UiFiles[entryName.asString()];
+        auto& uiFile = this->UicConst_.UiFiles[entryName.asString()];
         InfoT::GetJsonArray(uiFile.Options, entryOptions);
       }
     }
 
     // -- Evaluate settings
     // Check if uic executable exists (by reading the file time)
-    if (!UicConst_.ExecutableTime.Load(UicConst_.Executable)) {
-      return info.LogError(cmStrCat("The uic executable ",
-                                    MessagePath(UicConst_.Executable),
-                                    " does not exist."));
+    if (!this->UicConst_.ExecutableTime.Load(this->UicConst_.Executable)) {
+      return info.LogError(cmStrCat(
+        "The uic executable ", this->MessagePath(this->UicConst_.Executable),
+        " does not exist."));
     }
   }
 
@@ -2452,17 +2514,20 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
 
       Json::Value const& entry = val[ii];
       if (testEntry(entry.isArray(), "JSON value is not an array.") ||
-          testEntry(entry.size() == 3, "JSON array size invalid.")) {
+          testEntry(entry.size() == 4, "JSON array size invalid.")) {
         return false;
       }
 
       Json::Value const& entryName = entry[0u];
       Json::Value const& entryFlags = entry[1u];
       Json::Value const& entryBuild = entry[2u];
+      Json::Value const& entryConfigs = entry[3u];
       if (testEntry(entryName.isString(),
                     "JSON value for name is not a string.") ||
           testEntry(entryFlags.isString(),
                     "JSON value for flags is not a string.") ||
+          testEntry(entryConfigs.isNull() || entryConfigs.isArray(),
+                    "JSON value for configs is not null or array.") ||
           testEntry(entryBuild.isString(),
                     "JSON value for build path is not a string.")) {
         return false;
@@ -2475,6 +2540,22 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
         return false;
       }
 
+      if (entryConfigs.isArray()) {
+        bool configFound = false;
+        Json::ArrayIndex const configArraySize = entryConfigs.size();
+        for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) {
+          Json::Value const& config = entryConfigs[ci];
+          if (testEntry(config.isString(),
+                        "JSON value in config array is not a string.")) {
+            return false;
+          }
+          configFound = configFound || config.asString() == this->InfoConfig();
+        }
+        if (!configFound) {
+          continue;
+        }
+      }
+
       cmFileTime fileTime;
       if (!fileTime.Load(name)) {
         return info.LogError(cmStrCat(
@@ -2486,14 +2567,15 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
       sourceHandle->IsHeader = true;
       sourceHandle->Moc = (flags[0] == 'M');
       sourceHandle->Uic = (flags[1] == 'U');
-      if (sourceHandle->Moc && MocConst().Enabled) {
+      if (sourceHandle->Moc && this->MocConst().Enabled) {
         if (build.empty()) {
           return info.LogError(
             cmStrCat("Header file ", ii, " build path is empty"));
         }
         sourceHandle->BuildPath = std::move(build);
       }
-      BaseEval().Headers.emplace(std::move(name), std::move(sourceHandle));
+      this->BaseEval().Headers.emplace(std::move(name),
+                                       std::move(sourceHandle));
     }
   }
 
@@ -2515,16 +2597,19 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
 
       Json::Value const& entry = val[ii];
       if (testEntry(entry.isArray(), "JSON value is not an array.") ||
-          testEntry(entry.size() == 2, "JSON array size invalid.")) {
+          testEntry(entry.size() == 3, "JSON array size invalid.")) {
         return false;
       }
 
       Json::Value const& entryName = entry[0u];
       Json::Value const& entryFlags = entry[1u];
+      Json::Value const& entryConfigs = entry[2u];
       if (testEntry(entryName.isString(),
                     "JSON value for name is not a string.") ||
           testEntry(entryFlags.isString(),
-                    "JSON value for flags is not a string.")) {
+                    "JSON value for flags is not a string.") ||
+          testEntry(entryConfigs.isNull() || entryConfigs.isArray(),
+                    "JSON value for configs is not null or array.")) {
         return false;
       }
 
@@ -2534,6 +2619,22 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
         return false;
       }
 
+      if (entryConfigs.isArray()) {
+        bool configFound = false;
+        Json::ArrayIndex const configArraySize = entryConfigs.size();
+        for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) {
+          Json::Value const& config = entryConfigs[ci];
+          if (testEntry(config.isString(),
+                        "JSON value in config array is not a string.")) {
+            return false;
+          }
+          configFound = configFound || config.asString() == this->InfoConfig();
+        }
+        if (!configFound) {
+          continue;
+        }
+      }
+
       cmFileTime fileTime;
       if (!fileTime.Load(name)) {
         return info.LogError(cmStrCat(
@@ -2545,18 +2646,19 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
       sourceHandle->IsHeader = false;
       sourceHandle->Moc = (flags[0] == 'M');
       sourceHandle->Uic = (flags[1] == 'U');
-      BaseEval().Sources.emplace(std::move(name), std::move(sourceHandle));
+      this->BaseEval().Sources.emplace(std::move(name),
+                                       std::move(sourceHandle));
     }
   }
 
   // -- Init derived information
   // Moc variables
-  if (MocConst().Enabled) {
+  if (this->MocConst().Enabled) {
     // Compose moc includes list
     {
       // Compute framework paths
       std::set<std::string> frameworkPaths;
-      for (std::string const& path : MocConst().IncludePaths) {
+      for (std::string const& path : this->MocConst().IncludePaths) {
         // Extract framework path
         if (cmHasLiteralSuffix(path, ".framework/Headers")) {
           // Go up twice to get to the framework root
@@ -2567,24 +2669,25 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
         }
       }
       // Reserve options
-      MocConst_.OptionsIncludes.reserve(MocConst().IncludePaths.size() +
-                                        frameworkPaths.size() * 2);
+      this->MocConst_.OptionsIncludes.reserve(
+        this->MocConst().IncludePaths.size() + frameworkPaths.size() * 2);
       // Append includes
-      for (std::string const& path : MocConst().IncludePaths) {
-        MocConst_.OptionsIncludes.emplace_back("-I" + path);
+      for (std::string const& path : this->MocConst().IncludePaths) {
+        this->MocConst_.OptionsIncludes.emplace_back("-I" + path);
       }
       // Append framework includes
       for (std::string const& path : frameworkPaths) {
-        MocConst_.OptionsIncludes.emplace_back("-F");
-        MocConst_.OptionsIncludes.push_back(path);
+        this->MocConst_.OptionsIncludes.emplace_back("-F");
+        this->MocConst_.OptionsIncludes.push_back(path);
       }
     }
 
     // Compose moc definitions list
     {
-      MocConst_.OptionsDefinitions.reserve(MocConst().Definitions.size());
-      for (std::string const& def : MocConst().Definitions) {
-        MocConst_.OptionsDefinitions.emplace_back("-D" + def);
+      this->MocConst_.OptionsDefinitions.reserve(
+        this->MocConst().Definitions.size());
+      for (std::string const& def : this->MocConst().Definitions) {
+        this->MocConst_.OptionsDefinitions.emplace_back("-D" + def);
       }
     }
   }
@@ -2595,16 +2698,16 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
 template <class JOBTYPE>
 void cmQtAutoMocUicT::CreateParseJobs(SourceFileMapT const& sourceMap)
 {
-  cmFileTime const parseCacheTime = BaseEval().ParseCacheTime;
-  ParseCacheT& parseCache = BaseEval().ParseCache;
-  for (auto& src : sourceMap) {
+  cmFileTime const parseCacheTime = this->BaseEval().ParseCacheTime;
+  ParseCacheT& parseCache = this->BaseEval().ParseCache;
+  for (const auto& src : sourceMap) {
     // Get or create the file parse data reference
     ParseCacheT::GetOrInsertT cacheEntry = parseCache.GetOrInsert(src.first);
     src.second->ParseData = std::move(cacheEntry.first);
     // Create a parse job if the cache file was missing or is older
     if (cacheEntry.second || src.second->FileTime.Newer(parseCacheTime)) {
-      BaseEval().ParseCacheChanged = true;
-      WorkerPool().EmplaceJob<JOBTYPE>(src.second);
+      this->BaseEval().ParseCacheChanged = true;
+      this->WorkerPool().EmplaceJob<JOBTYPE>(src.second);
     }
   }
 }
@@ -2612,55 +2715,56 @@ void cmQtAutoMocUicT::CreateParseJobs(SourceFileMapT const& sourceMap)
 /** Concurrently callable implementation of cmSystemTools::CollapseFullPath */
 std::string cmQtAutoMocUicT::CollapseFullPathTS(std::string const& path) const
 {
-  std::lock_guard<std::mutex> guard(CMakeLibMutex_);
-  return cmSystemTools::CollapseFullPath(path, ProjectDirs().CurrentSource);
+  std::lock_guard<std::mutex> guard(this->CMakeLibMutex_);
+  return cmSystemTools::CollapseFullPath(path,
+                                         this->ProjectDirs().CurrentSource);
 }
 
 void cmQtAutoMocUicT::InitJobs()
 {
   // Add moc_predefs.h job
-  if (MocConst().Enabled && !MocConst().PredefsCmd.empty()) {
-    WorkerPool().EmplaceJob<JobMocPredefsT>();
+  if (this->MocConst().Enabled && !this->MocConst().PredefsCmd.empty()) {
+    this->WorkerPool().EmplaceJob<JobMocPredefsT>();
   }
 
   // Add header parse jobs
-  CreateParseJobs<JobParseHeaderT>(BaseEval().Headers);
+  this->CreateParseJobs<JobParseHeaderT>(this->BaseEval().Headers);
   // Add source parse jobs
-  CreateParseJobs<JobParseSourceT>(BaseEval().Sources);
+  this->CreateParseJobs<JobParseSourceT>(this->BaseEval().Sources);
 
   // Add parse cache evaluations jobs
   {
     // Add a fence job to ensure all parsing has finished
-    WorkerPool().EmplaceJob<JobFenceT>();
-    if (MocConst().Enabled) {
-      WorkerPool().EmplaceJob<JobEvalCacheMocT>();
+    this->WorkerPool().EmplaceJob<JobFenceT>();
+    if (this->MocConst().Enabled) {
+      this->WorkerPool().EmplaceJob<JobEvalCacheMocT>();
     }
-    if (UicConst().Enabled) {
-      WorkerPool().EmplaceJob<JobEvalCacheUicT>();
+    if (this->UicConst().Enabled) {
+      this->WorkerPool().EmplaceJob<JobEvalCacheUicT>();
     }
     // Add evaluate job
-    WorkerPool().EmplaceJob<JobEvalCacheFinishT>();
+    this->WorkerPool().EmplaceJob<JobEvalCacheFinishT>();
   }
 }
 
 bool cmQtAutoMocUicT::Process()
 {
-  SettingsFileRead();
-  ParseCacheRead();
-  if (!CreateDirectories()) {
+  this->SettingsFileRead();
+  this->ParseCacheRead();
+  if (!this->CreateDirectories()) {
     return false;
   }
-  InitJobs();
-  if (!WorkerPool_.Process(this)) {
+  this->InitJobs();
+  if (!this->WorkerPool_.Process(this)) {
     return false;
   }
-  if (JobError_) {
+  if (this->JobError_) {
     return false;
   }
-  if (!ParseCacheWrite()) {
+  if (!this->ParseCacheWrite()) {
     return false;
   }
-  if (!SettingsFileWrite()) {
+  if (!this->SettingsFileWrite()) {
     return false;
   }
   return true;
@@ -2676,70 +2780,72 @@ void cmQtAutoMocUicT::SettingsFileRead()
       cryptoHash.Append(";");
     };
 
-    if (MocConst_.Enabled) {
+    if (this->MocConst_.Enabled) {
       cryptoHash.Initialize();
-      cha(MocConst().Executable);
-      for (auto const& item : MocConst().OptionsDefinitions) {
+      cha(this->MocConst().Executable);
+      for (auto const& item : this->MocConst().OptionsDefinitions) {
         cha(item);
       }
-      for (auto const& item : MocConst().OptionsIncludes) {
+      for (auto const& item : this->MocConst().OptionsIncludes) {
         cha(item);
       }
-      for (auto const& item : MocConst().OptionsExtra) {
+      for (auto const& item : this->MocConst().OptionsExtra) {
         cha(item);
       }
-      for (auto const& item : MocConst().PredefsCmd) {
+      for (auto const& item : this->MocConst().PredefsCmd) {
         cha(item);
       }
-      for (auto const& filter : MocConst().DependFilters) {
+      for (auto const& filter : this->MocConst().DependFilters) {
         cha(filter.Key);
       }
-      for (auto const& filter : MocConst().MacroFilters) {
+      for (auto const& filter : this->MocConst().MacroFilters) {
         cha(filter.Key);
       }
-      SettingsStringMoc_ = cryptoHash.FinalizeHex();
+      this->SettingsStringMoc_ = cryptoHash.FinalizeHex();
     }
 
-    if (UicConst().Enabled) {
+    if (this->UicConst().Enabled) {
       cryptoHash.Initialize();
-      cha(UicConst().Executable);
-      std::for_each(UicConst().Options.begin(), UicConst().Options.end(), cha);
-      for (const auto& item : UicConst().UiFiles) {
+      cha(this->UicConst().Executable);
+      std::for_each(this->UicConst().Options.begin(),
+                    this->UicConst().Options.end(), cha);
+      for (const auto& item : this->UicConst().UiFiles) {
         cha(item.first);
         auto const& opts = item.second.Options;
         std::for_each(opts.begin(), opts.end(), cha);
       }
-      SettingsStringUic_ = cryptoHash.FinalizeHex();
+      this->SettingsStringUic_ = cryptoHash.FinalizeHex();
     }
   }
 
   // Read old settings and compare
   {
     std::string content;
-    if (cmQtAutoGenerator::FileRead(content, SettingsFile_)) {
-      if (MocConst().Enabled) {
-        if (SettingsStringMoc_ != SettingsFind(content, "moc")) {
-          MocConst_.SettingsChanged = true;
+    if (cmQtAutoGenerator::FileRead(content, this->SettingsFile_)) {
+      if (this->MocConst().Enabled) {
+        if (this->SettingsStringMoc_ != SettingsFind(content, "moc")) {
+          this->MocConst_.SettingsChanged = true;
         }
       }
-      if (UicConst().Enabled) {
-        if (SettingsStringUic_ != SettingsFind(content, "uic")) {
-          UicConst_.SettingsChanged = true;
+      if (this->UicConst().Enabled) {
+        if (this->SettingsStringUic_ != SettingsFind(content, "uic")) {
+          this->UicConst_.SettingsChanged = true;
         }
       }
       // In case any setting changed remove the old settings file.
       // This triggers a full rebuild on the next run if the current
       // build is aborted before writing the current settings in the end.
-      if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
-        cmSystemTools::RemoveFile(SettingsFile_);
+      if (this->MocConst().SettingsChanged ||
+          this->UicConst().SettingsChanged) {
+        cmSystemTools::RemoveFile(this->SettingsFile_);
       }
     } else {
       // Settings file read failed
-      if (MocConst().Enabled) {
-        MocConst_.SettingsChanged = true;
+      if (this->MocConst().Enabled) {
+        this->MocConst_.SettingsChanged = true;
       }
-      if (UicConst().Enabled) {
-        UicConst_.SettingsChanged = true;
+      if (this->UicConst().Enabled) {
+        this->UicConst_.SettingsChanged = true;
       }
     }
   }
@@ -2748,11 +2854,11 @@ void cmQtAutoMocUicT::SettingsFileRead()
 bool cmQtAutoMocUicT::SettingsFileWrite()
 {
   // Only write if any setting changed
-  if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
-    if (Log().Verbose()) {
-      Log().Info(
-        GenT::GEN,
-        cmStrCat("Writing the settings file ", MessagePath(SettingsFile_)));
+  if (this->MocConst().SettingsChanged || this->UicConst().SettingsChanged) {
+    if (this->Log().Verbose()) {
+      this->Log().Info(GenT::GEN,
+                       cmStrCat("Writing the settings file ",
+                                this->MessagePath(this->SettingsFile_)));
     }
     // Compose settings file content
     std::string content;
@@ -2763,17 +2869,18 @@ bool cmQtAutoMocUicT::SettingsFileWrite()
           content += cmStrCat(key, ':', value, '\n');
         }
       };
-      SettingAppend("moc", SettingsStringMoc_);
-      SettingAppend("uic", SettingsStringUic_);
+      SettingAppend("moc", this->SettingsStringMoc_);
+      SettingAppend("uic", this->SettingsStringUic_);
     }
     // Write settings file
     std::string error;
-    if (!cmQtAutoGenerator::FileWrite(SettingsFile_, content, &error)) {
-      Log().Error(GenT::GEN,
-                  cmStrCat("Writing the settings file ",
-                           MessagePath(SettingsFile_), " failed.\n", error));
+    if (!cmQtAutoGenerator::FileWrite(this->SettingsFile_, content, &error)) {
+      this->Log().Error(GenT::GEN,
+                        cmStrCat("Writing the settings file ",
+                                 this->MessagePath(this->SettingsFile_),
+                                 " failed.\n", error));
       // Remove old settings file to trigger a full rebuild on the next run
-      cmSystemTools::RemoveFile(SettingsFile_);
+      cmSystemTools::RemoveFile(this->SettingsFile_);
       return false;
     }
   }
@@ -2784,41 +2891,46 @@ void cmQtAutoMocUicT::ParseCacheRead()
 {
   cm::string_view reason;
   // Don't read the cache if it is invalid
-  if (!BaseEval().ParseCacheTime.Load(BaseConst().ParseCacheFile)) {
+  if (!this->BaseEval().ParseCacheTime.Load(
+        this->BaseConst().ParseCacheFile)) {
     reason = "Refreshing parse cache because it doesn't exist.";
-  } else if (MocConst().SettingsChanged || UicConst().SettingsChanged) {
+  } else if (this->MocConst().SettingsChanged ||
+             this->UicConst().SettingsChanged) {
     reason = "Refreshing parse cache because the settings changed.";
-  } else if (BaseEval().ParseCacheTime.Older(
-               BaseConst().CMakeExecutableTime)) {
+  } else if (this->BaseEval().ParseCacheTime.Older(
+               this->BaseConst().CMakeExecutableTime)) {
     reason =
       "Refreshing parse cache because it is older than the CMake executable.";
   }
 
   if (!reason.empty()) {
     // Don't read but refresh the complete parse cache
-    if (Log().Verbose()) {
-      Log().Info(GenT::GEN, reason);
+    if (this->Log().Verbose()) {
+      this->Log().Info(GenT::GEN, reason);
     }
-    BaseEval().ParseCacheChanged = true;
+    this->BaseEval().ParseCacheChanged = true;
   } else {
     // Read parse cache
-    BaseEval().ParseCache.ReadFromFile(BaseConst().ParseCacheFile);
+    this->BaseEval().ParseCache.ReadFromFile(this->BaseConst().ParseCacheFile);
   }
 }
 
 bool cmQtAutoMocUicT::ParseCacheWrite()
 {
-  if (BaseEval().ParseCacheChanged) {
-    if (Log().Verbose()) {
-      Log().Info(GenT::GEN,
-                 cmStrCat("Writing the parse cache file ",
-                          MessagePath(BaseConst().ParseCacheFile)));
-    }
-    if (!BaseEval().ParseCache.WriteToFile(BaseConst().ParseCacheFile)) {
-      Log().Error(GenT::GEN,
-                  cmStrCat("Writing the parse cache file ",
-                           MessagePath(BaseConst().ParseCacheFile),
-                           " failed."));
+  if (this->BaseEval().ParseCacheChanged) {
+    if (this->Log().Verbose()) {
+      this->Log().Info(
+        GenT::GEN,
+        cmStrCat("Writing the parse cache file ",
+                 this->MessagePath(this->BaseConst().ParseCacheFile)));
+    }
+    if (!this->BaseEval().ParseCache.WriteToFile(
+          this->BaseConst().ParseCacheFile)) {
+      this->Log().Error(
+        GenT::GEN,
+        cmStrCat("Writing the parse cache file ",
+                 this->MessagePath(this->BaseConst().ParseCacheFile),
+                 " failed."));
       return false;
     }
   }
@@ -2828,11 +2940,12 @@ bool cmQtAutoMocUicT::ParseCacheWrite()
 bool cmQtAutoMocUicT::CreateDirectories()
 {
   // Create AUTOGEN include directory
-  if (!cmSystemTools::MakeDirectory(BaseConst().AutogenIncludeDir)) {
-    Log().Error(GenT::GEN,
-                cmStrCat("Creating the AUTOGEN include directory ",
-                         MessagePath(BaseConst().AutogenIncludeDir),
-                         " failed."));
+  if (!cmSystemTools::MakeDirectory(this->BaseConst().AutogenIncludeDir)) {
+    this->Log().Error(
+      GenT::GEN,
+      cmStrCat("Creating the AUTOGEN include directory ",
+               this->MessagePath(this->BaseConst().AutogenIncludeDir),
+               " failed."));
     return false;
   }
   return true;
@@ -2841,34 +2954,34 @@ bool cmQtAutoMocUicT::CreateDirectories()
 std::vector<std::string> cmQtAutoMocUicT::dependenciesFromDepFile(
   const char* filePath)
 {
-  cmGccDepfileContent content = cmReadGccDepfile(filePath);
-  if (content.empty()) {
+  auto const content = cmReadGccDepfile(filePath);
+  if (!content || content->empty()) {
     return {};
   }
 
   // Moc outputs a depfile with exactly one rule.
   // Discard the rule and return the dependencies.
-  return content.front().paths;
+  return content->front().paths;
 }
 
 void cmQtAutoMocUicT::Abort(bool error)
 {
   if (error) {
-    JobError_.store(true);
+    this->JobError_.store(true);
   }
-  WorkerPool_.Abort();
+  this->WorkerPool_.Abort();
 }
 
 std::string cmQtAutoMocUicT::AbsoluteBuildPath(
   cm::string_view relativePath) const
 {
-  return cmStrCat(BaseConst().AutogenBuildDir, '/', relativePath);
+  return cmStrCat(this->BaseConst().AutogenBuildDir, '/', relativePath);
 }
 
 std::string cmQtAutoMocUicT::AbsoluteIncludePath(
   cm::string_view relativePath) const
 {
-  return cmStrCat(BaseConst().AutogenIncludeDir, '/', relativePath);
+  return cmStrCat(this->BaseConst().AutogenIncludeDir, '/', relativePath);
 }
 
 } // End of unnamed namespace
index 08eb4b5..414a692 100644 (file)
@@ -35,7 +35,7 @@ public:
 
 private:
   // -- Utility
-  bool IsMultiConfig() const { return MultiConfig_; }
+  bool IsMultiConfig() const { return this->MultiConfig_; }
   std::string MultiConfigOutput() const;
 
   // -- Abstract processing interface
@@ -52,7 +52,6 @@ private:
   bool GenerateRcc();
   bool GenerateWrapper();
 
-private:
   // -- Config settings
   bool MultiConfig_ = false;
   // -- Directories
@@ -93,38 +92,41 @@ cmQtAutoRccT::~cmQtAutoRccT() = default;
 bool cmQtAutoRccT::InitFromInfo(InfoT const& info)
 {
   // -- Required settings
-  if (!info.GetBool("MULTI_CONFIG", MultiConfig_, true) ||
-      !info.GetString("BUILD_DIR", AutogenBuildDir_, true) ||
-      !info.GetStringConfig("INCLUDE_DIR", IncludeDir_, true) ||
-      !info.GetString("RCC_EXECUTABLE", RccExecutable_, true) ||
-      !info.GetArray("RCC_LIST_OPTIONS", RccListOptions_, false) ||
-      !info.GetString("LOCK_FILE", LockFile_, true) ||
-      !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) ||
-      !info.GetString("SOURCE", QrcFile_, true) ||
-      !info.GetString("OUTPUT_CHECKSUM", RccPathChecksum_, true) ||
-      !info.GetString("OUTPUT_NAME", RccFileName_, true) ||
-      !info.GetArray("OPTIONS", Options_, false) ||
-      !info.GetArray("INPUTS", Inputs_, false)) {
+  if (!info.GetBool("MULTI_CONFIG", this->MultiConfig_, true) ||
+      !info.GetString("BUILD_DIR", this->AutogenBuildDir_, true) ||
+      !info.GetStringConfig("INCLUDE_DIR", this->IncludeDir_, true) ||
+      !info.GetString("RCC_EXECUTABLE", this->RccExecutable_, true) ||
+      !info.GetArray("RCC_LIST_OPTIONS", this->RccListOptions_, false) ||
+      !info.GetString("LOCK_FILE", this->LockFile_, true) ||
+      !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) ||
+      !info.GetString("SOURCE", this->QrcFile_, true) ||
+      !info.GetString("OUTPUT_CHECKSUM", this->RccPathChecksum_, true) ||
+      !info.GetString("OUTPUT_NAME", this->RccFileName_, true) ||
+      !info.GetArray("OPTIONS", this->Options_, false) ||
+      !info.GetArray("INPUTS", this->Inputs_, false)) {
     return false;
   }
 
   // -- Derive information
-  QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_);
-  QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_);
-  RccFilePublic_ =
-    cmStrCat(AutogenBuildDir_, '/', RccPathChecksum_, '/', RccFileName_);
+  this->QrcFileName_ = cmSystemTools::GetFilenameName(this->QrcFile_);
+  this->QrcFileDir_ = cmSystemTools::GetFilenamePath(this->QrcFile_);
+  this->RccFilePublic_ =
+    cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
+             this->RccFileName_);
 
   // rcc output file name
-  if (IsMultiConfig()) {
-    RccFileOutput_ = cmStrCat(IncludeDir_, '/', MultiConfigOutput());
+  if (this->IsMultiConfig()) {
+    this->RccFileOutput_ =
+      cmStrCat(this->IncludeDir_, '/', this->MultiConfigOutput());
   } else {
-    RccFileOutput_ = RccFilePublic_;
+    this->RccFileOutput_ = this->RccFilePublic_;
   }
 
   // -- Checks
-  if (!RccExecutableTime_.Load(RccExecutable_)) {
-    return info.LogError(cmStrCat(
-      "The rcc executable ", MessagePath(RccExecutable_), " does not exist."));
+  if (!this->RccExecutableTime_.Load(this->RccExecutable_)) {
+    return info.LogError(cmStrCat("The rcc executable ",
+                                  this->MessagePath(this->RccExecutable_),
+                                  " does not exist."));
   }
 
   return true;
@@ -132,41 +134,41 @@ bool cmQtAutoRccT::InitFromInfo(InfoT const& info)
 
 bool cmQtAutoRccT::Process()
 {
-  if (!SettingsFileRead()) {
+  if (!this->SettingsFileRead()) {
     return false;
   }
 
   // Test if the rcc output needs to be regenerated
   bool generate = false;
-  if (!TestQrcRccFiles(generate)) {
+  if (!this->TestQrcRccFiles(generate)) {
     return false;
   }
-  if (!generate && !TestResources(generate)) {
+  if (!generate && !this->TestResources(generate)) {
     return false;
   }
   // Generate on demand
   if (generate) {
-    if (!GenerateRcc()) {
+    if (!this->GenerateRcc()) {
       return false;
     }
   } else {
     // Test if the info file is newer than the output file
-    if (!TestInfoFile()) {
+    if (!this->TestInfoFile()) {
       return false;
     }
   }
 
-  if (!GenerateWrapper()) {
+  if (!this->GenerateWrapper()) {
     return false;
   }
 
-  return SettingsFileWrite();
+  return this->SettingsFileWrite();
 }
 
 std::string cmQtAutoRccT::MultiConfigOutput() const
 {
-  return cmStrCat(RccPathChecksum_, '/',
-                  AppendFilenameSuffix(RccFileName_, "_CMAKE_"));
+  return cmStrCat(this->RccPathChecksum_, '/',
+                  AppendFilenameSuffix(this->RccFileName_, "_CMAKE_"));
 }
 
 bool cmQtAutoRccT::SettingsFileRead()
@@ -178,23 +180,25 @@ bool cmQtAutoRccT::SettingsFileRead()
       cryptoHash.Append(value);
       cryptoHash.Append(";");
     };
-    cha(RccExecutable_);
-    std::for_each(RccListOptions_.begin(), RccListOptions_.end(), cha);
-    cha(QrcFile_);
-    cha(RccPathChecksum_);
-    cha(RccFileName_);
-    std::for_each(Options_.begin(), Options_.end(), cha);
-    std::for_each(Inputs_.begin(), Inputs_.end(), cha);
-    SettingsString_ = cryptoHash.FinalizeHex();
+    cha(this->RccExecutable_);
+    std::for_each(this->RccListOptions_.begin(), this->RccListOptions_.end(),
+                  cha);
+    cha(this->QrcFile_);
+    cha(this->RccPathChecksum_);
+    cha(this->RccFileName_);
+    std::for_each(this->Options_.begin(), this->Options_.end(), cha);
+    std::for_each(this->Inputs_.begin(), this->Inputs_.end(), cha);
+    this->SettingsString_ = cryptoHash.FinalizeHex();
   }
 
   // Make sure the settings file exists
-  if (!cmSystemTools::FileExists(SettingsFile_, true)) {
+  if (!cmSystemTools::FileExists(this->SettingsFile_, true)) {
     // Touch the settings file to make sure it exists
-    if (!cmSystemTools::Touch(SettingsFile_, true)) {
-      Log().Error(GenT::RCC,
-                  cmStrCat("Touching the settings file ",
-                           MessagePath(SettingsFile_), " failed."));
+    if (!cmSystemTools::Touch(this->SettingsFile_, true)) {
+      this->Log().Error(GenT::RCC,
+                        cmStrCat("Touching the settings file ",
+                                 this->MessagePath(this->SettingsFile_),
+                                 " failed."));
       return false;
     }
   }
@@ -202,21 +206,23 @@ bool cmQtAutoRccT::SettingsFileRead()
   // Lock the lock file
   {
     // Make sure the lock file exists
-    if (!cmSystemTools::FileExists(LockFile_, true)) {
-      if (!cmSystemTools::Touch(LockFile_, true)) {
-        Log().Error(GenT::RCC,
-                    cmStrCat("Touching the lock file ", MessagePath(LockFile_),
-                             " failed."));
+    if (!cmSystemTools::FileExists(this->LockFile_, true)) {
+      if (!cmSystemTools::Touch(this->LockFile_, true)) {
+        this->Log().Error(GenT::RCC,
+                          cmStrCat("Touching the lock file ",
+                                   this->MessagePath(this->LockFile_),
+                                   " failed."));
         return false;
       }
     }
     // Lock the lock file
-    cmFileLockResult lockResult =
-      LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1));
+    cmFileLockResult lockResult = this->LockFileLock_.Lock(
+      this->LockFile_, static_cast<unsigned long>(-1));
     if (!lockResult.IsOk()) {
-      Log().Error(GenT::RCC,
-                  cmStrCat("Locking of the lock file ", MessagePath(LockFile_),
-                           " failed.\n", lockResult.GetOutputMessage()));
+      this->Log().Error(GenT::RCC,
+                        cmStrCat("Locking of the lock file ",
+                                 this->MessagePath(this->LockFile_),
+                                 " failed.\n", lockResult.GetOutputMessage()));
       return false;
     }
   }
@@ -224,23 +230,24 @@ bool cmQtAutoRccT::SettingsFileRead()
   // Read old settings
   {
     std::string content;
-    if (FileRead(content, SettingsFile_)) {
-      SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc"));
+    if (FileRead(content, this->SettingsFile_)) {
+      this->SettingsChanged_ =
+        (this->SettingsString_ != SettingsFind(content, "rcc"));
       // In case any setting changed clear the old settings file.
       // This triggers a full rebuild on the next run if the current
       // build is aborted before writing the current settings in the end.
-      if (SettingsChanged_) {
+      if (this->SettingsChanged_) {
         std::string error;
-        if (!FileWrite(SettingsFile_, "", &error)) {
-          Log().Error(GenT::RCC,
-                      cmStrCat("Clearing of the settings file ",
-                               MessagePath(SettingsFile_), " failed.\n",
-                               error));
+        if (!FileWrite(this->SettingsFile_, "", &error)) {
+          this->Log().Error(GenT::RCC,
+                            cmStrCat("Clearing of the settings file ",
+                                     this->MessagePath(this->SettingsFile_),
+                                     " failed.\n", error));
           return false;
         }
       }
     } else {
-      SettingsChanged_ = true;
+      this->SettingsChanged_ = true;
     }
   }
 
@@ -250,26 +257,28 @@ bool cmQtAutoRccT::SettingsFileRead()
 bool cmQtAutoRccT::SettingsFileWrite()
 {
   // Only write if any setting changed
-  if (SettingsChanged_) {
-    if (Log().Verbose()) {
-      Log().Info(GenT::RCC,
-                 "Writing settings file " + MessagePath(SettingsFile_));
+  if (this->SettingsChanged_) {
+    if (this->Log().Verbose()) {
+      this->Log().Info(GenT::RCC,
+                       "Writing settings file " +
+                         this->MessagePath(this->SettingsFile_));
     }
     // Write settings file
-    std::string content = cmStrCat("rcc:", SettingsString_, '\n');
+    std::string content = cmStrCat("rcc:", this->SettingsString_, '\n');
     std::string error;
-    if (!FileWrite(SettingsFile_, content, &error)) {
-      Log().Error(GenT::RCC,
-                  cmStrCat("Writing of the settings file ",
-                           MessagePath(SettingsFile_), " failed.\n", error));
+    if (!FileWrite(this->SettingsFile_, content, &error)) {
+      this->Log().Error(GenT::RCC,
+                        cmStrCat("Writing of the settings file ",
+                                 this->MessagePath(this->SettingsFile_),
+                                 " failed.\n", error));
       // Remove old settings file to trigger a full rebuild on the next run
-      cmSystemTools::RemoveFile(SettingsFile_);
+      cmSystemTools::RemoveFile(this->SettingsFile_);
       return false;
     }
   }
 
   // Unlock the lock file
-  LockFileLock_.Release();
+  this->LockFileLock_.Release();
   return true;
 }
 
@@ -277,52 +286,57 @@ bool cmQtAutoRccT::SettingsFileWrite()
 bool cmQtAutoRccT::TestQrcRccFiles(bool& generate)
 {
   // Test if the rcc input file exists
-  if (!QrcFileTime_.Load(QrcFile_)) {
-    Log().Error(GenT::RCC,
-                cmStrCat("The resources file ", MessagePath(QrcFile_),
-                         " does not exist"));
+  if (!this->QrcFileTime_.Load(this->QrcFile_)) {
+    this->Log().Error(GenT::RCC,
+                      cmStrCat("The resources file ",
+                               this->MessagePath(this->QrcFile_),
+                               " does not exist"));
     return false;
   }
 
   // Test if the rcc output file exists
-  if (!RccFileTime_.Load(RccFileOutput_)) {
-    if (Log().Verbose()) {
-      Reason =
-        cmStrCat("Generating ", MessagePath(RccFileOutput_),
-                 ", because it doesn't exist, from ", MessagePath(QrcFile_));
+  if (!this->RccFileTime_.Load(this->RccFileOutput_)) {
+    if (this->Log().Verbose()) {
+      this->Reason =
+        cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+                 ", because it doesn't exist, from ",
+                 this->MessagePath(this->QrcFile_));
     }
     generate = true;
     return true;
   }
 
   // Test if the settings changed
-  if (SettingsChanged_) {
-    if (Log().Verbose()) {
-      Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_),
-                        ", because the rcc settings changed, from ",
-                        MessagePath(QrcFile_));
+  if (this->SettingsChanged_) {
+    if (this->Log().Verbose()) {
+      this->Reason =
+        cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+                 ", because the rcc settings changed, from ",
+                 this->MessagePath(this->QrcFile_));
     }
     generate = true;
     return true;
   }
 
   // Test if the rcc output file is older than the .qrc file
-  if (RccFileTime_.Older(QrcFileTime_)) {
-    if (Log().Verbose()) {
-      Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_),
-                        ", because it is older than ", MessagePath(QrcFile_),
-                        ", from ", MessagePath(QrcFile_));
+  if (this->RccFileTime_.Older(this->QrcFileTime_)) {
+    if (this->Log().Verbose()) {
+      this->Reason = cmStrCat(
+        "Generating ", this->MessagePath(this->RccFileOutput_),
+        ", because it is older than ", this->MessagePath(this->QrcFile_),
+        ", from ", this->MessagePath(this->QrcFile_));
     }
     generate = true;
     return true;
   }
 
   // Test if the rcc output file is older than the rcc executable
-  if (RccFileTime_.Older(RccExecutableTime_)) {
-    if (Log().Verbose()) {
-      Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_),
-                        ", because it is older than the rcc executable, from ",
-                        MessagePath(QrcFile_));
+  if (this->RccFileTime_.Older(this->RccExecutableTime_)) {
+    if (this->Log().Verbose()) {
+      this->Reason =
+        cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+                 ", because it is older than the rcc executable, from ",
+                 this->MessagePath(this->QrcFile_));
     }
     generate = true;
     return true;
@@ -334,34 +348,38 @@ bool cmQtAutoRccT::TestQrcRccFiles(bool& generate)
 bool cmQtAutoRccT::TestResources(bool& generate)
 {
   // Read resource files list
-  if (Inputs_.empty()) {
+  if (this->Inputs_.empty()) {
     std::string error;
-    RccLister const lister(RccExecutable_, RccListOptions_);
-    if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) {
-      Log().Error(
-        GenT::RCC,
-        cmStrCat("Listing of ", MessagePath(QrcFile_), " failed.\n", error));
+    RccLister const lister(this->RccExecutable_, this->RccListOptions_);
+    if (!lister.list(this->QrcFile_, this->Inputs_, error,
+                     this->Log().Verbose())) {
+      this->Log().Error(GenT::RCC,
+                        cmStrCat("Listing of ",
+                                 this->MessagePath(this->QrcFile_),
+                                 " failed.\n", error));
       return false;
     }
   }
 
   // Check if any resource file is newer than the rcc output file
-  for (std::string const& resFile : Inputs_) {
+  for (std::string const& resFile : this->Inputs_) {
     // Check if the resource file exists
     cmFileTime fileTime;
     if (!fileTime.Load(resFile)) {
-      Log().Error(GenT::RCC,
-                  cmStrCat("The resource file ", MessagePath(resFile),
-                           " listed in ", MessagePath(QrcFile_),
-                           " does not exist."));
+      this->Log().Error(GenT::RCC,
+                        cmStrCat("The resource file ",
+                                 this->MessagePath(resFile), " listed in ",
+                                 this->MessagePath(this->QrcFile_),
+                                 " does not exist."));
       return false;
     }
     // Check if the resource file is newer than the rcc output file
-    if (RccFileTime_.Older(fileTime)) {
-      if (Log().Verbose()) {
-        Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_),
-                          ", because it is older than ", MessagePath(resFile),
-                          ", from ", MessagePath(QrcFile_));
+    if (this->RccFileTime_.Older(fileTime)) {
+      if (this->Log().Verbose()) {
+        this->Reason =
+          cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_),
+                   ", because it is older than ", this->MessagePath(resFile),
+                   ", from ", this->MessagePath(this->QrcFile_));
       }
       generate = true;
       break;
@@ -373,21 +391,23 @@ bool cmQtAutoRccT::TestResources(bool& generate)
 bool cmQtAutoRccT::TestInfoFile()
 {
   // Test if the rcc output file is older than the info file
-  if (RccFileTime_.Older(InfoFileTime())) {
-    if (Log().Verbose()) {
-      Log().Info(GenT::RCC,
-                 cmStrCat("Touching ", MessagePath(RccFileOutput_),
-                          " because it is older than ",
-                          MessagePath(InfoFile())));
+  if (this->RccFileTime_.Older(this->InfoFileTime())) {
+    if (this->Log().Verbose()) {
+      this->Log().Info(GenT::RCC,
+                       cmStrCat("Touching ",
+                                this->MessagePath(this->RccFileOutput_),
+                                " because it is older than ",
+                                this->MessagePath(this->InfoFile())));
     }
     // Touch build file
-    if (!cmSystemTools::Touch(RccFileOutput_, false)) {
-      Log().Error(
-        GenT::RCC,
-        cmStrCat("Touching ", MessagePath(RccFileOutput_), " failed."));
+    if (!cmSystemTools::Touch(this->RccFileOutput_, false)) {
+      this->Log().Error(GenT::RCC,
+                        cmStrCat("Touching ",
+                                 this->MessagePath(this->RccFileOutput_),
+                                 " failed."));
       return false;
     }
-    BuildFileChanged_ = true;
+    this->BuildFileChanged_ = true;
   }
 
   return true;
@@ -396,51 +416,53 @@ bool cmQtAutoRccT::TestInfoFile()
 bool cmQtAutoRccT::GenerateRcc()
 {
   // Make parent directory
-  if (!MakeParentDirectory(RccFileOutput_)) {
-    Log().Error(GenT::RCC,
-                cmStrCat("Could not create parent directory of ",
-                         MessagePath(RccFileOutput_)));
+  if (!MakeParentDirectory(this->RccFileOutput_)) {
+    this->Log().Error(GenT::RCC,
+                      cmStrCat("Could not create parent directory of ",
+                               this->MessagePath(this->RccFileOutput_)));
     return false;
   }
 
   // Compose rcc command
   std::vector<std::string> cmd;
-  cmd.push_back(RccExecutable_);
-  cm::append(cmd, Options_);
+  cmd.push_back(this->RccExecutable_);
+  cm::append(cmd, this->Options_);
   cmd.emplace_back("-o");
-  cmd.push_back(RccFileOutput_);
-  cmd.push_back(QrcFile_);
+  cmd.push_back(this->RccFileOutput_);
+  cmd.push_back(this->QrcFile_);
 
   // Log reason and command
-  if (Log().Verbose()) {
-    Log().Info(GenT::RCC,
-               cmStrCat(Reason, cmHasSuffix(Reason, '\n') ? "" : "\n",
-                        QuotedCommand(cmd), '\n'));
+  if (this->Log().Verbose()) {
+    this->Log().Info(GenT::RCC,
+                     cmStrCat(this->Reason,
+                              cmHasSuffix(this->Reason, '\n') ? "" : "\n",
+                              QuotedCommand(cmd), '\n'));
   }
 
   std::string rccStdOut;
   std::string rccStdErr;
   int retVal = 0;
   bool result = cmSystemTools::RunSingleCommand(
-    cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(),
+    cmd, &rccStdOut, &rccStdErr, &retVal, this->AutogenBuildDir_.c_str(),
     cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto);
   if (!result || (retVal != 0)) {
     // rcc process failed
-    Log().ErrorCommand(GenT::RCC,
-                       cmStrCat("The rcc process failed to compile\n  ",
-                                MessagePath(QrcFile_), "\ninto\n  ",
-                                MessagePath(RccFileOutput_)),
-                       cmd, rccStdOut + rccStdErr);
-    cmSystemTools::RemoveFile(RccFileOutput_);
+    this->Log().ErrorCommand(GenT::RCC,
+                             cmStrCat("The rcc process failed to compile\n  ",
+                                      this->MessagePath(this->QrcFile_),
+                                      "\ninto\n  ",
+                                      this->MessagePath(this->RccFileOutput_)),
+                             cmd, rccStdOut + rccStdErr);
+    cmSystemTools::RemoveFile(this->RccFileOutput_);
     return false;
   }
 
   // rcc process success
   // Print rcc output
   if (!rccStdOut.empty()) {
-    Log().Info(GenT::RCC, rccStdOut);
+    this->Log().Info(GenT::RCC, rccStdOut);
   }
-  BuildFileChanged_ = true;
+  this->BuildFileChanged_ = true;
 
   return true;
 }
@@ -448,47 +470,48 @@ bool cmQtAutoRccT::GenerateRcc()
 bool cmQtAutoRccT::GenerateWrapper()
 {
   // Generate a wrapper source file on demand
-  if (IsMultiConfig()) {
+  if (this->IsMultiConfig()) {
     // Wrapper file content
     std::string content =
       cmStrCat("// This is an autogenerated configuration wrapper file.\n",
                "// Changes will be overwritten.\n", "#include <",
-               MultiConfigOutput(), ">\n");
+               this->MultiConfigOutput(), ">\n");
 
     // Compare with existing file content
     bool fileDiffers = true;
     {
       std::string oldContents;
-      if (FileRead(oldContents, RccFilePublic_)) {
+      if (FileRead(oldContents, this->RccFilePublic_)) {
         fileDiffers = (oldContents != content);
       }
     }
     if (fileDiffers) {
       // Write new wrapper file
-      if (Log().Verbose()) {
-        Log().Info(GenT::RCC,
-                   cmStrCat("Generating RCC wrapper file ",
-                            MessagePath(RccFilePublic_)));
+      if (this->Log().Verbose()) {
+        this->Log().Info(GenT::RCC,
+                         cmStrCat("Generating RCC wrapper file ",
+                                  this->MessagePath(this->RccFilePublic_)));
       }
       std::string error;
-      if (!FileWrite(RccFilePublic_, content, &error)) {
-        Log().Error(GenT::RCC,
-                    cmStrCat("Generating RCC wrapper file ",
-                             MessagePath(RccFilePublic_), " failed.\n",
-                             error));
+      if (!FileWrite(this->RccFilePublic_, content, &error)) {
+        this->Log().Error(GenT::RCC,
+                          cmStrCat("Generating RCC wrapper file ",
+                                   this->MessagePath(this->RccFilePublic_),
+                                   " failed.\n", error));
         return false;
       }
-    } else if (BuildFileChanged_) {
+    } else if (this->BuildFileChanged_) {
       // Just touch the wrapper file
-      if (Log().Verbose()) {
-        Log().Info(
-          GenT::RCC,
-          cmStrCat("Touching RCC wrapper file ", MessagePath(RccFilePublic_)));
+      if (this->Log().Verbose()) {
+        this->Log().Info(GenT::RCC,
+                         cmStrCat("Touching RCC wrapper file ",
+                                  this->MessagePath(this->RccFilePublic_)));
       }
-      if (!cmSystemTools::Touch(RccFilePublic_, false)) {
-        Log().Error(GenT::RCC,
-                    cmStrCat("Touching RCC wrapper file ",
-                             MessagePath(RccFilePublic_), " failed."));
+      if (!cmSystemTools::Touch(this->RccFilePublic_, false)) {
+        this->Log().Error(GenT::RCC,
+                          cmStrCat("Touching RCC wrapper file ",
+                                   this->MessagePath(this->RccFilePublic_),
+                                   " failed."));
         return false;
       }
     }
index 26e93bb..fce6e80 100644 (file)
@@ -25,7 +25,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot)
   , Markup(MarkupNone)
   , Directive(DirectiveNone)
   , CMakeDirective("^.. (cmake:)?("
-                   "command|variable"
+                   "command|envvar|genex|variable"
                    ")::[ \t]+([^ \t\n]+)$")
   , CMakeModuleDirective("^.. cmake-module::[ \t]+([^ \t\n]+)$")
   , ParsedLiteralDirective("^.. parsed-literal::[ \t]*(.*)$")
@@ -37,7 +37,8 @@ cmRST::cmRST(std::ostream& os, std::string docroot)
   , NoteDirective("^.. note::[ \t]*(.*)$")
   , ModuleRST(R"(^#\[(=*)\[\.rst:$)")
   , CMakeRole("(:cmake)?:("
-              "command|cpack_gen|generator|variable|envvar|module|policy|"
+              "command|cpack_gen|generator|genex|"
+              "variable|envvar|module|policy|"
               "prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|"
               "prop_test|prop_tgt|"
               "manual"
index f5f9c67..d00bbdf 100644 (file)
@@ -3,7 +3,6 @@
 #include "cmRulePlaceholderExpander.h"
 
 #include <cctype>
-#include <cstring>
 #include <utility>
 
 #include "cmOutputConverter.h"
@@ -20,11 +19,6 @@ cmRulePlaceholderExpander::cmRulePlaceholderExpander(
 {
 }
 
-cmRulePlaceholderExpander::RuleVariables::RuleVariables()
-{
-  memset(this, 0, sizeof(*this));
-}
-
 std::string cmRulePlaceholderExpander::ExpandRuleVariable(
   cmOutputConverter* outputConverter, std::string const& variable,
   const RuleVariables& replaceValues)
@@ -50,6 +44,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
       return replaceValues.Source;
     }
   }
+  if (replaceValues.DynDepFile) {
+    if (variable == "DYNDEP_FILE") {
+      return replaceValues.DynDepFile;
+    }
+  }
   if (replaceValues.PreprocessedSource) {
     if (variable == "PREPROCESSED_SOURCE") {
       return replaceValues.PreprocessedSource;
@@ -141,6 +140,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
       return replaceValues.DependencyFile;
     }
   }
+  if (replaceValues.DependencyTarget) {
+    if (variable == "DEP_TARGET") {
+      return replaceValues.DependencyTarget;
+    }
+  }
   if (replaceValues.Fatbinary) {
     if (variable == "FATBINARY") {
       return replaceValues.Fatbinary;
index c8d107d..f8dc368 100644 (file)
@@ -27,45 +27,46 @@ public:
   // ExpandRuleVariables
   struct RuleVariables
   {
-    RuleVariables();
-    const char* CMTargetName;
-    const char* CMTargetType;
-    const char* TargetPDB;
-    const char* TargetCompilePDB;
-    const char* TargetVersionMajor;
-    const char* TargetVersionMinor;
-    const char* Language;
-    const char* AIXExports;
-    const char* Objects;
-    const char* Target;
-    const char* LinkLibraries;
-    const char* Source;
-    const char* AssemblySource;
-    const char* PreprocessedSource;
-    const char* Output;
-    const char* Object;
-    const char* ObjectDir;
-    const char* ObjectFileDir;
-    const char* Flags;
-    const char* ObjectsQuoted;
-    const char* SONameFlag;
-    const char* TargetSOName;
-    const char* TargetInstallNameDir;
-    const char* LinkFlags;
-    const char* Manifests;
-    const char* LanguageCompileFlags;
-    const char* Defines;
-    const char* Includes;
-    const char* DependencyFile;
-    const char* FilterPrefix;
-    const char* SwiftLibraryName;
-    const char* SwiftModule;
-    const char* SwiftModuleName;
-    const char* SwiftOutputFileMap;
-    const char* SwiftSources;
-    const char* ISPCHeader;
-    const char* Fatbinary;
-    const char* RegisterFile;
+    const char* CMTargetName = nullptr;
+    const char* CMTargetType = nullptr;
+    const char* TargetPDB = nullptr;
+    const char* TargetCompilePDB = nullptr;
+    const char* TargetVersionMajor = nullptr;
+    const char* TargetVersionMinor = nullptr;
+    const char* Language = nullptr;
+    const char* AIXExports = nullptr;
+    const char* Objects = nullptr;
+    const char* Target = nullptr;
+    const char* LinkLibraries = nullptr;
+    const char* Source = nullptr;
+    const char* AssemblySource = nullptr;
+    const char* PreprocessedSource = nullptr;
+    const char* DynDepFile = nullptr;
+    const char* Output = nullptr;
+    const char* Object = nullptr;
+    const char* ObjectDir = nullptr;
+    const char* ObjectFileDir = nullptr;
+    const char* Flags = nullptr;
+    const char* ObjectsQuoted = nullptr;
+    const char* SONameFlag = nullptr;
+    const char* TargetSOName = nullptr;
+    const char* TargetInstallNameDir = nullptr;
+    const char* LinkFlags = nullptr;
+    const char* Manifests = nullptr;
+    const char* LanguageCompileFlags = nullptr;
+    const char* Defines = nullptr;
+    const char* Includes = nullptr;
+    const char* DependencyFile = nullptr;
+    const char* DependencyTarget = nullptr;
+    const char* FilterPrefix = nullptr;
+    const char* SwiftLibraryName = nullptr;
+    const char* SwiftModule = nullptr;
+    const char* SwiftModuleName = nullptr;
+    const char* SwiftOutputFileMap = nullptr;
+    const char* SwiftSources = nullptr;
+    const char* ISPCHeader = nullptr;
+    const char* Fatbinary = nullptr;
+    const char* RegisterFile = nullptr;
   };
 
   // Expand rule variables in CMake of the type found in language rules
index 0781d29..472f234 100644 (file)
@@ -181,13 +181,10 @@ bool cmRuntimeDependencyArchive::GetRuntimeDependencies(
       return false;
     }
   }
-  for (auto const& mod : modules) {
-    if (!this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY)) {
-      return false;
-    }
-  }
-
-  return true;
+  return std::all_of(
+    modules.begin(), modules.end(), [this](std::string const& mod) -> bool {
+      return this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY);
+    });
 }
 
 void cmRuntimeDependencyArchive::SetError(const std::string& e)
diff --git a/Source/cmScanDepFormat.cxx b/Source/cmScanDepFormat.cxx
new file mode 100644 (file)
index 0000000..e046069
--- /dev/null
@@ -0,0 +1,265 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmScanDepFormat.h"
+
+#include <cctype>
+#include <cstdio>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGeneratedFileStream.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static bool ParseFilename(Json::Value const& val, std::string& result)
+{
+  if (val.isString()) {
+    result = val.asString();
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+static Json::Value EncodeFilename(std::string const& path)
+{
+  std::string data;
+  data.reserve(path.size());
+
+  for (auto const& byte : path) {
+    if (std::iscntrl(byte)) {
+      // Control characters.
+      data.append("\\u");
+      char buf[5];
+      std::snprintf(buf, sizeof(buf), "%04x", byte);
+      data.append(buf);
+    } else if (byte == '"' || byte == '\\') {
+      // Special JSON characters.
+      data.push_back('\\');
+      data.push_back(byte);
+    } else {
+      // Other data.
+      data.push_back(byte);
+    }
+  }
+
+  return data;
+}
+
+#define PARSE_BLOB(val, res)                                                  \
+  do {                                                                        \
+    if (!ParseFilename(val, res)) {                                           \
+      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \
+                                    arg_pp, ": invalid blob"));               \
+      return false;                                                           \
+    }                                                                         \
+  } while (0)
+
+#define PARSE_FILENAME(val, res)                                              \
+  do {                                                                        \
+    if (!ParseFilename(val, res)) {                                           \
+      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \
+                                    arg_pp, ": invalid filename"));           \
+      return false;                                                           \
+    }                                                                         \
+                                                                              \
+    if (!cmSystemTools::FileIsFullPath(res)) {                                \
+      res = cmStrCat(work_directory, '/', res);                               \
+    }                                                                         \
+  } while (0)
+
+bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info)
+{
+  Json::Value ppio;
+  Json::Value const& ppi = ppio;
+  cmsys::ifstream ppf(arg_pp.c_str(), std::ios::in | std::ios::binary);
+  {
+    Json::Reader reader;
+    if (!reader.parse(ppf, ppio, false)) {
+      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+                                    arg_pp,
+                                    reader.getFormattedErrorMessages()));
+      return false;
+    }
+  }
+
+  Json::Value const& version = ppi["version"];
+  if (version.asUInt() != 0) {
+    cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+                                  arg_pp, ": version ", version.asString()));
+    return false;
+  }
+
+  Json::Value const& rules = ppi["rules"];
+  if (rules.isArray()) {
+    if (rules.size() != 1) {
+      cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+                                    arg_pp, ": expected 1 source entry"));
+      return false;
+    }
+
+    for (auto const& rule : rules) {
+      Json::Value const& workdir = rule["work-directory"];
+      if (!workdir.isString()) {
+        cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
+                                      arg_pp,
+                                      ": work-directory is not a string"));
+        return false;
+      }
+      std::string work_directory;
+      PARSE_BLOB(workdir, work_directory);
+
+      Json::Value const& depends = rule["depends"];
+      if (depends.isArray()) {
+        std::string depend_filename;
+        for (auto const& depend : depends) {
+          PARSE_FILENAME(depend, depend_filename);
+          info->Includes.push_back(depend_filename);
+        }
+      }
+
+      if (rule.isMember("future-compile")) {
+        Json::Value const& future_compile = rule["future-compile"];
+
+        if (future_compile.isMember("outputs")) {
+          Json::Value const& outputs = future_compile["outputs"];
+          if (outputs.isArray()) {
+            if (outputs.empty()) {
+              cmSystemTools::Error(
+                cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp,
+                         ": expected at least one 1 output"));
+              return false;
+            }
+
+            PARSE_FILENAME(outputs[0], info->PrimaryOutput);
+          }
+        }
+
+        if (future_compile.isMember("provides")) {
+          Json::Value const& provides = future_compile["provides"];
+          if (provides.isArray()) {
+            for (auto const& provide : provides) {
+              cmSourceReqInfo provide_info;
+
+              Json::Value const& logical_name = provide["logical-name"];
+              PARSE_BLOB(logical_name, provide_info.LogicalName);
+
+              if (provide.isMember("compiled-module-path")) {
+                Json::Value const& compiled_module_path =
+                  provide["compiled-module-path"];
+                PARSE_FILENAME(compiled_module_path,
+                               provide_info.CompiledModulePath);
+              } else {
+                provide_info.CompiledModulePath =
+                  cmStrCat(provide_info.LogicalName, ".mod");
+              }
+
+              info->Provides.push_back(provide_info);
+            }
+          }
+        }
+
+        if (future_compile.isMember("requires")) {
+          Json::Value const& reqs = future_compile["requires"];
+          if (reqs.isArray()) {
+            for (auto const& require : reqs) {
+              cmSourceReqInfo require_info;
+
+              Json::Value const& logical_name = require["logical-name"];
+              PARSE_BLOB(logical_name, require_info.LogicalName);
+
+              if (require.isMember("compiled-module-path")) {
+                Json::Value const& compiled_module_path =
+                  require["compiled-module-path"];
+                PARSE_FILENAME(compiled_module_path,
+                               require_info.CompiledModulePath);
+              }
+
+              info->Requires.push_back(require_info);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+bool cmScanDepFormat_P1689_Write(std::string const& path,
+                                 std::string const& input,
+                                 cmSourceInfo const& info)
+{
+  Json::Value ddi(Json::objectValue);
+  ddi["version"] = 0;
+  ddi["revision"] = 0;
+
+  Json::Value& rules = ddi["rules"] = Json::arrayValue;
+
+  Json::Value rule(Json::objectValue);
+  rule["work-directory"] =
+    EncodeFilename(cmSystemTools::GetCurrentWorkingDirectory());
+  Json::Value& inputs = rule["inputs"] = Json::arrayValue;
+  inputs.append(EncodeFilename(input));
+
+  Json::Value& rule_outputs = rule["outputs"] = Json::arrayValue;
+  rule_outputs.append(EncodeFilename(path));
+
+  Json::Value& depends = rule["depends"] = Json::arrayValue;
+  for (auto const& include : info.Includes) {
+    depends.append(EncodeFilename(include));
+  }
+
+  Json::Value& future_compile = rule["future-compile"] = Json::objectValue;
+
+  Json::Value& outputs = future_compile["outputs"] = Json::arrayValue;
+  outputs.append(info.PrimaryOutput);
+
+  Json::Value& provides = future_compile["provides"] = Json::arrayValue;
+  for (auto const& provide : info.Provides) {
+    Json::Value provide_obj(Json::objectValue);
+    auto const encoded = EncodeFilename(provide.LogicalName);
+    provide_obj["logical-name"] = encoded;
+    if (provide.CompiledModulePath.empty()) {
+      provide_obj["compiled-module-path"] = encoded;
+    } else {
+      provide_obj["compiled-module-path"] =
+        EncodeFilename(provide.CompiledModulePath);
+    }
+
+    // TODO: Source file tracking. See below.
+
+    provides.append(provide_obj);
+  }
+
+  Json::Value& reqs = future_compile["requires"] = Json::arrayValue;
+  for (auto const& require : info.Requires) {
+    Json::Value require_obj(Json::objectValue);
+    auto const encoded = EncodeFilename(require.LogicalName);
+    require_obj["logical-name"] = encoded;
+    if (require.CompiledModulePath.empty()) {
+      require_obj["compiled-module-path"] = encoded;
+    } else {
+      require_obj["compiled-module-path"] =
+        EncodeFilename(require.CompiledModulePath);
+    }
+
+    // TODO: Source filename inclusion. Requires collating with the provides
+    // filenames (as a sanity check if available on both sides).
+
+    reqs.append(require_obj);
+  }
+
+  rules.append(rule);
+
+  cmGeneratedFileStream ddif(path);
+  ddif << ddi;
+
+  return !!ddif;
+}
diff --git a/Source/cmScanDepFormat.h b/Source/cmScanDepFormat.h
new file mode 100644 (file)
index 0000000..1ad0ecf
--- /dev/null
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <string>
+#include <vector>
+
+struct cmSourceReqInfo
+{
+  std::string LogicalName;
+  std::string CompiledModulePath;
+};
+
+struct cmSourceInfo
+{
+  std::string PrimaryOutput;
+
+  // Set of provided and required modules.
+  std::vector<cmSourceReqInfo> Provides;
+  std::vector<cmSourceReqInfo> Requires;
+
+  // Set of files included in the translation unit.
+  std::vector<std::string> Includes;
+};
+
+bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp,
+                                 cmSourceInfo* info);
+bool cmScanDepFormat_P1689_Write(std::string const& path,
+                                 std::string const& input,
+                                 cmSourceInfo const& info);
index adc0679..5ac7be9 100644 (file)
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmScriptGenerator.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "cmStringAlgorithms.h"
@@ -11,7 +12,6 @@ cmScriptGenerator::cmScriptGenerator(std::string config_var,
                                      std::vector<std::string> configurations)
   : RuntimeConfigVariable(std::move(config_var))
   , Configurations(std::move(configurations))
-  , ConfigurationName("")
   , ConfigurationTypes(nullptr)
   , ActionsPerConfig(false)
 {
@@ -120,12 +120,10 @@ bool cmScriptGenerator::GeneratesForConfig(const std::string& config)
   // This is a configuration-specific rule.  Check if the config
   // matches this rule.
   std::string config_upper = cmSystemTools::UpperCase(config);
-  for (std::string const& cfg : this->Configurations) {
-    if (cmSystemTools::UpperCase(cfg) == config_upper) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(this->Configurations.begin(), this->Configurations.end(),
+                     [&config_upper](std::string const& cfg) -> bool {
+                       return cmSystemTools::UpperCase(cfg) == config_upper;
+                     });
 }
 
 void cmScriptGenerator::GenerateScriptActionsOnce(std::ostream& os,
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
deleted file mode 100644 (file)
index 7f97406..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmServer.h"
-
-#include <algorithm>
-#include <cassert>
-#include <csignal>
-#include <cstdint>
-#include <iostream>
-#include <mutex>
-#include <utility>
-
-#include <cm/memory>
-#include <cm/shared_mutex>
-
-#include <cm3p/json/reader.h>
-#include <cm3p/json/writer.h>
-
-#include "cmsys/FStream.hxx"
-
-#include "cmConnection.h"
-#include "cmFileMonitor.h"
-#include "cmJsonObjectDictionary.h"
-#include "cmServerDictionary.h"
-#include "cmServerProtocol.h"
-#include "cmSystemTools.h"
-#include "cmake.h"
-
-void on_signal(uv_signal_t* signal, int signum)
-{
-  auto conn = static_cast<cmServerBase*>(signal->data);
-  conn->OnSignal(signum);
-}
-
-static void on_walk_to_shutdown(uv_handle_t* handle, void* arg)
-{
-  (void)arg;
-  assert(uv_is_closing(handle));
-  if (!uv_is_closing(handle)) {
-    uv_close(handle, &cmEventBasedConnection::on_close);
-  }
-}
-
-class cmServer::DebugInfo
-{
-public:
-  DebugInfo()
-    : StartTime(uv_hrtime())
-  {
-  }
-
-  bool PrintStatistics = false;
-
-  std::string OutputFile;
-  uint64_t StartTime;
-};
-
-cmServer::cmServer(cmConnection* conn, bool supportExperimental)
-  : cmServerBase(conn)
-  , SupportExperimental(supportExperimental)
-{
-  // Register supported protocols:
-  this->RegisterProtocol(cm::make_unique<cmServerProtocol1>());
-}
-
-cmServer::~cmServer()
-{
-  Close();
-}
-
-void cmServer::ProcessRequest(cmConnection* connection,
-                              const std::string& input)
-{
-  Json::Reader reader;
-  Json::Value value;
-  if (!reader.parse(input, value)) {
-    this->WriteParseError(connection, "Failed to parse JSON input.");
-    return;
-  }
-
-  std::unique_ptr<DebugInfo> debug;
-  Json::Value debugValue = value["debug"];
-  if (!debugValue.isNull()) {
-    debug = cm::make_unique<DebugInfo>();
-    debug->OutputFile = debugValue["dumpToFile"].asString();
-    debug->PrintStatistics = debugValue["showStats"].asBool();
-  }
-
-  const cmServerRequest request(this, connection, value[kTYPE_KEY].asString(),
-                                value[kCOOKIE_KEY].asString(), value);
-
-  if (request.Type.empty()) {
-    cmServerResponse response(request);
-    response.SetError("No type given in request.");
-    this->WriteResponse(connection, response, nullptr);
-    return;
-  }
-
-  cmSystemTools::SetMessageCallback(
-    [&request](const std::string& msg, const char* title) {
-      reportMessage(msg, title, request);
-    });
-
-  if (this->Protocol) {
-    this->Protocol->CMakeInstance()->SetProgressCallback(
-      [&request](const std::string& msg, float prog) {
-        reportProgress(msg, prog, request);
-      });
-    this->WriteResponse(connection, this->Protocol->Process(request),
-                        debug.get());
-  } else {
-    this->WriteResponse(connection, this->SetProtocolVersion(request),
-                        debug.get());
-  }
-}
-
-void cmServer::RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol)
-{
-  if (protocol->IsExperimental() && !this->SupportExperimental) {
-    protocol.reset();
-    return;
-  }
-  auto version = protocol->ProtocolVersion();
-  assert(version.first >= 0);
-  assert(version.second >= 0);
-  auto it = std::find_if(
-    this->SupportedProtocols.begin(), this->SupportedProtocols.end(),
-    [version](const std::unique_ptr<cmServerProtocol>& p) {
-      return p->ProtocolVersion() == version;
-    });
-  if (it == this->SupportedProtocols.end()) {
-    this->SupportedProtocols.push_back(std::move(protocol));
-  }
-}
-
-void cmServer::PrintHello(cmConnection* connection) const
-{
-  Json::Value hello = Json::objectValue;
-  hello[kTYPE_KEY] = "hello";
-
-  Json::Value& protocolVersions = hello[kSUPPORTED_PROTOCOL_VERSIONS] =
-    Json::arrayValue;
-
-  for (auto const& proto : this->SupportedProtocols) {
-    auto version = proto->ProtocolVersion();
-    Json::Value tmp = Json::objectValue;
-    tmp[kMAJOR_KEY] = version.first;
-    tmp[kMINOR_KEY] = version.second;
-    if (proto->IsExperimental()) {
-      tmp[kIS_EXPERIMENTAL_KEY] = true;
-    }
-    protocolVersions.append(tmp);
-  }
-
-  this->WriteJsonObject(connection, hello, nullptr);
-}
-
-void cmServer::reportProgress(const std::string& msg, float progress,
-                              const cmServerRequest& request)
-{
-  if (progress < 0.0f || progress > 1.0f) {
-    request.ReportMessage(msg, "");
-  } else {
-    request.ReportProgress(0, static_cast<int>(progress * 1000), 1000, msg);
-  }
-}
-
-void cmServer::reportMessage(const std::string& msg, const char* title,
-                             const cmServerRequest& request)
-{
-  std::string titleString;
-  if (title) {
-    titleString = title;
-  }
-  request.ReportMessage(msg, titleString);
-}
-
-cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
-{
-  if (request.Type != kHANDSHAKE_TYPE) {
-    return request.ReportError("Waiting for type \"" + kHANDSHAKE_TYPE +
-                               "\".");
-  }
-
-  Json::Value requestedProtocolVersion = request.Data[kPROTOCOL_VERSION_KEY];
-  if (requestedProtocolVersion.isNull()) {
-    return request.ReportError("\"" + kPROTOCOL_VERSION_KEY +
-                               "\" is required for \"" + kHANDSHAKE_TYPE +
-                               "\".");
-  }
-
-  if (!requestedProtocolVersion.isObject()) {
-    return request.ReportError("\"" + kPROTOCOL_VERSION_KEY +
-                               "\" must be a JSON object.");
-  }
-
-  Json::Value majorValue = requestedProtocolVersion[kMAJOR_KEY];
-  if (!majorValue.isInt()) {
-    return request.ReportError("\"" + kMAJOR_KEY +
-                               "\" must be set and an integer.");
-  }
-
-  Json::Value minorValue = requestedProtocolVersion[kMINOR_KEY];
-  if (!minorValue.isNull() && !minorValue.isInt()) {
-    return request.ReportError("\"" + kMINOR_KEY +
-                               "\" must be unset or an integer.");
-  }
-
-  const int major = majorValue.asInt();
-  const int minor = minorValue.isNull() ? -1 : minorValue.asInt();
-  if (major < 0) {
-    return request.ReportError("\"" + kMAJOR_KEY + "\" must be >= 0.");
-  }
-  if (!minorValue.isNull() && minor < 0) {
-    return request.ReportError("\"" + kMINOR_KEY +
-                               "\" must be >= 0 when set.");
-  }
-
-  this->Protocol =
-    cmServer::FindMatchingProtocol(this->SupportedProtocols, major, minor);
-  if (!this->Protocol) {
-    return request.ReportError("Protocol version not supported.");
-  }
-
-  std::string errorMessage;
-  if (!this->Protocol->Activate(this, request, &errorMessage)) {
-    this->Protocol = nullptr;
-    return request.ReportError("Failed to activate protocol version: " +
-                               errorMessage);
-  }
-  return request.Reply(Json::objectValue);
-}
-
-bool cmServer::Serve(std::string* errorMessage)
-{
-  if (this->SupportedProtocols.empty()) {
-    *errorMessage =
-      "No protocol versions defined. Maybe you need --experimental?";
-    return false;
-  }
-  assert(!this->Protocol);
-
-  return cmServerBase::Serve(errorMessage);
-}
-
-cmFileMonitor* cmServer::FileMonitor() const
-{
-  return fileMonitor.get();
-}
-
-void cmServer::WriteJsonObject(const Json::Value& jsonValue,
-                               const DebugInfo* debug) const
-{
-  cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex);
-  for (auto& connection : this->Connections) {
-    WriteJsonObject(connection.get(), jsonValue, debug);
-  }
-}
-
-void cmServer::WriteJsonObject(cmConnection* connection,
-                               const Json::Value& jsonValue,
-                               const DebugInfo* debug) const
-{
-  Json::FastWriter writer;
-
-  auto beforeJson = uv_hrtime();
-  std::string result = writer.write(jsonValue);
-
-  if (debug) {
-    Json::Value copy = jsonValue;
-    if (debug->PrintStatistics) {
-      Json::Value stats = Json::objectValue;
-      auto endTime = uv_hrtime();
-
-      stats["jsonSerialization"] = double(endTime - beforeJson) / 1000000.0;
-      stats["totalTime"] = double(endTime - debug->StartTime) / 1000000.0;
-      stats["size"] = static_cast<int>(result.size());
-      if (!debug->OutputFile.empty()) {
-        stats["dumpFile"] = debug->OutputFile;
-      }
-
-      copy["zzzDebug"] = stats;
-
-      result = writer.write(copy); // Update result to include debug info
-    }
-
-    if (!debug->OutputFile.empty()) {
-      cmsys::ofstream myfile(debug->OutputFile.c_str());
-      myfile << result;
-    }
-  }
-
-  connection->WriteData(result);
-}
-
-cmServerProtocol* cmServer::FindMatchingProtocol(
-  const std::vector<std::unique_ptr<cmServerProtocol>>& protocols, int major,
-  int minor)
-{
-  cmServerProtocol* bestMatch = nullptr;
-  for (const auto& protocol : protocols) {
-    auto version = protocol->ProtocolVersion();
-    if (major != version.first) {
-      continue;
-    }
-    if (minor == version.second) {
-      return protocol.get();
-    }
-    if (!bestMatch || bestMatch->ProtocolVersion().second < version.second) {
-      bestMatch = protocol.get();
-    }
-  }
-  return minor < 0 ? bestMatch : nullptr;
-}
-
-void cmServer::WriteProgress(const cmServerRequest& request, int min,
-                             int current, int max,
-                             const std::string& message) const
-{
-  assert(min <= current && current <= max);
-  assert(message.length() != 0);
-
-  Json::Value obj = Json::objectValue;
-  obj[kTYPE_KEY] = kPROGRESS_TYPE;
-  obj[kREPLY_TO_KEY] = request.Type;
-  obj[kCOOKIE_KEY] = request.Cookie;
-  obj[kPROGRESS_MESSAGE_KEY] = message;
-  obj[kPROGRESS_MINIMUM_KEY] = min;
-  obj[kPROGRESS_MAXIMUM_KEY] = max;
-  obj[kPROGRESS_CURRENT_KEY] = current;
-
-  this->WriteJsonObject(request.Connection, obj, nullptr);
-}
-
-void cmServer::WriteMessage(const cmServerRequest& request,
-                            const std::string& message,
-                            const std::string& title) const
-{
-  if (message.empty()) {
-    return;
-  }
-
-  Json::Value obj = Json::objectValue;
-  obj[kTYPE_KEY] = kMESSAGE_TYPE;
-  obj[kREPLY_TO_KEY] = request.Type;
-  obj[kCOOKIE_KEY] = request.Cookie;
-  obj[kMESSAGE_KEY] = message;
-  if (!title.empty()) {
-    obj[kTITLE_KEY] = title;
-  }
-
-  WriteJsonObject(request.Connection, obj, nullptr);
-}
-
-void cmServer::WriteParseError(cmConnection* connection,
-                               const std::string& message) const
-{
-  Json::Value obj = Json::objectValue;
-  obj[kTYPE_KEY] = kERROR_TYPE;
-  obj[kERROR_MESSAGE_KEY] = message;
-  obj[kREPLY_TO_KEY] = "";
-  obj[kCOOKIE_KEY] = "";
-
-  this->WriteJsonObject(connection, obj, nullptr);
-}
-
-void cmServer::WriteSignal(const std::string& name,
-                           const Json::Value& data) const
-{
-  assert(data.isObject());
-  Json::Value obj = data;
-  obj[kTYPE_KEY] = kSIGNAL_TYPE;
-  obj[kREPLY_TO_KEY] = "";
-  obj[kCOOKIE_KEY] = "";
-  obj[kNAME_KEY] = name;
-
-  WriteJsonObject(obj, nullptr);
-}
-
-void cmServer::WriteResponse(cmConnection* connection,
-                             const cmServerResponse& response,
-                             const DebugInfo* debug) const
-{
-  assert(response.IsComplete());
-
-  Json::Value obj = response.Data();
-  obj[kCOOKIE_KEY] = response.Cookie;
-  obj[kTYPE_KEY] = response.IsError() ? kERROR_TYPE : kREPLY_TYPE;
-  obj[kREPLY_TO_KEY] = response.Type;
-  if (response.IsError()) {
-    obj[kERROR_MESSAGE_KEY] = response.ErrorMessage();
-  }
-
-  this->WriteJsonObject(connection, obj, debug);
-}
-
-void cmServer::OnConnected(cmConnection* connection)
-{
-  PrintHello(connection);
-}
-
-void cmServer::OnServeStart()
-{
-  cmServerBase::OnServeStart();
-  fileMonitor = std::make_shared<cmFileMonitor>(GetLoop());
-}
-
-void cmServer::StartShutDown()
-{
-  if (fileMonitor) {
-    fileMonitor->StopMonitoring();
-    fileMonitor.reset();
-  }
-  cmServerBase::StartShutDown();
-}
-
-static void __start_thread(void* arg)
-{
-  auto server = static_cast<cmServerBase*>(arg);
-  std::string error;
-  bool success = server->Serve(&error);
-  if (!success || !error.empty()) {
-    std::cerr << "Error during serve: " << error << std::endl;
-  }
-}
-
-bool cmServerBase::StartServeThread()
-{
-  ServeThreadRunning = true;
-  uv_thread_create(&ServeThread, __start_thread, this);
-  return true;
-}
-
-static void __shutdownThread(uv_async_t* arg)
-{
-  auto server = static_cast<cmServerBase*>(arg->data);
-  server->StartShutDown();
-}
-
-bool cmServerBase::Serve(std::string* errorMessage)
-{
-#ifndef NDEBUG
-  uv_thread_t blank_thread_t = {};
-  assert(uv_thread_equal(&blank_thread_t, &ServeThreadId));
-  ServeThreadId = uv_thread_self();
-#endif
-
-  errorMessage->clear();
-
-  ShutdownSignal.init(Loop, __shutdownThread, this);
-
-  SIGINTHandler.init(Loop, this);
-  SIGHUPHandler.init(Loop, this);
-
-  SIGINTHandler.start(&on_signal, SIGINT);
-  SIGHUPHandler.start(&on_signal, SIGHUP);
-
-  OnServeStart();
-
-  {
-    cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex);
-    for (auto& connection : Connections) {
-      if (!connection->OnServeStart(errorMessage)) {
-        return false;
-      }
-    }
-  }
-
-  if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
-    // It is important we don't ever let the event loop exit with open handles
-    // at best this is a memory leak, but it can also introduce race conditions
-    // which can hang the program.
-    assert(false && "Event loop stopped in unclean state.");
-
-    *errorMessage = "Internal Error: Event loop stopped in unclean state.";
-    return false;
-  }
-
-  return true;
-}
-
-void cmServerBase::OnConnected(cmConnection*)
-{
-}
-
-void cmServerBase::OnServeStart()
-{
-}
-
-void cmServerBase::StartShutDown()
-{
-  ShutdownSignal.reset();
-  SIGINTHandler.reset();
-  SIGHUPHandler.reset();
-
-  {
-    std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex);
-    for (auto& connection : Connections) {
-      connection->OnConnectionShuttingDown();
-    }
-    Connections.clear();
-  }
-
-  uv_walk(&Loop, on_walk_to_shutdown, nullptr);
-}
-
-bool cmServerBase::OnSignal(int signum)
-{
-  (void)signum;
-  StartShutDown();
-  return true;
-}
-
-cmServerBase::cmServerBase(cmConnection* connection)
-{
-  auto err = uv_loop_init(&Loop);
-  (void)err;
-  Loop.data = this;
-  assert(err == 0);
-
-  AddNewConnection(connection);
-}
-
-void cmServerBase::Close()
-{
-  if (Loop.data) {
-    if (ServeThreadRunning) {
-      this->ShutdownSignal.send();
-      uv_thread_join(&ServeThread);
-    }
-
-    uv_loop_close(&Loop);
-    Loop.data = nullptr;
-  }
-}
-cmServerBase::~cmServerBase()
-{
-  Close();
-}
-
-void cmServerBase::AddNewConnection(cmConnection* ownedConnection)
-{
-  {
-    std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex);
-    Connections.emplace_back(ownedConnection);
-  }
-  ownedConnection->SetServer(this);
-}
-
-uv_loop_t* cmServerBase::GetLoop()
-{
-  return &Loop;
-}
-
-void cmServerBase::OnDisconnect(cmConnection* pConnection)
-{
-  auto pred = [pConnection](const std::unique_ptr<cmConnection>& m) {
-    return m.get() == pConnection;
-  };
-  {
-    std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex);
-    Connections.erase(
-      std::remove_if(Connections.begin(), Connections.end(), pred),
-      Connections.end());
-  }
-
-  if (Connections.empty()) {
-    this->ShutdownSignal.send();
-  }
-}
diff --git a/Source/cmServer.h b/Source/cmServer.h
deleted file mode 100644 (file)
index 9543329..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <cm/shared_mutex>
-
-#include <cm3p/json/value.h>
-#include <cm3p/uv.h>
-
-#include "cmUVHandlePtr.h"
-
-class cmConnection;
-class cmFileMonitor;
-class cmServerProtocol;
-class cmServerRequest;
-class cmServerResponse;
-
-/***
- * This essentially hold and manages a libuv event queue and responds to
- * messages
- * on any of its connections.
- */
-class cmServerBase
-{
-public:
-  cmServerBase(cmConnection* connection);
-  virtual ~cmServerBase();
-
-  virtual void AddNewConnection(cmConnection* ownedConnection);
-
-  /***
-   * The main override responsible for tailoring behavior towards
-   * whatever the given server is supposed to do
-   *
-   * This should almost always be called by the given connections
-   * directly.
-   *
-   * @param connection The connection the request was received on
-   * @param request The actual request
-   */
-  virtual void ProcessRequest(cmConnection* connection,
-                              const std::string& request) = 0;
-  virtual void OnConnected(cmConnection* connection);
-
-  /***
-   * Start a dedicated thread. If this is used to start the server, it will
-   * join on the
-   * servers dtor.
-   */
-  virtual bool StartServeThread();
-  virtual bool Serve(std::string* errorMessage);
-
-  virtual void OnServeStart();
-  virtual void StartShutDown();
-
-  virtual bool OnSignal(int signum);
-  uv_loop_t* GetLoop();
-  void Close();
-  void OnDisconnect(cmConnection* pConnection);
-
-protected:
-  mutable cm::shared_mutex ConnectionsMutex;
-  std::vector<std::unique_ptr<cmConnection>> Connections;
-
-  bool ServeThreadRunning = false;
-  uv_thread_t ServeThread;
-  cm::uv_async_ptr ShutdownSignal;
-#ifndef NDEBUG
-public:
-  // When the server starts it will mark down it's current thread ID,
-  // which is useful in other contexts to just assert that operations
-  // are performed on that same thread.
-  uv_thread_t ServeThreadId = {};
-
-protected:
-#endif
-
-  uv_loop_t Loop;
-
-  cm::uv_signal_ptr SIGINTHandler;
-  cm::uv_signal_ptr SIGHUPHandler;
-};
-
-class cmServer : public cmServerBase
-{
-public:
-  class DebugInfo;
-
-  cmServer(cmConnection* conn, bool supportExperimental);
-  ~cmServer() override;
-
-  cmServer(cmServer const&) = delete;
-  cmServer& operator=(cmServer const&) = delete;
-
-  bool Serve(std::string* errorMessage) override;
-
-  cmFileMonitor* FileMonitor() const;
-
-private:
-  void RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol);
-
-  // Callbacks from cmServerConnection:
-
-  void ProcessRequest(cmConnection* connection,
-                      const std::string& request) override;
-  std::shared_ptr<cmFileMonitor> fileMonitor;
-
-public:
-  void OnServeStart() override;
-
-  void StartShutDown() override;
-
-public:
-  void OnConnected(cmConnection* connection) override;
-
-private:
-  static void reportProgress(const std::string& msg, float progress,
-                             const cmServerRequest& request);
-  static void reportMessage(const std::string& msg, const char* title,
-                            const cmServerRequest& request);
-
-  // Handle requests:
-  cmServerResponse SetProtocolVersion(const cmServerRequest& request);
-
-  void PrintHello(cmConnection* connection) const;
-
-  // Write responses:
-  void WriteProgress(const cmServerRequest& request, int min, int current,
-                     int max, const std::string& message) const;
-  void WriteMessage(const cmServerRequest& request, const std::string& message,
-                    const std::string& title) const;
-  void WriteResponse(cmConnection* connection,
-                     const cmServerResponse& response,
-                     const DebugInfo* debug) const;
-  void WriteParseError(cmConnection* connection,
-                       const std::string& message) const;
-  void WriteSignal(const std::string& name, const Json::Value& obj) const;
-
-  void WriteJsonObject(Json::Value const& jsonValue,
-                       const DebugInfo* debug) const;
-
-  void WriteJsonObject(cmConnection* connection, Json::Value const& jsonValue,
-                       const DebugInfo* debug) const;
-
-  static cmServerProtocol* FindMatchingProtocol(
-    const std::vector<std::unique_ptr<cmServerProtocol>>& protocols, int major,
-    int minor);
-
-  const bool SupportExperimental;
-
-  cmServerProtocol* Protocol = nullptr;
-  std::vector<std::unique_ptr<cmServerProtocol>> SupportedProtocols;
-
-  friend class cmServerProtocol;
-  friend class cmServerRequest;
-};
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
deleted file mode 100644 (file)
index b4f41a0..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmConfigure.h"
-
-#include "cmServerConnection.h"
-
-#include <cm3p/uv.h>
-
-#include "cmServer.h"
-#include "cmServerDictionary.h"
-
-#ifdef _WIN32
-#  include "io.h"
-#else
-#  include <unistd.h>
-#endif
-#include <cassert>
-#include <utility>
-
-cmStdIoConnection::cmStdIoConnection(
-  cmConnectionBufferStrategy* bufferStrategy)
-  : cmEventBasedConnection(bufferStrategy)
-{
-}
-
-cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id)
-{
-  switch (uv_guess_handle(file_id)) {
-    case UV_TTY: {
-      cm::uv_tty_ptr tty;
-      tty.init(*this->Server->GetLoop(), file_id, file_id == 0,
-               static_cast<cmEventBasedConnection*>(this));
-      uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL);
-      return { std::move(tty) };
-    }
-    case UV_FILE:
-      if (file_id == 0) {
-        return nullptr;
-      }
-      // Intentional fallthrough; stdin can _not_ be treated as a named
-      // pipe, however stdout can be.
-      CM_FALLTHROUGH;
-    case UV_NAMED_PIPE: {
-      cm::uv_pipe_ptr pipe;
-      pipe.init(*this->Server->GetLoop(), 0,
-                static_cast<cmEventBasedConnection*>(this));
-      uv_pipe_open(pipe, file_id);
-      return { std::move(pipe) };
-    }
-    default:
-      assert(false && "Unable to determine stream type");
-      return nullptr;
-  }
-}
-
-void cmStdIoConnection::SetServer(cmServerBase* s)
-{
-  cmConnection::SetServer(s);
-  if (!s) {
-    return;
-  }
-
-  this->ReadStream = SetupStream(0);
-  this->WriteStream = SetupStream(1);
-}
-
-void shutdown_connection(uv_prepare_t* prepare)
-{
-  cmStdIoConnection* connection =
-    static_cast<cmStdIoConnection*>(prepare->data);
-
-  if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(prepare))) {
-    uv_close(reinterpret_cast<uv_handle_t*>(prepare),
-             &cmEventBasedConnection::on_close_delete<uv_prepare_t>);
-  }
-  connection->OnDisconnect(0);
-}
-
-bool cmStdIoConnection::OnServeStart(std::string* pString)
-{
-  Server->OnConnected(this);
-  if (this->ReadStream.get()) {
-    uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
-  } else if (uv_guess_handle(0) == UV_FILE) {
-    char buffer[1024];
-    while (auto len = read(0, buffer, sizeof(buffer))) {
-      ReadData(std::string(buffer, buffer + len));
-    }
-
-    // We can't start the disconnect from here, add a prepare hook to do that
-    // for us
-    auto prepare = new uv_prepare_t();
-    prepare->data = this;
-    uv_prepare_init(Server->GetLoop(), prepare);
-    uv_prepare_start(prepare, shutdown_connection);
-  }
-  return cmConnection::OnServeStart(pString);
-}
-
-bool cmStdIoConnection::OnConnectionShuttingDown()
-{
-  if (ReadStream.get()) {
-    uv_read_stop(ReadStream);
-    ReadStream->data = nullptr;
-  }
-
-  this->ReadStream.reset();
-
-  cmEventBasedConnection::OnConnectionShuttingDown();
-
-  return true;
-}
-
-cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
-  : cmPipeConnection(name, new cmServerBufferStrategy)
-{
-}
-
-cmServerStdIoConnection::cmServerStdIoConnection()
-  : cmStdIoConnection(new cmServerBufferStrategy)
-{
-}
-
-cmConnectionBufferStrategy::~cmConnectionBufferStrategy() = default;
-
-void cmConnectionBufferStrategy::clear()
-{
-}
-
-std::string cmServerBufferStrategy::BufferOutMessage(
-  const std::string& rawBuffer) const
-{
-  return std::string("\n") + kSTART_MAGIC + std::string("\n") + rawBuffer +
-    kEND_MAGIC + std::string("\n");
-}
-
-std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer)
-{
-  for (;;) {
-    auto needle = RawReadBuffer.find('\n');
-
-    if (needle == std::string::npos) {
-      return "";
-    }
-    std::string line = RawReadBuffer.substr(0, needle);
-    const auto ls = line.size();
-    if (ls > 1 && line.at(ls - 1) == '\r') {
-      line.erase(ls - 1, 1);
-    }
-    RawReadBuffer.erase(RawReadBuffer.begin(),
-                        RawReadBuffer.begin() + static_cast<long>(needle) + 1);
-    if (line == kSTART_MAGIC) {
-      RequestBuffer.clear();
-      continue;
-    }
-    if (line == kEND_MAGIC) {
-      std::string rtn;
-      rtn.swap(this->RequestBuffer);
-      return rtn;
-    }
-
-    this->RequestBuffer += line;
-    this->RequestBuffer += "\n";
-  }
-}
diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h
deleted file mode 100644 (file)
index a70edb4..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <string>
-
-#include "cmConnection.h"
-#include "cmPipeConnection.h"
-#include "cmUVHandlePtr.h"
-
-class cmServerBase;
-
-/***
- * This connection buffer strategy accepts messages in the form of
- * [== "CMake Server" ==[
-{
-  ... some JSON message ...
-}
-]== "CMake Server" ==]
- * and only passes on the core json; it discards the envelope.
- */
-class cmServerBufferStrategy : public cmConnectionBufferStrategy
-{
-public:
-  std::string BufferMessage(std::string& rawBuffer) override;
-  std::string BufferOutMessage(const std::string& rawBuffer) const override;
-
-private:
-  std::string RequestBuffer;
-};
-
-/***
- * Generic connection over std io interfaces -- tty
- */
-class cmStdIoConnection : public cmEventBasedConnection
-{
-public:
-  cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy);
-
-  void SetServer(cmServerBase* s) override;
-
-  bool OnConnectionShuttingDown() override;
-
-  bool OnServeStart(std::string* pString) override;
-
-private:
-  cm::uv_stream_ptr SetupStream(int file_id);
-  cm::uv_stream_ptr ReadStream;
-};
-
-/***
- * These specific connections use the cmake server
- * buffering strategy.
- */
-class cmServerStdIoConnection : public cmStdIoConnection
-{
-public:
-  cmServerStdIoConnection();
-};
-
-class cmServerPipeConnection : public cmPipeConnection
-{
-public:
-  cmServerPipeConnection(const std::string& name);
-};
diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h
deleted file mode 100644 (file)
index 961e4b7..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include <string>
-
-// Vocabulary:
-
-static const std::string kDIRTY_SIGNAL = "dirty";
-static const std::string kFILE_CHANGE_SIGNAL = "fileChange";
-
-static const std::string kCACHE_TYPE = "cache";
-static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs";
-static const std::string kCODE_MODEL_TYPE = "codemodel";
-static const std::string kCOMPUTE_TYPE = "compute";
-static const std::string kCONFIGURE_TYPE = "configure";
-static const std::string kERROR_TYPE = "error";
-static const std::string kFILESYSTEM_WATCHERS_TYPE = "fileSystemWatchers";
-static const std::string kGLOBAL_SETTINGS_TYPE = "globalSettings";
-static const std::string kHANDSHAKE_TYPE = "handshake";
-static const std::string kMESSAGE_TYPE = "message";
-static const std::string kPROGRESS_TYPE = "progress";
-static const std::string kREPLY_TYPE = "reply";
-static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings";
-static const std::string kSIGNAL_TYPE = "signal";
-static const std::string kCTEST_INFO_TYPE = "ctestInfo";
-
-static const std::string kBUILD_FILES_KEY = "buildFiles";
-static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
-static const std::string kCACHE_KEY = "cache";
-static const std::string kCAPABILITIES_KEY = "capabilities";
-static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
-static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory";
-static const std::string kCOOKIE_KEY = "cookie";
-static const std::string kDEBUG_OUTPUT_KEY = "debugOutput";
-static const std::string kERROR_MESSAGE_KEY = "errorMessage";
-static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
-static const std::string kGENERATOR_KEY = "generator";
-static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental";
-static const std::string kKEYS_KEY = "keys";
-static const std::string kMAJOR_KEY = "major";
-static const std::string kMESSAGE_KEY = "message";
-static const std::string kMINOR_KEY = "minor";
-static const std::string kPLATFORM_KEY = "platform";
-static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent";
-static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum";
-static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage";
-static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum";
-static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion";
-static const std::string kREPLY_TO_KEY = "inReplyTo";
-static const std::string kSUPPORTED_PROTOCOL_VERSIONS =
-  "supportedProtocolVersions";
-static const std::string kTITLE_KEY = "title";
-static const std::string kTOOLSET_KEY = "toolset";
-static const std::string kTRACE_EXPAND_KEY = "traceExpand";
-static const std::string kTRACE_KEY = "trace";
-static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized";
-static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli";
-static const std::string kWARN_UNUSED_KEY = "warnUnused";
-static const std::string kWATCHED_DIRECTORIES_KEY = "watchedDirectories";
-static const std::string kWATCHED_FILES_KEY = "watchedFiles";
-
-static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==[";
-static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]";
-
-static const std::string kRENAME_PROPERTY_VALUE = "rename";
-static const std::string kCHANGE_PROPERTY_VALUE = "change";
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
deleted file mode 100644 (file)
index e586fd9..0000000
+++ /dev/null
@@ -1,760 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmServerProtocol.h"
-
-#include <algorithm>
-#include <cassert>
-#include <functional>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <cm/memory>
-#include <cmext/algorithm>
-
-#include <cm3p/uv.h>
-
-#include "cmExternalMakefileProjectGenerator.h"
-#include "cmFileMonitor.h"
-#include "cmGlobalGenerator.h"
-#include "cmJsonObjectDictionary.h"
-#include "cmJsonObjects.h"
-#include "cmMessageType.h"
-#include "cmProperty.h"
-#include "cmServer.h"
-#include "cmServerDictionary.h"
-#include "cmState.h"
-#include "cmSystemTools.h"
-#include "cmake.h"
-
-// Get rid of some windows macros:
-#undef max
-
-namespace {
-
-std::vector<std::string> toStringList(const Json::Value& in)
-{
-  std::vector<std::string> result;
-  for (auto const& it : in) {
-    result.push_back(it.asString());
-  }
-  return result;
-}
-
-} // namespace
-
-cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection,
-                                 std::string t, std::string c, Json::Value d)
-  : Type(std::move(t))
-  , Cookie(std::move(c))
-  , Data(std::move(d))
-  , Connection(connection)
-  , m_Server(server)
-{
-}
-
-void cmServerRequest::ReportProgress(int min, int current, int max,
-                                     const std::string& message) const
-{
-  this->m_Server->WriteProgress(*this, min, current, max, message);
-}
-
-void cmServerRequest::ReportMessage(const std::string& message,
-                                    const std::string& title) const
-{
-  m_Server->WriteMessage(*this, message, title);
-}
-
-cmServerResponse cmServerRequest::Reply(const Json::Value& data) const
-{
-  cmServerResponse response(*this);
-  response.SetData(data);
-  return response;
-}
-
-cmServerResponse cmServerRequest::ReportError(const std::string& message) const
-{
-  cmServerResponse response(*this);
-  response.SetError(message);
-  return response;
-}
-
-cmServerResponse::cmServerResponse(const cmServerRequest& request)
-  : Type(request.Type)
-  , Cookie(request.Cookie)
-{
-}
-
-void cmServerResponse::SetData(const Json::Value& data)
-{
-  assert(this->m_Payload == PAYLOAD_UNKNOWN);
-  if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) {
-    this->SetError("Response contains cookie or type field.");
-    return;
-  }
-  this->m_Payload = PAYLOAD_DATA;
-  this->m_Data = data;
-}
-
-void cmServerResponse::SetError(const std::string& message)
-{
-  assert(this->m_Payload == PAYLOAD_UNKNOWN);
-  this->m_Payload = PAYLOAD_ERROR;
-  this->m_ErrorMessage = message;
-}
-
-bool cmServerResponse::IsComplete() const
-{
-  return this->m_Payload != PAYLOAD_UNKNOWN;
-}
-
-bool cmServerResponse::IsError() const
-{
-  assert(this->m_Payload != PAYLOAD_UNKNOWN);
-  return this->m_Payload == PAYLOAD_ERROR;
-}
-
-std::string cmServerResponse::ErrorMessage() const
-{
-  if (this->m_Payload == PAYLOAD_ERROR) {
-    return this->m_ErrorMessage;
-  }
-  return std::string();
-}
-
-Json::Value cmServerResponse::Data() const
-{
-  assert(this->m_Payload != PAYLOAD_UNKNOWN);
-  return this->m_Data;
-}
-
-bool cmServerProtocol::Activate(cmServer* server,
-                                const cmServerRequest& request,
-                                std::string* errorMessage)
-{
-  assert(server);
-  this->m_Server = server;
-  this->m_CMakeInstance =
-    cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
-  this->m_WarnUnused = false;
-  const bool result = this->DoActivate(request, errorMessage);
-  if (!result) {
-    this->m_CMakeInstance = nullptr;
-  }
-  return result;
-}
-
-cmFileMonitor* cmServerProtocol::FileMonitor() const
-{
-  return this->m_Server ? this->m_Server->FileMonitor() : nullptr;
-}
-
-void cmServerProtocol::SendSignal(const std::string& name,
-                                  const Json::Value& data) const
-{
-  if (this->m_Server) {
-    this->m_Server->WriteSignal(name, data);
-  }
-}
-
-cmake* cmServerProtocol::CMakeInstance() const
-{
-  return this->m_CMakeInstance.get();
-}
-
-bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/,
-                                  std::string* /*errorMessage*/)
-{
-  return true;
-}
-
-std::pair<int, int> cmServerProtocol1::ProtocolVersion() const
-{
-  return { 1, 2 };
-}
-
-static void setErrorMessage(std::string* errorMessage, const std::string& text)
-{
-  if (errorMessage) {
-    *errorMessage = text;
-  }
-}
-
-static bool getOrTestHomeDirectory(cmState* state, std::string& value,
-                                   std::string* errorMessage)
-{
-  const std::string cachedValue =
-    *state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
-  if (value.empty()) {
-    value = cachedValue;
-    return true;
-  }
-  const std::string suffix = "/CMakeLists.txt";
-  const std::string cachedValueCML = cachedValue + suffix;
-  const std::string valueCML = value + suffix;
-  if (!cmSystemTools::SameFile(valueCML, cachedValueCML)) {
-    setErrorMessage(errorMessage,
-                    std::string("\"CMAKE_HOME_DIRECTORY\" is set but "
-                                "incompatible with configured "
-                                "source directory value."));
-    return false;
-  }
-  return true;
-}
-
-static bool getOrTestValue(cmState* state, const std::string& key,
-                           std::string& value,
-                           const std::string& keyDescription,
-                           std::string* errorMessage)
-{
-  const std::string cachedValue = state->GetSafeCacheEntryValue(key);
-  if (value.empty()) {
-    value = cachedValue;
-  }
-  if (!cachedValue.empty() && cachedValue != value) {
-    setErrorMessage(errorMessage,
-                    std::string("\"") + key +
-                      "\" is set but incompatible with configured " +
-                      keyDescription + " value.");
-    return false;
-  }
-  return true;
-}
-
-bool cmServerProtocol1::DoActivate(const cmServerRequest& request,
-                                   std::string* errorMessage)
-{
-  std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString();
-  std::string buildDirectory = request.Data[kBUILD_DIRECTORY_KEY].asString();
-  std::string generator = request.Data[kGENERATOR_KEY].asString();
-  std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString();
-  std::string toolset = request.Data[kTOOLSET_KEY].asString();
-  std::string platform = request.Data[kPLATFORM_KEY].asString();
-
-  // normalize source and build directory
-  if (!sourceDirectory.empty()) {
-    sourceDirectory = cmSystemTools::CollapseFullPath(sourceDirectory);
-    cmSystemTools::ConvertToUnixSlashes(sourceDirectory);
-  }
-  if (!buildDirectory.empty()) {
-    buildDirectory = cmSystemTools::CollapseFullPath(buildDirectory);
-    cmSystemTools::ConvertToUnixSlashes(buildDirectory);
-  }
-
-  if (buildDirectory.empty()) {
-    setErrorMessage(errorMessage,
-                    std::string("\"") + kBUILD_DIRECTORY_KEY +
-                      "\" is missing.");
-    return false;
-  }
-
-  cmake* cm = CMakeInstance();
-  if (cmSystemTools::PathExists(buildDirectory)) {
-    if (!cmSystemTools::FileIsDirectory(buildDirectory)) {
-      setErrorMessage(errorMessage,
-                      std::string("\"") + kBUILD_DIRECTORY_KEY +
-                        "\" exists but is not a directory.");
-      return false;
-    }
-
-    const std::string cachePath = cmake::FindCacheFile(buildDirectory);
-    if (cm->LoadCache(cachePath)) {
-      cmState* state = cm->GetState();
-
-      // Check generator:
-      if (!getOrTestValue(state, "CMAKE_GENERATOR", generator, "generator",
-                          errorMessage)) {
-        return false;
-      }
-
-      // check extra generator:
-      if (!getOrTestValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator,
-                          "extra generator", errorMessage)) {
-        return false;
-      }
-
-      // check sourcedir:
-      if (!getOrTestHomeDirectory(state, sourceDirectory, errorMessage)) {
-        return false;
-      }
-
-      // check toolset:
-      if (!getOrTestValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset",
-                          errorMessage)) {
-        return false;
-      }
-
-      // check platform:
-      if (!getOrTestValue(state, "CMAKE_GENERATOR_PLATFORM", platform,
-                          "platform", errorMessage)) {
-        return false;
-      }
-    }
-  }
-
-  if (sourceDirectory.empty()) {
-    setErrorMessage(errorMessage,
-                    std::string("\"") + kSOURCE_DIRECTORY_KEY +
-                      "\" is unset but required.");
-    return false;
-  }
-  if (!cmSystemTools::FileIsDirectory(sourceDirectory)) {
-    setErrorMessage(errorMessage,
-                    std::string("\"") + kSOURCE_DIRECTORY_KEY +
-                      "\" is not a directory.");
-    return false;
-  }
-  if (generator.empty()) {
-    setErrorMessage(errorMessage,
-                    std::string("\"") + kGENERATOR_KEY +
-                      "\" is unset but required.");
-    return false;
-  }
-
-  std::vector<cmake::GeneratorInfo> generators;
-  cm->GetRegisteredGenerators(generators);
-  auto baseIt = std::find_if(generators.begin(), generators.end(),
-                             [&generator](const cmake::GeneratorInfo& info) {
-                               return info.name == generator;
-                             });
-  if (baseIt == generators.end()) {
-    setErrorMessage(errorMessage,
-                    std::string("Generator \"") + generator +
-                      "\" not supported.");
-    return false;
-  }
-  auto extraIt = std::find_if(
-    generators.begin(), generators.end(),
-    [&generator, &extraGenerator](const cmake::GeneratorInfo& info) {
-      return info.baseName == generator && info.extraName == extraGenerator;
-    });
-  if (extraIt == generators.end()) {
-    setErrorMessage(errorMessage,
-                    std::string("The combination of generator \"" + generator +
-                                "\" and extra generator \"" + extraGenerator +
-                                "\" is not supported."));
-    return false;
-  }
-  if (!extraIt->supportsToolset && !toolset.empty()) {
-    setErrorMessage(errorMessage,
-                    std::string("Toolset was provided but is not supported by "
-                                "the requested generator."));
-    return false;
-  }
-  if (!extraIt->supportsPlatform && !platform.empty()) {
-    setErrorMessage(errorMessage,
-                    std::string("Platform was provided but is not supported "
-                                "by the requested generator."));
-    return false;
-  }
-
-  this->GeneratorInfo =
-    GeneratorInformation(generator, extraGenerator, toolset, platform,
-                         sourceDirectory, buildDirectory);
-
-  this->m_State = STATE_ACTIVE;
-  return true;
-}
-
-void cmServerProtocol1::HandleCMakeFileChanges(const std::string& path,
-                                               int event, int status)
-{
-  assert(status == 0);
-  static_cast<void>(status);
-
-  if (!m_isDirty) {
-    m_isDirty = true;
-    SendSignal(kDIRTY_SIGNAL, Json::objectValue);
-  }
-  Json::Value obj = Json::objectValue;
-  obj[kPATH_KEY] = path;
-  Json::Value properties = Json::arrayValue;
-  if (event & UV_RENAME) {
-    properties.append(kRENAME_PROPERTY_VALUE);
-  }
-  if (event & UV_CHANGE) {
-    properties.append(kCHANGE_PROPERTY_VALUE);
-  }
-
-  obj[kPROPERTIES_KEY] = properties;
-  SendSignal(kFILE_CHANGE_SIGNAL, obj);
-}
-
-cmServerResponse cmServerProtocol1::Process(const cmServerRequest& request)
-{
-  assert(this->m_State >= STATE_ACTIVE);
-
-  if (request.Type == kCACHE_TYPE) {
-    return this->ProcessCache(request);
-  }
-  if (request.Type == kCMAKE_INPUTS_TYPE) {
-    return this->ProcessCMakeInputs(request);
-  }
-  if (request.Type == kCODE_MODEL_TYPE) {
-    return this->ProcessCodeModel(request);
-  }
-  if (request.Type == kCOMPUTE_TYPE) {
-    return this->ProcessCompute(request);
-  }
-  if (request.Type == kCONFIGURE_TYPE) {
-    return this->ProcessConfigure(request);
-  }
-  if (request.Type == kFILESYSTEM_WATCHERS_TYPE) {
-    return this->ProcessFileSystemWatchers(request);
-  }
-  if (request.Type == kGLOBAL_SETTINGS_TYPE) {
-    return this->ProcessGlobalSettings(request);
-  }
-  if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) {
-    return this->ProcessSetGlobalSettings(request);
-  }
-  if (request.Type == kCTEST_INFO_TYPE) {
-    return this->ProcessCTests(request);
-  }
-
-  return request.ReportError("Unknown command!");
-}
-
-bool cmServerProtocol1::IsExperimental() const
-{
-  return true;
-}
-
-cmServerResponse cmServerProtocol1::ProcessCache(
-  const cmServerRequest& request)
-{
-  cmState* state = this->CMakeInstance()->GetState();
-
-  Json::Value result = Json::objectValue;
-
-  std::vector<std::string> allKeys = state->GetCacheEntryKeys();
-
-  Json::Value list = Json::arrayValue;
-  std::vector<std::string> keys = toStringList(request.Data[kKEYS_KEY]);
-  if (keys.empty()) {
-    keys = allKeys;
-  } else {
-    for (auto const& i : keys) {
-      if (!cm::contains(allKeys, i)) {
-        return request.ReportError("Key \"" + i + "\" not found in cache.");
-      }
-    }
-  }
-  std::sort(keys.begin(), keys.end());
-  for (auto const& key : keys) {
-    Json::Value entry = Json::objectValue;
-    entry[kKEY_KEY] = key;
-    entry[kTYPE_KEY] =
-      cmState::CacheEntryTypeToString(state->GetCacheEntryType(key));
-    entry[kVALUE_KEY] = *state->GetCacheEntryValue(key);
-
-    Json::Value props = Json::objectValue;
-    bool haveProperties = false;
-    for (auto const& prop : state->GetCacheEntryPropertyList(key)) {
-      haveProperties = true;
-      props[prop] = *state->GetCacheEntryProperty(key, prop);
-    }
-    if (haveProperties) {
-      entry[kPROPERTIES_KEY] = props;
-    }
-
-    list.append(entry);
-  }
-
-  result[kCACHE_KEY] = list;
-  return request.Reply(result);
-}
-
-cmServerResponse cmServerProtocol1::ProcessCMakeInputs(
-  const cmServerRequest& request)
-{
-  if (this->m_State < STATE_CONFIGURED) {
-    return request.ReportError("This instance was not yet configured.");
-  }
-
-  const cmake* cm = this->CMakeInstance();
-  const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot();
-  const std::string& sourceDir = cm->GetHomeDirectory();
-
-  Json::Value result = Json::objectValue;
-  result[kSOURCE_DIRECTORY_KEY] = sourceDir;
-  result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir;
-  result[kBUILD_FILES_KEY] = cmDumpCMakeInputs(cm);
-  return request.Reply(result);
-}
-
-cmServerResponse cmServerProtocol1::ProcessCodeModel(
-  const cmServerRequest& request)
-{
-  if (this->m_State != STATE_COMPUTED) {
-    return request.ReportError("No build system was generated yet.");
-  }
-
-  return request.Reply(cmDumpCodeModel(this->CMakeInstance()));
-}
-
-cmServerResponse cmServerProtocol1::ProcessCompute(
-  const cmServerRequest& request)
-{
-  if (this->m_State > STATE_CONFIGURED) {
-    return request.ReportError("This build system was already generated.");
-  }
-  if (this->m_State < STATE_CONFIGURED) {
-    return request.ReportError("This project was not configured yet.");
-  }
-
-  cmake* cm = this->CMakeInstance();
-  int ret = cm->Generate();
-
-  if (ret < 0) {
-    return request.ReportError("Failed to compute build system.");
-  }
-  m_State = STATE_COMPUTED;
-  return request.Reply(Json::Value());
-}
-
-cmServerResponse cmServerProtocol1::ProcessConfigure(
-  const cmServerRequest& request)
-{
-  if (this->m_State == STATE_INACTIVE) {
-    return request.ReportError("This instance is inactive.");
-  }
-
-  FileMonitor()->StopMonitoring();
-
-  std::string errorMessage;
-  cmake* cm = this->CMakeInstance();
-  this->GeneratorInfo.SetupGenerator(cm, &errorMessage);
-  if (!errorMessage.empty()) {
-    return request.ReportError(errorMessage);
-  }
-
-  // Make sure the types of cacheArguments matches (if given):
-  std::vector<std::string> cacheArgs = { "unused" };
-  bool cacheArgumentsError = false;
-  const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY];
-  if (!passedArgs.isNull()) {
-    if (passedArgs.isString()) {
-      cacheArgs.push_back(passedArgs.asString());
-    } else if (passedArgs.isArray()) {
-      for (auto const& arg : passedArgs) {
-        if (!arg.isString()) {
-          cacheArgumentsError = true;
-          break;
-        }
-        cacheArgs.push_back(arg.asString());
-      }
-    } else {
-      cacheArgumentsError = true;
-    }
-  }
-  if (cacheArgumentsError) {
-    request.ReportError(
-      "cacheArguments must be unset, a string or an array of strings.");
-  }
-
-  std::string sourceDir = cm->GetHomeDirectory();
-  const std::string buildDir = cm->GetHomeOutputDirectory();
-
-  cmGlobalGenerator* gg = cm->GetGlobalGenerator();
-
-  if (buildDir.empty()) {
-    return request.ReportError("No build directory set via Handshake.");
-  }
-
-  if (cm->LoadCache(buildDir)) {
-    // build directory has been set up before
-    cmProp cachedSourceDir =
-      cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY");
-    if (!cachedSourceDir) {
-      return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache.");
-    }
-    if (sourceDir.empty()) {
-      sourceDir = *cachedSourceDir;
-      cm->SetHomeDirectory(sourceDir);
-    }
-
-    cmProp cachedGenerator =
-      cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR");
-    if (cachedGenerator) {
-      if (gg && gg->GetName() != *cachedGenerator) {
-        return request.ReportError("Configured generator does not match with "
-                                   "CMAKE_GENERATOR found in cache.");
-      }
-    }
-  } else {
-    // build directory has not been set up before
-    if (sourceDir.empty()) {
-      return request.ReportError("No sourceDirectory set via "
-                                 "setGlobalSettings and no cache found in "
-                                 "buildDirectory.");
-    }
-  }
-
-  cmSystemTools::ResetErrorOccuredFlag(); // Reset error state
-
-  if (cm->AddCMakePaths() != 1) {
-    return request.ReportError("Failed to set CMake paths.");
-  }
-
-  if (!cm->SetCacheArgs(cacheArgs)) {
-    return request.ReportError("cacheArguments could not be set.");
-  }
-
-  int ret = cm->Configure();
-  cm->IssueMessage(
-    MessageType::DEPRECATION_WARNING,
-    "The 'cmake-server(7)' is deprecated.  "
-    "Please port clients to use the 'cmake-file-api(7)' instead.");
-  if (ret < 0) {
-    return request.ReportError("Configuration failed.");
-  }
-
-  std::vector<std::string> toWatchList;
-  cmGetCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList,
-                   nullptr);
-
-  FileMonitor()->MonitorPaths(toWatchList,
-                              [this](const std::string& p, int e, int s) {
-                                this->HandleCMakeFileChanges(p, e, s);
-                              });
-
-  m_State = STATE_CONFIGURED;
-  m_isDirty = false;
-  return request.Reply(Json::Value());
-}
-
-cmServerResponse cmServerProtocol1::ProcessGlobalSettings(
-  const cmServerRequest& request)
-{
-  cmake* cm = this->CMakeInstance();
-  Json::Value obj = Json::objectValue;
-
-  // Capabilities information:
-  obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson();
-
-  obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
-  obj[kTRACE_KEY] = cm->GetTrace();
-  obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand();
-  obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized();
-  obj[kWARN_UNUSED_KEY] = m_WarnUnused;
-  obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli();
-  obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars();
-
-  obj[kSOURCE_DIRECTORY_KEY] = this->GeneratorInfo.SourceDirectory;
-  obj[kBUILD_DIRECTORY_KEY] = this->GeneratorInfo.BuildDirectory;
-
-  // Currently used generator:
-  obj[kGENERATOR_KEY] = this->GeneratorInfo.GeneratorName;
-  obj[kEXTRA_GENERATOR_KEY] = this->GeneratorInfo.ExtraGeneratorName;
-
-  return request.Reply(obj);
-}
-
-static void setBool(const cmServerRequest& request, const std::string& key,
-                    std::function<void(bool)> const& setter)
-{
-  if (request.Data[key].isNull()) {
-    return;
-  }
-  setter(request.Data[key].asBool());
-}
-
-cmServerResponse cmServerProtocol1::ProcessSetGlobalSettings(
-  const cmServerRequest& request)
-{
-  const std::vector<std::string> boolValues = {
-    kDEBUG_OUTPUT_KEY,       kTRACE_KEY,       kTRACE_EXPAND_KEY,
-    kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY,
-    kCHECK_SYSTEM_VARS_KEY
-  };
-  for (std::string const& i : boolValues) {
-    if (!request.Data[i].isNull() && !request.Data[i].isBool()) {
-      return request.ReportError("\"" + i +
-                                 "\" must be unset or a bool value.");
-    }
-  }
-
-  cmake* cm = this->CMakeInstance();
-
-  setBool(request, kDEBUG_OUTPUT_KEY,
-          [cm](bool e) { cm->SetDebugOutputOn(e); });
-  setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); });
-  setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); });
-  setBool(request, kWARN_UNINITIALIZED_KEY,
-          [cm](bool e) { cm->SetWarnUninitialized(e); });
-  setBool(request, kWARN_UNUSED_KEY, [this](bool e) { m_WarnUnused = e; });
-  setBool(request, kWARN_UNUSED_CLI_KEY,
-          [cm](bool e) { cm->SetWarnUnusedCli(e); });
-  setBool(request, kCHECK_SYSTEM_VARS_KEY,
-          [cm](bool e) { cm->SetCheckSystemVars(e); });
-
-  return request.Reply(Json::Value());
-}
-
-cmServerResponse cmServerProtocol1::ProcessFileSystemWatchers(
-  const cmServerRequest& request)
-{
-  const cmFileMonitor* const fm = FileMonitor();
-  Json::Value result = Json::objectValue;
-  Json::Value files = Json::arrayValue;
-  for (auto const& f : fm->WatchedFiles()) {
-    files.append(f);
-  }
-  Json::Value directories = Json::arrayValue;
-  for (auto const& d : fm->WatchedDirectories()) {
-    directories.append(d);
-  }
-  result[kWATCHED_FILES_KEY] = files;
-  result[kWATCHED_DIRECTORIES_KEY] = directories;
-
-  return request.Reply(result);
-}
-
-cmServerResponse cmServerProtocol1::ProcessCTests(
-  const cmServerRequest& request)
-{
-  if (this->m_State < STATE_COMPUTED) {
-    return request.ReportError("This instance was not yet computed.");
-  }
-
-  return request.Reply(cmDumpCTestInfo(this->CMakeInstance()));
-}
-
-cmServerProtocol1::GeneratorInformation::GeneratorInformation(
-  std::string generatorName, std::string extraGeneratorName,
-  std::string toolset, std::string platform, std::string sourceDirectory,
-  std::string buildDirectory)
-  : GeneratorName(std::move(generatorName))
-  , ExtraGeneratorName(std::move(extraGeneratorName))
-  , Toolset(std::move(toolset))
-  , Platform(std::move(platform))
-  , SourceDirectory(std::move(sourceDirectory))
-  , BuildDirectory(std::move(buildDirectory))
-{
-}
-
-void cmServerProtocol1::GeneratorInformation::SetupGenerator(
-  cmake* cm, std::string* errorMessage)
-{
-  const std::string fullGeneratorName =
-    cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
-      GeneratorName, ExtraGeneratorName);
-
-  cm->SetHomeDirectory(SourceDirectory);
-  cm->SetHomeOutputDirectory(BuildDirectory);
-
-  auto gg = cm->CreateGlobalGenerator(fullGeneratorName);
-  if (!gg) {
-    setErrorMessage(
-      errorMessage,
-      std::string("Could not set up the requested combination of \"") +
-        kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\"");
-    return;
-  }
-
-  cm->SetGlobalGenerator(std::move(gg));
-
-  cm->SetGeneratorToolset(Toolset);
-  cm->SetGeneratorPlatform(Platform);
-}
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
deleted file mode 100644 (file)
index 6009e23..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <cm3p/json/value.h>
-
-#include "cmake.h"
-
-class cmConnection;
-class cmFileMonitor;
-class cmServer;
-class cmServerRequest;
-
-class cmServerResponse
-{
-public:
-  explicit cmServerResponse(const cmServerRequest& request);
-
-  void SetData(const Json::Value& data);
-  void SetError(const std::string& message);
-
-  bool IsComplete() const;
-  bool IsError() const;
-  std::string ErrorMessage() const;
-  Json::Value Data() const;
-
-  const std::string Type;
-  const std::string Cookie;
-
-private:
-  enum PayLoad
-  {
-    PAYLOAD_UNKNOWN,
-    PAYLOAD_ERROR,
-    PAYLOAD_DATA
-  };
-  PayLoad m_Payload = PAYLOAD_UNKNOWN;
-  std::string m_ErrorMessage;
-  Json::Value m_Data;
-};
-
-class cmServerRequest
-{
-public:
-  cmServerResponse Reply(const Json::Value& data) const;
-  cmServerResponse ReportError(const std::string& message) const;
-
-  const std::string Type;
-  const std::string Cookie;
-  const Json::Value Data;
-  cmConnection* Connection;
-
-private:
-  cmServerRequest(cmServer* server, cmConnection* connection, std::string t,
-                  std::string c, Json::Value d);
-
-  void ReportProgress(int min, int current, int max,
-                      const std::string& message) const;
-  void ReportMessage(const std::string& message,
-                     const std::string& title) const;
-
-  cmServer* m_Server;
-
-  friend class cmServer;
-};
-
-class cmServerProtocol
-{
-public:
-  cmServerProtocol() = default;
-  virtual ~cmServerProtocol() = default;
-
-  cmServerProtocol(cmServerProtocol const&) = delete;
-  cmServerProtocol& operator=(cmServerProtocol const&) = delete;
-
-  virtual std::pair<int, int> ProtocolVersion() const = 0;
-  virtual bool IsExperimental() const = 0;
-  virtual cmServerResponse Process(const cmServerRequest& request) = 0;
-
-  bool Activate(cmServer* server, const cmServerRequest& request,
-                std::string* errorMessage);
-
-  cmFileMonitor* FileMonitor() const;
-  void SendSignal(const std::string& name, const Json::Value& data) const;
-
-protected:
-  cmake* CMakeInstance() const;
-  // Implement protocol specific activation tasks here. Called from Activate().
-  virtual bool DoActivate(const cmServerRequest& request,
-                          std::string* errorMessage);
-  bool m_WarnUnused = false; // storage for legacy option
-
-private:
-  std::unique_ptr<cmake> m_CMakeInstance;
-  cmServer* m_Server = nullptr; // not owned!
-
-  friend class cmServer;
-};
-
-class cmServerProtocol1 : public cmServerProtocol
-{
-public:
-  std::pair<int, int> ProtocolVersion() const override;
-  bool IsExperimental() const override;
-  cmServerResponse Process(const cmServerRequest& request) override;
-
-private:
-  bool DoActivate(const cmServerRequest& request,
-                  std::string* errorMessage) override;
-
-  void HandleCMakeFileChanges(const std::string& path, int event, int status);
-
-  // Handle requests:
-  cmServerResponse ProcessCache(const cmServerRequest& request);
-  cmServerResponse ProcessCMakeInputs(const cmServerRequest& request);
-  cmServerResponse ProcessCodeModel(const cmServerRequest& request);
-  cmServerResponse ProcessCompute(const cmServerRequest& request);
-  cmServerResponse ProcessConfigure(const cmServerRequest& request);
-  cmServerResponse ProcessGlobalSettings(const cmServerRequest& request);
-  cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request);
-  cmServerResponse ProcessFileSystemWatchers(const cmServerRequest& request);
-  cmServerResponse ProcessCTests(const cmServerRequest& request);
-
-  enum State
-  {
-    STATE_INACTIVE,
-    STATE_ACTIVE,
-    STATE_CONFIGURED,
-    STATE_COMPUTED
-  };
-  State m_State = STATE_INACTIVE;
-
-  bool m_isDirty = false;
-
-  struct GeneratorInformation
-  {
-  public:
-    GeneratorInformation() = default;
-    GeneratorInformation(std::string generatorName,
-                         std::string extraGeneratorName, std::string toolset,
-                         std::string platform, std::string sourceDirectory,
-                         std::string buildDirectory);
-
-    void SetupGenerator(cmake* cm, std::string* errorMessage);
-
-    std::string GeneratorName;
-    std::string ExtraGeneratorName;
-    std::string Toolset;
-    std::string Platform;
-
-    std::string SourceDirectory;
-    std::string BuildDirectory;
-  };
-
-  GeneratorInformation GeneratorInfo;
-};
index df6a38a..c899053 100644 (file)
 #include "cmGlobalGenerator.h"
 #include "cmInstalledFile.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmProperty.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
+#include "cmSourceFileLocation.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -157,7 +160,7 @@ bool HandleSourceFileDirectoryScopeValidation(
   return true;
 }
 
-bool HandleAndValidateSourceFileDirectortoryScopes(
+bool HandleAndValidateSourceFileDirectoryScopes(
   cmExecutionStatus& status, bool source_file_directory_option_enabled,
   bool source_file_target_option_enabled,
   std::vector<std::string>& source_file_directories,
@@ -186,7 +189,7 @@ std::string MakeSourceFilePathAbsoluteIfNeeded(
   if (!needed) {
     return source_file_path;
   }
-  const std::string absolute_file_path = cmSystemTools::CollapseFullPath(
+  std::string absolute_file_path = cmSystemTools::CollapseFullPath(
     source_file_path, status.GetMakefile().GetCurrentSourceDirectory());
   return absolute_file_path;
 }
@@ -216,8 +219,92 @@ void MakeSourceFilePathsAbsoluteIfNeeded(
     source_files_absolute_paths.push_back(absolute_file_path);
   }
 }
+
+bool HandleAndValidateSourceFilePropertyGENERATED(
+  cmSourceFile* sf, std::string const& propertyValue, PropertyOp op)
+{
+  const auto& mf = *sf->GetLocation().GetMakefile();
+  auto policyStatus = mf.GetPolicyStatus(cmPolicies::CMP0118);
+
+  const bool policyWARN = policyStatus == cmPolicies::WARN;
+  const bool policyNEW = policyStatus != cmPolicies::OLD && !policyWARN;
+
+  if (policyWARN) {
+    if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
+      mf.IssueMessage(
+        MessageType::AUTHOR_WARNING,
+        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
+                 "\nAttempt to set property 'GENERATED' with the following "
+                 "non-boolean value (which will be interpreted as \"0\"):\n",
+                 propertyValue,
+                 "\nThat exact value will not be retrievable. A value of "
+                 "\"0\" will be returned instead.\n"
+                 "This will be an error under policy CMP0118.\n"));
+    }
+    if (cmIsOff(propertyValue)) {
+      mf.IssueMessage(
+        MessageType::AUTHOR_WARNING,
+        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
+                 "\nUnsetting property 'GENERATED' will not be allowed under "
+                 "policy CMP0118!\n"));
+    }
+    if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
+      mf.IssueMessage(
+        MessageType::AUTHOR_WARNING,
+        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118),
+                 "\nAppending to property 'GENERATED' will not be allowed "
+                 "under policy CMP0118!\n"));
+    }
+  } else if (policyNEW) {
+    if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
+      mf.IssueMessage(
+        MessageType::AUTHOR_ERROR,
+        cmStrCat(
+          "Policy CMP0118 is set to NEW and the following non-boolean value "
+          "given for property 'GENERATED' is therefore not allowed:\n",
+          propertyValue, "\nReplace it with a boolean value!\n"));
+      return true;
+    }
+    if (cmIsOff(propertyValue)) {
+      mf.IssueMessage(
+        MessageType::AUTHOR_ERROR,
+        "Unsetting the 'GENERATED' property is not allowed under CMP0118!\n");
+      return true;
+    }
+    if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) {
+      mf.IssueMessage(MessageType::AUTHOR_ERROR,
+                      "Policy CMP0118 is set to NEW and appending to the "
+                      "'GENERATED' property is therefore not allowed. Only "
+                      "setting it to \"1\" is allowed!\n");
+      return true;
+    }
+  }
+
+  // Set property.
+  if (!policyNEW) {
+    // Do it the traditional way.
+    switch (op) {
+      case PropertyOp::Append:
+        sf->AppendProperty("GENERATED", propertyValue, false);
+        break;
+      case PropertyOp::AppendAsString:
+        sf->AppendProperty("GENERATED", propertyValue, true);
+        break;
+      case PropertyOp::Remove:
+        sf->SetProperty("GENERATED", nullptr);
+        break;
+      case PropertyOp::Set:
+        sf->SetProperty("GENERATED", propertyValue.c_str());
+        break;
+    }
+  } else {
+    sf->MarkAsGenerated();
+  }
+  return true;
 }
 
+} // END: namespace SetPropertyCommand
+
 bool cmSetPropertyCommand(std::vector<std::string> const& args,
                           cmExecutionStatus& status)
 {
@@ -324,7 +411,7 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args,
 
   std::vector<cmMakefile*> source_file_directory_makefiles;
   bool file_scopes_handled =
-    SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
+    SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
       status, source_file_directory_option_enabled,
       source_file_target_option_enabled, source_file_directories,
       source_file_target_directories, source_file_directory_makefiles);
@@ -367,7 +454,7 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args,
   return true;
 }
 
-namespace {
+namespace /* anonymous */ {
 bool HandleGlobalMode(cmExecutionStatus& status,
                       const std::set<std::string>& names,
                       const std::string& propertyName,
@@ -502,7 +589,7 @@ bool HandleSourceMode(cmExecutionStatus& status,
     status, files_absolute, unique_files.begin(), unique_files.end(),
     source_file_paths_should_be_absolute);
 
-  for (const auto mf : directory_makefiles) {
+  for (auto* const mf : directory_makefiles) {
     for (std::string const& name : files_absolute) {
       // Get the source file.
       if (cmSourceFile* sf = mf->GetOrCreateSource(name)) {
@@ -525,6 +612,18 @@ bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
                   const std::string& propertyValue, bool appendAsString,
                   bool appendMode, bool remove)
 {
+  // Special validation and handling of GENERATED flag?
+  if (propertyName == "GENERATED") {
+    SetPropertyCommand::PropertyOp op = (remove)
+      ? SetPropertyCommand::PropertyOp::Remove
+      : (appendAsString)
+        ? SetPropertyCommand::PropertyOp::AppendAsString
+        : (appendMode) ? SetPropertyCommand::PropertyOp::Append
+                       : SetPropertyCommand::PropertyOp::Set;
+    return SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
+      sf, propertyValue, op);
+  }
+
   // Set or append the property.
   if (appendMode) {
     sf->AppendProperty(propertyName, propertyValue, appendAsString);
index 89fdd9a..05c4873 100644 (file)
@@ -9,6 +9,7 @@
 
 class cmMakefile;
 class cmExecutionStatus;
+class cmSourceFile;
 
 bool cmSetPropertyCommand(std::vector<std::string> const& args,
                           cmExecutionStatus& status);
@@ -25,7 +26,7 @@ bool HandleSourceFileDirectoryScopeValidation(
   std::vector<std::string>& source_file_directories,
   std::vector<std::string>& source_file_target_directories);
 
-bool HandleAndValidateSourceFileDirectortoryScopes(
+bool HandleAndValidateSourceFileDirectoryScopes(
   cmExecutionStatus& status, bool source_directories_option_encountered,
   bool source_target_directories_option_encountered,
   std::vector<std::string>& source_directories,
@@ -39,4 +40,16 @@ void MakeSourceFilePathsAbsoluteIfNeeded(
   std::vector<std::string>& source_files_absolute_paths,
   std::vector<std::string>::const_iterator files_it_begin,
   std::vector<std::string>::const_iterator files_it_end, bool needed);
+
+enum class PropertyOp
+{
+  Remove,
+  Set,
+  Append,
+  AppendAsString
+};
+
+bool HandleAndValidateSourceFilePropertyGENERATED(
+  cmSourceFile* sf, std::string const& propertyValue,
+  PropertyOp op = PropertyOp::Set);
 }
index c1b0c28..237b67f 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <cm/string_view>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
@@ -82,7 +83,7 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
   const auto props_begin = options_it;
 
   bool file_scopes_handled =
-    SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes(
+    SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
       status, source_file_directory_option_enabled,
       source_file_target_option_enabled, source_file_directories,
       source_file_target_directories, source_file_directory_makefiles);
@@ -100,7 +101,7 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args,
   // Now call the worker function for each directory scope represented by a
   // cmMakefile instance.
   std::string errors;
-  for (const auto mf : source_file_directory_makefiles) {
+  for (auto* const mf : source_file_directory_makefiles) {
     bool ret = RunCommandForScope(mf, files.begin(), files.end(), props_begin,
                                   args.end(), errors);
     if (!ret) {
@@ -167,7 +168,13 @@ static bool RunCommandForScope(
     if (cmSourceFile* sf = mf->GetOrCreateSource(sfname)) {
       // loop through the props and set them
       for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) {
-        sf->SetProperty(*k, (k + 1)->c_str());
+        // Special handling for GENERATED property?
+        if (*k == "GENERATED"_s) {
+          SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
+            sf, *(k + 1));
+        } else {
+          sf->SetProperty(*k, (k + 1)->c_str());
+        }
       }
     }
   }
index ef44a57..3f3c8d5 100644 (file)
@@ -8,6 +8,7 @@
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmake.h"
 
 cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name,
-                           cmSourceFileLocationKind kind)
-  : Location(mf, name, kind)
+                           bool generated, cmSourceFileLocationKind kind)
+  : Location(mf, name, (!generated) ? kind : cmSourceFileLocationKind::Known)
 {
+  if (generated) {
+    this->MarkAsGenerated();
+  }
 }
 
 std::string const& cmSourceFile::GetExtension() const
@@ -25,6 +29,8 @@ std::string const& cmSourceFile::GetExtension() const
   return this->Extension;
 }
 
+const std::string propTRUE = "1";
+const std::string propFALSE = "0";
 const std::string cmSourceFile::propLANGUAGE = "LANGUAGE";
 const std::string cmSourceFile::propLOCATION = "LOCATION";
 const std::string cmSourceFile::propGENERATED = "GENERATED";
@@ -54,16 +60,14 @@ std::string const& cmSourceFile::GetOrDetermineLanguage()
   }
 
   // Perform computation needed to get the language if necessary.
-  if (this->FullPath.empty() && this->Language.empty()) {
-    // If a known extension is given or a known full path is given
-    // then trust that the current extension is sufficient to
-    // determine the language.  This will fail only if the user
-    // specifies a full path to the source but leaves off the
-    // extension, which is kind of weird.
-    if (this->Location.ExtensionIsAmbiguous() &&
+  if (this->Language.empty()) {
+    // If a known extension is given or a known full path is given then trust
+    // that the current extension is sufficient to determine the language. This
+    // will fail only if the user specifies a full path to the source but
+    // leaves off the extension, which is kind of weird.
+    if (this->FullPath.empty() && this->Location.ExtensionIsAmbiguous() &&
         this->Location.DirectoryIsAmbiguous()) {
-      // Finalize the file location to get the extension and set the
-      // language.
+      // Finalize the file location to get the extension and set the language.
       this->ResolveFullPath();
     } else {
       // Use the known extension to get the language if possible.
@@ -93,10 +97,11 @@ cmSourceFileLocation const& cmSourceFile::GetLocation() const
   return this->Location;
 }
 
-std::string const& cmSourceFile::ResolveFullPath(std::string* error)
+std::string const& cmSourceFile::ResolveFullPath(std::string* error,
+                                                 std::string* cmp0115Warning)
 {
   if (this->FullPath.empty()) {
-    if (this->FindFullPath(error)) {
+    if (this->FindFullPath(error, cmp0115Warning)) {
       this->CheckExtension();
     }
   }
@@ -108,14 +113,18 @@ std::string const& cmSourceFile::GetFullPath() const
   return this->FullPath;
 }
 
-bool cmSourceFile::FindFullPath(std::string* error)
+bool cmSourceFile::FindFullPath(std::string* error,
+                                std::string* cmp0115Warning)
 {
   // If the file is generated compute the location without checking on disk.
-  if (this->GetIsGenerated()) {
+  // Note: We also check for a locally set GENERATED property, because
+  //       it might have been set before policy CMP0118 was set to NEW.
+  if (this->GetIsGenerated(CheckScope::GlobalAndLocal)) {
     // The file is either already a full path or is relative to the
     // build directory for the target.
     this->Location.DirectoryUseBinary();
     this->FullPath = this->Location.GetFullPath();
+    this->FindFullPathFailed = false;
     return true;
   }
 
@@ -131,23 +140,52 @@ bool cmSourceFile::FindFullPath(std::string* error)
   // List of extension lists
   std::vector<std::string> exts =
     makefile->GetCMakeInstance()->GetAllExtensions();
+  auto cmp0115 = makefile->GetPolicyStatus(cmPolicies::CMP0115);
+  auto cmp0118 = makefile->GetPolicyStatus(cmPolicies::CMP0118);
+  bool const cmp0118new =
+    cmp0118 != cmPolicies::OLD && cmp0118 != cmPolicies::WARN;
 
   // Tries to find the file in a given directory
-  auto findInDir = [this, &exts, &lPath](std::string const& dir) -> bool {
+  auto findInDir = [this, &exts, &lPath, cmp0115, cmp0115Warning, cmp0118new,
+                    makefile](std::string const& dir) -> bool {
     // Compute full path
     std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir);
     // Try full path
-    if (cmSystemTools::FileExists(fullPath)) {
+    if (cmp0118new &&
+        makefile->GetGlobalGenerator()->IsGeneratedFile(fullPath)) {
+      this->IsGenerated = true;
+    }
+    if (this->IsGenerated || cmSystemTools::FileExists(fullPath)) {
       this->FullPath = fullPath;
       return true;
     }
-    // Try full path with extension
-    for (std::string const& ext : exts) {
-      if (!ext.empty()) {
-        std::string extPath = cmStrCat(fullPath, '.', ext);
-        if (cmSystemTools::FileExists(extPath)) {
-          this->FullPath = extPath;
-          return true;
+    // This has to be an if statement due to a bug in Oracle Developer Studio.
+    // See https://community.oracle.com/tech/developers/discussion/4476246/
+    // for details.
+    if (cmp0115 == cmPolicies::OLD || cmp0115 == cmPolicies::WARN) {
+      // Try full path with extension
+      for (std::string const& ext : exts) {
+        if (!ext.empty()) {
+          std::string extPath = cmStrCat(fullPath, '.', ext);
+          if (cmp0118new &&
+              makefile->GetGlobalGenerator()->IsGeneratedFile(extPath)) {
+            this->IsGenerated = true;
+          }
+          if (this->IsGenerated || cmSystemTools::FileExists(extPath)) {
+            this->FullPath = extPath;
+            if (cmp0115 == cmPolicies::WARN) {
+              std::string warning =
+                cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0115),
+                         "\nFile:\n  ", extPath);
+              if (cmp0115Warning) {
+                *cmp0115Warning = std::move(warning);
+              } else {
+                makefile->GetCMakeInstance()->IssueMessage(
+                  MessageType::AUTHOR_WARNING, warning);
+              }
+            }
+            return true;
+          }
         }
       }
     }
@@ -168,11 +206,19 @@ bool cmSourceFile::FindFullPath(std::string* error)
   }
 
   // Compose error
-  std::string err =
-    cmStrCat("Cannot find source file:\n  ", lPath, "\nTried extensions");
-  for (std::string const& ext : exts) {
-    err += " .";
-    err += ext;
+  std::string err = cmStrCat("Cannot find source file:\n  ", lPath);
+  switch (cmp0115) {
+    case cmPolicies::OLD:
+    case cmPolicies::WARN:
+      err = cmStrCat(err, "\nTried extensions");
+      for (auto const& ext : exts) {
+        err = cmStrCat(err, " .", ext);
+      }
+      break;
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::NEW:
+      break;
   }
   if (error != nullptr) {
     *error = std::move(err);
@@ -246,11 +292,6 @@ void cmSourceFile::SetProperty(const std::string& prop, const char* value)
   } else {
     this->Properties.SetProperty(prop, value);
   }
-
-  // Update IsGenerated flag
-  if (prop == propGENERATED) {
-    this->IsGenerated = cmIsOn(value);
-  }
 }
 
 void cmSourceFile::AppendProperty(const std::string& prop,
@@ -274,14 +315,9 @@ void cmSourceFile::AppendProperty(const std::string& prop,
   } else {
     this->Properties.AppendProperty(prop, value, asString);
   }
-
-  // Update IsGenerated flag
-  if (prop == propGENERATED) {
-    this->IsGenerated = this->GetPropertyAsBool(propGENERATED);
-  }
 }
 
-const char* cmSourceFile::GetPropertyForUser(const std::string& prop)
+cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
 {
   // This method is a consequence of design history and backwards
   // compatibility.  GetProperty is (and should be) a const method.
@@ -305,13 +341,27 @@ const char* cmSourceFile::GetPropertyForUser(const std::string& prop)
   // Similarly, LANGUAGE can be determined by the file extension
   // if it is requested by the user.
   if (prop == propLANGUAGE) {
-    // The c_str pointer is valid until `this->Language` is modified.
-    return this->GetOrDetermineLanguage().c_str();
+    // The pointer is valid until `this->Language` is modified.
+    return &this->GetOrDetermineLanguage();
+  }
+
+  // Special handling for GENERATED property.
+  if (prop == propGENERATED) {
+    // We need to check policy CMP0118 in order to determine if we need to
+    // possibly consider the value of a locally set GENERATED property, too.
+    auto policyStatus =
+      this->Location.GetMakefile()->GetPolicyStatus(cmPolicies::CMP0118);
+    if (this->GetIsGenerated(
+          (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD)
+            ? CheckScope::GlobalAndLocal
+            : CheckScope::Global)) {
+      return &propTRUE;
+    }
+    return &propFALSE;
   }
 
   // Perform the normal property lookup.
-  cmProp p = this->GetProperty(prop);
-  return p ? p->c_str() : nullptr;
+  return this->GetProperty(prop);
 }
 
 cmProp cmSourceFile::GetProperty(const std::string& prop) const
@@ -369,13 +419,15 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
   return retVal;
 }
 
-const char* cmSourceFile::GetSafeProperty(const std::string& prop) const
+const std::string& cmSourceFile::GetSafeProperty(const std::string& prop) const
 {
   cmProp ret = this->GetProperty(prop);
-  if (!ret) {
-    return "";
+  if (ret) {
+    return *ret;
   }
-  return ret->c_str();
+
+  static std::string const s_empty;
+  return s_empty;
 }
 
 bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
@@ -383,11 +435,29 @@ bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
   return cmIsOn(this->GetProperty(prop));
 }
 
+void cmSourceFile::MarkAsGenerated()
+{
+  this->IsGenerated = true;
+  const auto& mf = *this->Location.GetMakefile();
+  mf.GetGlobalGenerator()->MarkAsGeneratedFile(this->ResolveFullPath());
+}
+
+bool cmSourceFile::GetIsGenerated(CheckScope checkScope) const
+{
+  if (this->IsGenerated) {
+    // Globally marked as generated!
+    return true;
+  }
+  if (checkScope == CheckScope::GlobalAndLocal) {
+    // Check locally stored properties.
+    return this->GetPropertyAsBool(propGENERATED);
+  }
+  return false;
+}
+
 void cmSourceFile::SetProperties(cmPropertyMap properties)
 {
   this->Properties = std::move(properties);
-
-  this->IsGenerated = this->GetPropertyAsBool(propGENERATED);
 }
 
 cmCustomCommand* cmSourceFile::GetCustomCommand() const
index 39ea8e3..76a5ded 100644 (file)
@@ -20,18 +20,18 @@ class cmMakefile;
 /** \class cmSourceFile
  * \brief Represent a class loaded from a makefile.
  *
- * cmSourceFile is represents a class loaded from
- * a makefile.
+ * cmSourceFile represents a class loaded from a makefile.
  */
 class cmSourceFile
 {
 public:
   /**
-   * Construct with the makefile storing the source and the initial
-   * name referencing it.
+   * Construct with the makefile storing the source and the initial name
+   * referencing it. If it shall be marked as generated, this source file's
+   * kind is assumed to be known, regardless of the given value.
    */
   cmSourceFile(
-    cmMakefile* mf, const std::string& name,
+    cmMakefile* mf, const std::string& name, bool generated,
     cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous);
 
   /**
@@ -47,16 +47,36 @@ public:
   //! Might return a nullptr if the property is not set or invalid
   cmProp GetProperty(const std::string& prop) const;
   //! Always returns a valid pointer
-  const char* GetSafeProperty(const std::string& prop) const;
+  const std::string& GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
 
   /** Implement getting a property when called from a CMake language
       command like get_property or get_source_file_property.  */
-  const char* GetPropertyForUser(const std::string& prop);
+  cmProp GetPropertyForUser(const std::string& prop);
 
-  //! Checks is the GENERATED property is set and true
-  /// @return Equivalent to GetPropertyAsBool("GENERATED")
-  bool GetIsGenerated() const { return this->IsGenerated; }
+  /// Marks this file as generated
+  /**
+   * This stores this file's path in the global table for all generated source
+   * files.
+   */
+  void MarkAsGenerated();
+  enum class CheckScope
+  {
+    Global,
+    GlobalAndLocal
+  };
+  /// Determines if this source file is marked as generated.
+  /**
+   * This will check if this file's path is stored in the global table of all
+   * generated source files. If that is not the case and checkScope is set to
+   * GlobalAndLocal the value of the possibly existing local GENERATED property
+   * is returned instead.
+   * @param checkScope Determines if alternatively for backwards-compatibility
+   * a local GENERATED property should be considered, too.
+   * @return true if this source file is marked as generated, otherwise false.
+   */
+  bool GetIsGenerated(
+    CheckScope checkScope = CheckScope::GlobalAndLocal) const;
 
   const std::vector<BT<std::string>>& GetCompileOptions() const
   {
@@ -77,7 +97,8 @@ public:
    * Resolves the full path to the file.  Attempts to locate the file on disk
    * and finalizes its location.
    */
-  std::string const& ResolveFullPath(std::string* error = nullptr);
+  std::string const& ResolveFullPath(std::string* error = nullptr,
+                                     std::string* cmp0115Warning = nullptr);
 
   /**
    * The resolved full path to the file.  The returned file name might be empty
@@ -138,7 +159,7 @@ private:
   bool FindFullPathFailed = false;
   bool IsGenerated = false;
 
-  bool FindFullPath(std::string* error);
+  bool FindFullPath(std::string* error, std::string* cmp0115Warning);
   void CheckExtension();
   void CheckLanguage(std::string const& ext);
 
@@ -154,7 +175,7 @@ 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|cxx|cu|f|f90|for|fpp|ftn|m|mm|"                 \
+  "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|"             \
   "rc|def|r|odl|idl|hpj|bat)$"
 
 #define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$"
index 222bafa..8c7154d 100644 (file)
@@ -33,8 +33,7 @@ cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf,
   this->AmbiguousExtension = true;
   this->Directory = cmSystemTools::GetFilenamePath(name);
   if (cmSystemTools::FileIsFullPath(this->Directory)) {
-    this->Directory = cmSystemTools::CollapseFullPath(
-      this->Directory, mf->GetHomeOutputDirectory());
+    this->Directory = cmSystemTools::CollapseFullPath(this->Directory);
   }
   this->Name = cmSystemTools::GetFilenameName(name);
   if (kind == cmSourceFileLocationKind::Known) {
@@ -99,7 +98,7 @@ void cmSourceFileLocation::UpdateExtension(const std::string& name)
   // The global generator checks extensions of enabled languages.
   cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
   cmMakefile const* mf = this->Makefile;
-  auto cm = mf->GetCMakeInstance();
+  auto* cm = mf->GetCMakeInstance();
   if (!gg->GetLanguageFromExtension(ext.c_str()).empty() ||
       cm->IsAKnownExtension(ext)) {
     // This is a known extension.  Use the given filename with extension.
@@ -156,7 +155,7 @@ bool cmSourceFileLocation::MatchesAmbiguousExtension(
   // disk.  One of these must match if loc refers to this source file.
   auto ext = cm::string_view(this->Name).substr(loc.Name.size() + 1);
   cmMakefile const* mf = this->Makefile;
-  auto cm = mf->GetCMakeInstance();
+  auto* cm = mf->GetCMakeInstance();
   return cm->IsAKnownExtension(ext);
 }
 
index 8672f61..bf6925e 100644 (file)
@@ -44,6 +44,16 @@ struct StandardNeeded
   int value;
 };
 
+int ParseStd(std::string const& level)
+{
+  try {
+    return std::stoi(level);
+  } catch (std::invalid_argument&) {
+    // Fall through to use an invalid value.
+  }
+  return -1;
+}
+
 struct StanardLevelComputer
 {
   explicit StanardLevelComputer(std::string lang, std::vector<int> levels,
@@ -113,17 +123,8 @@ struct StanardLevelComputer
       standardStr = "03";
     }
 
-    int standardValue = -1;
-    int defaultValue = -1;
-    try {
-      standardValue = std::stoi(standardStr);
-      defaultValue = std::stoi(*defaultStd);
-    } catch (std::invalid_argument&) {
-      // fall through as we want an error
-      // when we can't find the bad value in the `stds` vector
-    }
-
-    auto stdIt = std::find(cm::cbegin(stds), cm::cend(stds), standardValue);
+    auto stdIt =
+      std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(standardStr));
     if (stdIt == cm::cend(stds)) {
       std::string e =
         cmStrCat(this->Language, "_STANDARD is set to invalid value '",
@@ -134,7 +135,7 @@ struct StanardLevelComputer
     }
 
     auto defaultStdIt =
-      std::find(cm::cbegin(stds), cm::cend(stds), defaultValue);
+      std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(*defaultStd));
     if (defaultStdIt == cm::cend(stds)) {
       std::string e = cmStrCat("CMAKE_", this->Language,
                                "_STANDARD_DEFAULT is set to invalid value '",
@@ -195,7 +196,7 @@ struct StanardLevelComputer
     if (existingStandard) {
       existingLevelIter =
         std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
-                  std::stoi(*existingStandard));
+                  ParseStd(*existingStandard));
       if (existingLevelIter == cm::cend(this->Levels)) {
         const std::string e =
           cmStrCat("The ", this->Language, "_STANDARD property on target \"",
@@ -240,7 +241,7 @@ struct StanardLevelComputer
     }
     // convert defaultStandard to an integer
     if (std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
-                  std::stoi(*defaultStandard)) == cm::cend(this->Levels)) {
+                  ParseStd(*defaultStandard)) == cm::cend(this->Levels)) {
       const std::string e = cmStrCat("The CMAKE_", this->Language,
                                      "_STANDARD_DEFAULT variable contains an "
                                      "invalid value: \"",
@@ -257,7 +258,7 @@ struct StanardLevelComputer
 
     auto existingLevelIter =
       std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
-                std::stoi(*existingStandard));
+                ParseStd(*existingStandard));
     if (existingLevelIter == cm::cend(this->Levels)) {
       const std::string e =
         cmStrCat("The ", this->Language, "_STANDARD property on target \"",
@@ -311,19 +312,19 @@ std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping =
                             std::vector<std::string>{ "90", "99", "11" } } },
     { "CXX",
       StanardLevelComputer{
-        "CXX", std::vector<int>{ 98, 11, 14, 17, 20 },
-        std::vector<std::string>{ "98", "11", "14", "17", "20" } } },
+        "CXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
+        std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
     { "CUDA",
       StanardLevelComputer{
-        "CUDA", std::vector<int>{ 03, 11, 14, 17, 20 },
-        std::vector<std::string>{ "03", "11", "14", "17", "20" } } },
+        "CUDA", std::vector<int>{ 03, 11, 14, 17, 20, 23 },
+        std::vector<std::string>{ "03", "11", "14", "17", "20", "23" } } },
     { "OBJC",
       StanardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11 },
                             std::vector<std::string>{ "90", "99", "11" } } },
     { "OBJCXX",
       StanardLevelComputer{
-        "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20 },
-        std::vector<std::string>{ "98", "11", "14", "17", "20" } } },
+        "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
+        std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } },
   };
 }
 
index 64c1645..1da8c98 100644 (file)
@@ -4,18 +4,22 @@
 
 #if defined(__linux)
 /* Needed for glibc < 2.12 */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _XOPEN_SOURCE 600
 #endif
 #if !defined(_POSIX_C_SOURCE) && !defined(_WIN32) && !defined(__sun)
 /* POSIX APIs are needed */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _POSIX_C_SOURCE 200809L
 #endif
 #if defined(__sun) && defined(__GNUC__) && !defined(__cplusplus)
 /* C sources: for fileno and strdup */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _XOPEN_SOURCE 600
 #endif
 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
 /* For isascii */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _XOPEN_SOURCE 700
 #endif
 
index d268e62..d97762b 100644 (file)
@@ -110,12 +110,9 @@ bool cmState::StringToCacheEntryType(const std::string& s,
 
 bool cmState::IsCacheEntryType(std::string const& key)
 {
-  for (const std::string& i : cmCacheEntryTypes) {
-    if (key == i) {
-      return true;
-    }
-  }
-  return false;
+  return std::any_of(
+    cmCacheEntryTypes.begin(), cmCacheEntryTypes.end(),
+    [&key](std::string const& i) -> bool { return key == i; });
 }
 
 bool cmState::LoadCache(const std::string& path, bool internal,
@@ -347,7 +344,7 @@ cmPropertyDefinition const* cmState::GetPropertyDefinition(
 bool cmState::IsPropertyChained(const std::string& name,
                                 cmProperty::ScopeType scope) const
 {
-  if (auto def = this->GetPropertyDefinition(name, scope)) {
+  if (const auto* def = this->GetPropertyDefinition(name, scope)) {
     return def->IsChained();
   }
   return false;
@@ -441,6 +438,19 @@ void cmState::AddBuiltinCommand(std::string const& name,
     });
 }
 
+void cmState::AddFlowControlCommand(std::string const& name, Command command)
+{
+  this->FlowControlCommands.insert(name);
+  this->AddBuiltinCommand(name, std::move(command));
+}
+
+void cmState::AddFlowControlCommand(std::string const& name,
+                                    BuiltinCommand command)
+{
+  this->FlowControlCommands.insert(name);
+  this->AddBuiltinCommand(name, command);
+}
+
 void cmState::AddDisallowedCommand(std::string const& name,
                                    BuiltinCommand command,
                                    cmPolicies::PolicyID policy,
@@ -470,7 +480,7 @@ void cmState::AddDisallowedCommand(std::string const& name,
 
 void cmState::AddUnexpectedCommand(std::string const& name, const char* error)
 {
-  this->AddBuiltinCommand(
+  this->AddFlowControlCommand(
     name,
     [name, error](std::vector<cmListFileArgument> const&,
                   cmExecutionStatus& status) -> bool {
@@ -485,21 +495,33 @@ void cmState::AddUnexpectedCommand(std::string const& name, const char* error)
     });
 }
 
-void cmState::AddScriptedCommand(std::string const& name, Command command)
+bool cmState::AddScriptedCommand(std::string const& name, BT<Command> command,
+                                 cmMakefile& mf)
 {
   std::string sName = cmSystemTools::LowerCase(name);
 
+  if (this->FlowControlCommands.count(sName)) {
+    mf.GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("Built-in flow control command \"", sName,
+               "\" cannot be overridden."),
+      command.Backtrace);
+    cmSystemTools::SetFatalErrorOccured();
+    return false;
+  }
+
   // if the command already exists, give a new name to the old command.
   if (Command oldCmd = this->GetCommandByExactName(sName)) {
     this->ScriptedCommands["_" + sName] = oldCmd;
   }
 
-  this->ScriptedCommands[sName] = std::move(command);
+  this->ScriptedCommands[sName] = std::move(command.Value);
+  return true;
 }
 
 cmState::Command cmState::GetCommand(std::string const& name) const
 {
-  return GetCommandByExactName(cmSystemTools::LowerCase(name));
+  return this->GetCommandByExactName(cmSystemTools::LowerCase(name));
 }
 
 cmState::Command cmState::GetCommandByExactName(std::string const& name) const
index e4c9eb5..4e41156 100644 (file)
@@ -9,6 +9,7 @@
 #include <set>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "cmDefinitions.h"
@@ -24,6 +25,7 @@
 class cmCacheManager;
 class cmCommand;
 class cmGlobVerificationManager;
+class cmMakefile;
 class cmStateSnapshot;
 class cmMessenger;
 class cmExecutionStatus;
@@ -159,10 +161,13 @@ public:
                          std::unique_ptr<cmCommand> command);
   void AddBuiltinCommand(std::string const& name, Command command);
   void AddBuiltinCommand(std::string const& name, BuiltinCommand command);
+  void AddFlowControlCommand(std::string const& name, Command command);
+  void AddFlowControlCommand(std::string const& name, BuiltinCommand command);
   void AddDisallowedCommand(std::string const& name, BuiltinCommand command,
                             cmPolicies::PolicyID policy, const char* message);
   void AddUnexpectedCommand(std::string const& name, const char* error);
-  void AddScriptedCommand(std::string const& name, Command command);
+  bool AddScriptedCommand(std::string const& name, BT<Command> command,
+                          cmMakefile& mf);
   void RemoveBuiltinCommand(std::string const& name);
   void RemoveUserDefinedCommands();
   std::vector<std::string> GetCommandNames() const;
@@ -225,6 +230,7 @@ private:
   std::vector<std::string> EnabledLanguages;
   std::unordered_map<std::string, Command> BuiltinCommands;
   std::unordered_map<std::string, Command> ScriptedCommands;
+  std::unordered_set<std::string> FlowControlCommands;
   cmPropertyMap GlobalProperties;
   std::unique_ptr<cmCacheManager> CacheManager;
   std::unique_ptr<cmGlobVerificationManager> GlobVerificationManager;
index 796bb1f..7ce362a 100644 (file)
@@ -148,11 +148,13 @@ bool cmStateDirectory::ContainsBoth(std::string const& local_path,
             cmSystemTools::IsSubDirectory(a, b));
   };
 
-  bool bothInBinary = PathEqOrSubDir(local_path, GetRelativePathTopBinary()) &&
-    PathEqOrSubDir(remote_path, GetRelativePathTopBinary());
+  bool bothInBinary =
+    PathEqOrSubDir(local_path, this->GetRelativePathTopBinary()) &&
+    PathEqOrSubDir(remote_path, this->GetRelativePathTopBinary());
 
-  bool bothInSource = PathEqOrSubDir(local_path, GetRelativePathTopSource()) &&
-    PathEqOrSubDir(remote_path, GetRelativePathTopSource());
+  bool bothInSource =
+    PathEqOrSubDir(local_path, this->GetRelativePathTopSource()) &&
+    PathEqOrSubDir(remote_path, this->GetRelativePathTopSource());
 
   return bothInBinary || bothInSource;
 }
index 56a262d..70c19bc 100644 (file)
@@ -97,7 +97,6 @@ private:
   void ComputeRelativePathTopSource();
   void ComputeRelativePathTopBinary();
 
-private:
   cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator
     DirectoryState;
   cmStateSnapshot Snapshot_;
index 898b828..aefaa64 100644 (file)
@@ -1,5 +1,6 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #define _SCL_SECURE_NO_WARNINGS
 
 #include "cmString.hxx"
@@ -19,17 +20,17 @@ void String::internally_mutate_to_stable_string()
   // We assume that only one thread mutates this instance at
   // a time even if we point to a shared string buffer referenced
   // by other threads.
-  *this = String(data(), size());
+  *this = String(this->data(), this->size());
 }
 
 bool String::is_stable() const
 {
-  return str_if_stable() != nullptr;
+  return this->str_if_stable() != nullptr;
 }
 
 void String::stabilize()
 {
-  if (is_stable()) {
+  if (this->is_stable()) {
     return;
   }
   this->internally_mutate_to_stable_string();
@@ -37,16 +38,17 @@ void String::stabilize()
 
 std::string const* String::str_if_stable() const
 {
-  if (!data()) {
+  if (!this->data()) {
     // We view no string.
     // This is stable for the lifetime of our current value.
     return &empty_string_;
   }
 
-  if (string_ && data() == string_->data() && size() == string_->size()) {
+  if (this->string_ && this->data() == this->string_->data() &&
+      this->size() == this->string_->size()) {
     // We view an entire string.
     // This is stable for the lifetime of our current value.
-    return string_.get();
+    return this->string_.get();
   }
 
   return nullptr;
@@ -54,18 +56,18 @@ std::string const* String::str_if_stable() const
 
 std::string const& String::str()
 {
-  if (std::string const* s = str_if_stable()) {
+  if (std::string const* s = this->str_if_stable()) {
     return *s;
   }
   // Mutate to hold a std::string that is stable for the lifetime
   // of our current value.
   this->internally_mutate_to_stable_string();
-  return *string_;
+  return *this->string_;
 }
 
 const char* String::c_str()
 {
-  const char* c = data();
+  const char* c = this->data();
   if (c == nullptr) {
     return c;
   }
@@ -73,42 +75,42 @@ const char* String::c_str()
   // We always point into a null-terminated string so it is safe to
   // access one past the end.  If it is a null byte then we can use
   // the pointer directly.
-  if (c[size()] == '\0') {
+  if (c[this->size()] == '\0') {
     return c;
   }
 
   // Mutate to hold a std::string so we can get a null terminator.
   this->internally_mutate_to_stable_string();
-  c = string_->c_str();
+  c = this->string_->c_str();
   return c;
 }
 
 String& String::insert(size_type index, size_type count, char ch)
 {
   std::string s;
-  s.reserve(size() + count);
-  s.assign(data(), size());
+  s.reserve(this->size() + count);
+  s.assign(this->data(), this->size());
   s.insert(index, count, ch);
   return *this = std::move(s);
 }
 
 String& String::erase(size_type index, size_type count)
 {
-  if (index > size()) {
+  if (index > this->size()) {
     throw std::out_of_range("Index out of range in String::erase");
   }
-  size_type const rcount = std::min(count, size() - index);
+  size_type const rcount = std::min(count, this->size() - index);
   size_type const rindex = index + rcount;
   std::string s;
-  s.reserve(size() - rcount);
-  s.assign(data(), index);
-  s.append(data() + rindex, size() - rindex);
+  s.reserve(this->size() - rcount);
+  s.assign(this->data(), index);
+  s.append(this->data() + rindex, this->size() - rindex);
   return *this = std::move(s);
 }
 
 String String::substr(size_type pos, size_type count) const
 {
-  if (pos > size()) {
+  if (pos > this->size()) {
     throw std::out_of_range("Index out of range in String::substr");
   }
   return String(*this, pos, count);
@@ -116,14 +118,14 @@ String String::substr(size_type pos, size_type count) const
 
 String::String(std::string&& s, Private)
   : string_(std::make_shared<std::string>(std::move(s)))
-  , view_(string_->data(), string_->size())
+  , view_(this->string_->data(), this->string_->size())
 {
 }
 
 String::size_type String::copy(char* dest, size_type count,
                                size_type pos) const
 {
-  return view_.copy(dest, count, pos);
+  return this->view_.copy(dest, count, pos);
 }
 
 std::ostream& operator<<(std::ostream& os, String const& s)
index b41b960..f1e462b 100644 (file)
@@ -301,8 +301,8 @@ public:
       The other instance is left as a null string.  */
   String& operator=(String&& s) noexcept
   {
-    string_ = std::move(s.string_);
-    view_ = s.view_;
+    this->string_ = std::move(s.string_);
+    this->view_ = s.view_;
     s.view_ = string_view();
     return *this;
   }
@@ -340,33 +340,33 @@ public:
   }
 
   /** Return true if the instance is not a null string.  */
-  explicit operator bool() const noexcept { return data() != nullptr; }
+  explicit operator bool() const noexcept { return this->data() != nullptr; }
 
   /** Return a view of the string.  */
-  string_view view() const noexcept { return view_; }
+  string_view view() const noexcept { return this->view_; }
   operator string_view() const noexcept { return this->view(); }
 
   /** Return true if the instance is an empty stringn or null string.  */
-  bool empty() const noexcept { return view_.empty(); }
+  bool empty() const noexcept { return this->view_.empty(); }
 
   /** Return a pointer to the start of the string.  */
-  const char* data() const noexcept { return view_.data(); }
+  const char* data() const noexcept { return this->view_.data(); }
 
   /** Return the length of the string in bytes.  */
-  size_type size() const noexcept { return view_.size(); }
-  size_type length() const noexcept { return view_.length(); }
+  size_type size() const noexcept { return this->view_.size(); }
+  size_type length() const noexcept { return this->view_.length(); }
 
   /** Return the character at the given position.
       No bounds checking is performed.  */
-  char operator[](size_type pos) const noexcept { return view_[pos]; }
+  char operator[](size_type pos) const noexcept { return this->view_[pos]; }
 
   /** Return the character at the given position.
       If the position is out of bounds, throws std::out_of_range.  */
-  char at(size_type pos) const { return view_.at(pos); }
+  char at(size_type pos) const { return this->view_.at(pos); }
 
-  char front() const noexcept { return view_.front(); }
+  char front() const noexcept { return this->view_.front(); }
 
-  char back() const noexcept { return view_.back(); }
+  char back() const noexcept { return this->view_.back(); }
 
   /** Return true if this instance is stable and otherwise false.
       An instance is stable if it is in the 'null' state or if it is
@@ -392,15 +392,18 @@ public:
       or str() is called.  */
   const char* c_str();
 
-  const_iterator begin() const noexcept { return view_.begin(); }
-  const_iterator end() const noexcept { return view_.end(); }
-  const_iterator cbegin() const noexcept { return begin(); }
-  const_iterator cend() const noexcept { return end(); }
+  const_iterator begin() const noexcept { return this->view_.begin(); }
+  const_iterator end() const noexcept { return this->view_.end(); }
+  const_iterator cbegin() const noexcept { return this->begin(); }
+  const_iterator cend() const noexcept { return this->end(); }
 
-  const_reverse_iterator rbegin() const noexcept { return view_.rbegin(); }
-  const_reverse_iterator rend() const noexcept { return view_.rend(); }
-  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
-  const_reverse_iterator crend() const noexcept { return rend(); }
+  const_reverse_iterator rbegin() const noexcept
+  {
+    return this->view_.rbegin();
+  }
+  const_reverse_iterator rend() const noexcept { return this->view_.rend(); }
+  const_reverse_iterator crbegin() const noexcept { return this->rbegin(); }
+  const_reverse_iterator crend() const noexcept { return this->rend(); }
 
   /** Append to the string using any type that implements the
       AsStringView trait.  */
@@ -410,8 +413,8 @@ public:
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
     std::string r;
-    r.reserve(size() + v.size());
-    r.assign(data(), size());
+    r.reserve(this->size() + v.size());
+    r.assign(this->data(), this->size());
     r.append(v.data(), v.size());
     return *this = std::move(r);
   }
@@ -428,21 +431,21 @@ public:
   void push_back(char ch)
   {
     std::string s;
-    s.reserve(size() + 1);
-    s.assign(data(), size());
+    s.reserve(this->size() + 1);
+    s.assign(this->data(), this->size());
     s.push_back(ch);
     *this = std::move(s);
   }
 
-  void pop_back() { *this = String(*this, 0, size() - 1); }
+  void pop_back() { *this = String(*this, 0, this->size() - 1); }
 
   template <typename T>
   typename std::enable_if<AsStringView<T>::value, String&>::type replace(
     size_type pos, size_type count, T&& s)
   {
-    const_iterator first = begin() + pos;
+    const_iterator first = this->begin() + pos;
     const_iterator last = first + count;
-    return replace(first, last, std::forward<T>(s));
+    return this->replace(first, last, std::forward<T>(s));
   }
 
   template <typename InputIterator>
@@ -450,9 +453,9 @@ public:
                   InputIterator first2, InputIterator last2)
   {
     std::string out;
-    out.append(view_.begin(), first);
+    out.append(this->view_.begin(), first);
     out.append(first2, last2);
-    out.append(last, view_.end());
+    out.append(last, this->view_.end());
     return *this = std::move(out);
   }
 
@@ -462,10 +465,11 @@ public:
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
     std::string out;
-    out.reserve((first - view_.begin()) + v.size() + (view_.end() - last));
-    out.append(view_.begin(), first);
+    out.reserve((first - this->view_.begin()) + v.size() +
+                (this->view_.end() - last));
+    out.append(this->view_.begin(), first);
     out.append(v.data(), v.size());
-    out.append(last, view_.end());
+    out.append(last, this->view_.end());
     return *this = std::move(out);
   }
 
@@ -476,39 +480,40 @@ public:
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
     v = v.substr(pos2, count2);
-    return replace(pos, count, v);
+    return this->replace(pos, count, v);
   }
 
   String& replace(size_type pos, size_type count, size_type count2, char ch)
   {
-    const_iterator first = begin() + pos;
+    const_iterator first = this->begin() + pos;
     const_iterator last = first + count;
-    return replace(first, last, count2, ch);
+    return this->replace(first, last, count2, ch);
   }
 
   String& replace(const_iterator first, const_iterator last, size_type count2,
                   char ch)
   {
     std::string out;
-    out.reserve((first - view_.begin()) + count2 + (view_.end() - last));
-    out.append(view_.begin(), first);
+    out.reserve((first - this->view_.begin()) + count2 +
+                (this->view_.end() - last));
+    out.append(this->view_.begin(), first);
     out.append(count2, ch);
-    out.append(last, view_.end());
+    out.append(last, this->view_.end());
     return *this = std::move(out);
   }
 
   size_type copy(char* dest, size_type count, size_type pos = 0) const;
 
-  void resize(size_type count) { resize(count, char()); }
+  void resize(size_type count) { this->resize(count, char()); }
 
   void resize(size_type count, char ch)
   {
     std::string s;
     s.reserve(count);
-    if (count <= size()) {
-      s.assign(data(), count);
+    if (count <= this->size()) {
+      s.assign(this->data(), count);
     } else {
-      s.assign(data(), size());
+      s.assign(this->data(), this->size());
       s.resize(count, ch);
     }
     *this = std::move(s);
@@ -516,8 +521,8 @@ public:
 
   void swap(String& other)
   {
-    std::swap(string_, other.string_);
-    std::swap(view_, other.view_);
+    std::swap(this->string_, other.string_);
+    std::swap(this->view_, other.view_);
   }
 
   /** Return a substring starting at position 'pos' and
@@ -528,29 +533,29 @@ public:
   typename std::enable_if<AsStringView<T>::value, int>::type compare(
     T&& s) const
   {
-    return view_.compare(AsStringView<T>::view(std::forward<T>(s)));
+    return this->view_.compare(AsStringView<T>::view(std::forward<T>(s)));
   }
 
   int compare(size_type pos1, size_type count1, string_view v) const
   {
-    return view_.compare(pos1, count1, v);
+    return this->view_.compare(pos1, count1, v);
   }
 
   int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
               size_type count2) const
   {
-    return view_.compare(pos1, count1, v, pos2, count2);
+    return this->view_.compare(pos1, count1, v, pos2, count2);
   }
 
   int compare(size_type pos1, size_type count1, const char* s) const
   {
-    return view_.compare(pos1, count1, s);
+    return this->view_.compare(pos1, count1, s);
   }
 
   int compare(size_type pos1, size_type count1, const char* s,
               size_type count2) const
   {
-    return view_.compare(pos1, count1, s, count2);
+    return this->view_.compare(pos1, count1, s, count2);
   }
 
   template <typename T>
@@ -558,12 +563,12 @@ public:
     T&& s, size_type pos = 0) const
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
-    return view_.find(v, pos);
+    return this->view_.find(v, pos);
   }
 
   size_type find(const char* s, size_type pos, size_type count) const
   {
-    return view_.find(s, pos, count);
+    return this->view_.find(s, pos, count);
   }
 
   template <typename T>
@@ -571,12 +576,12 @@ public:
     T&& s, size_type pos = npos) const
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
-    return view_.rfind(v, pos);
+    return this->view_.rfind(v, pos);
   }
 
   size_type rfind(const char* s, size_type pos, size_type count) const
   {
-    return view_.rfind(s, pos, count);
+    return this->view_.rfind(s, pos, count);
   }
 
   template <typename T>
@@ -584,12 +589,12 @@ public:
   find_first_of(T&& s, size_type pos = 0) const
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
-    return view_.find_first_of(v, pos);
+    return this->view_.find_first_of(v, pos);
   }
 
   size_type find_first_of(const char* s, size_type pos, size_type count) const
   {
-    return view_.find_first_of(s, pos, count);
+    return this->view_.find_first_of(s, pos, count);
   }
 
   template <typename T>
@@ -597,13 +602,13 @@ public:
   find_first_not_of(T&& s, size_type pos = 0) const
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
-    return view_.find_first_not_of(v, pos);
+    return this->view_.find_first_not_of(v, pos);
   }
 
   size_type find_first_not_of(const char* s, size_type pos,
                               size_type count) const
   {
-    return view_.find_first_not_of(s, pos, count);
+    return this->view_.find_first_not_of(s, pos, count);
   }
 
   template <typename T>
@@ -611,12 +616,12 @@ public:
   find_last_of(T&& s, size_type pos = npos) const
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
-    return view_.find_last_of(v, pos);
+    return this->view_.find_last_of(v, pos);
   }
 
   size_type find_last_of(const char* s, size_type pos, size_type count) const
   {
-    return view_.find_last_of(s, pos, count);
+    return this->view_.find_last_of(s, pos, count);
   }
 
   template <typename T>
@@ -624,13 +629,13 @@ public:
   find_last_not_of(T&& s, size_type pos = npos) const
   {
     string_view v = AsStringView<T>::view(std::forward<T>(s));
-    return view_.find_last_not_of(v, pos);
+    return this->view_.find_last_not_of(v, pos);
   }
 
   size_type find_last_not_of(const char* s, size_type pos,
                              size_type count) const
   {
-    return view_.find_last_not_of(s, pos, count);
+    return this->view_.find_last_not_of(s, pos, count);
   }
 
 private:
@@ -822,7 +827,10 @@ struct StringOpPlus
   }
 #endif
   operator std::string() const;
-  std::string::size_type size() const { return l.size() + r.size(); }
+  std::string::size_type size() const
+  {
+    return this->l.size() + this->r.size();
+  }
 };
 
 template <typename T>
@@ -848,7 +856,7 @@ template <typename L, typename R>
 StringOpPlus<L, R>::operator std::string() const
 {
   std::string s;
-  s.reserve(size());
+  s.reserve(this->size());
   s += *this;
   return s;
 }
index e0af281..5bb6e7b 100644 (file)
@@ -11,6 +11,9 @@
 
 std::string cmTrimWhitespace(cm::string_view str)
 {
+  // XXX(clang-tidy): This declaration and the next cannot be `const auto*`
+  // because the qualification of `auto` is platform-dependent.
+  // NOLINTNEXTLINE(readability-qualified-auto)
   auto start = str.begin();
   while (start != str.end() && cmIsSpace(*start)) {
     ++start;
@@ -18,6 +21,7 @@ std::string cmTrimWhitespace(cm::string_view str)
   if (start == str.end()) {
     return std::string();
   }
+  // NOLINTNEXTLINE(readability-qualified-auto)
   auto stop = str.end() - 1;
   while (cmIsSpace(*stop)) {
     --stop;
@@ -161,42 +165,42 @@ inline void MakeDigits(cm::string_view& view, char (&digits)[N],
 
 cmAlphaNum::cmAlphaNum(int val)
 {
-  MakeDigits(View_, Digits_, "%i", val);
+  MakeDigits(this->View_, this->Digits_, "%i", val);
 }
 
 cmAlphaNum::cmAlphaNum(unsigned int val)
 {
-  MakeDigits(View_, Digits_, "%u", val);
+  MakeDigits(this->View_, this->Digits_, "%u", val);
 }
 
 cmAlphaNum::cmAlphaNum(long int val)
 {
-  MakeDigits(View_, Digits_, "%li", val);
+  MakeDigits(this->View_, this->Digits_, "%li", val);
 }
 
 cmAlphaNum::cmAlphaNum(unsigned long int val)
 {
-  MakeDigits(View_, Digits_, "%lu", val);
+  MakeDigits(this->View_, this->Digits_, "%lu", val);
 }
 
 cmAlphaNum::cmAlphaNum(long long int val)
 {
-  MakeDigits(View_, Digits_, "%lli", val);
+  MakeDigits(this->View_, this->Digits_, "%lli", val);
 }
 
 cmAlphaNum::cmAlphaNum(unsigned long long int val)
 {
-  MakeDigits(View_, Digits_, "%llu", val);
+  MakeDigits(this->View_, this->Digits_, "%llu", val);
 }
 
 cmAlphaNum::cmAlphaNum(float val)
 {
-  MakeDigits(View_, Digits_, "%g", static_cast<double>(val));
+  MakeDigits(this->View_, this->Digits_, "%g", static_cast<double>(val));
 }
 
 cmAlphaNum::cmAlphaNum(double val)
 {
-  MakeDigits(View_, Digits_, "%g", val);
+  MakeDigits(this->View_, this->Digits_, "%g", val);
 }
 
 std::string cmCatViews(std::initializer_list<cm::string_view> views)
index 01e3d94..6b458ec 100644 (file)
@@ -48,7 +48,7 @@ struct cmStrCmp
   {
   }
 
-  bool operator()(cm::string_view sv) const { return Test_ == sv; }
+  bool operator()(cm::string_view sv) const { return this->Test_ == sv; }
 
 private:
   std::string const Test_;
@@ -163,9 +163,9 @@ public:
   {
   }
   cmAlphaNum(char ch)
-    : View_(Digits_, 1)
+    : View_(this->Digits_, 1)
   {
-    Digits_[0] = ch;
+    this->Digits_[0] = ch;
   }
   cmAlphaNum(int val);
   cmAlphaNum(unsigned int val);
@@ -176,7 +176,7 @@ public:
   cmAlphaNum(float val);
   cmAlphaNum(double val);
 
-  cm::string_view View() const { return View_; }
+  cm::string_view View() const { return this->View_; }
 
 private:
   cm::string_view View_;
index b28fca9..23fc3e0 100644 (file)
@@ -1,5 +1,6 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #define _SCL_SECURE_NO_WARNINGS
 
 #include "cmStringCommand.h"
@@ -966,21 +967,21 @@ public:
 
 const std::string& Args::PopFront(cm::string_view error)
 {
-  if (empty()) {
+  if (this->empty()) {
     throw json_error({ error });
   }
-  const std::string& res = *begin();
-  advance(1);
+  const std::string& res = *this->begin();
+  this->advance(1);
   return res;
 }
 
 const std::string& Args::PopBack(cm::string_view error)
 {
-  if (empty()) {
+  if (this->empty()) {
     throw json_error({ error });
   }
-  const std::string& res = *(end() - 1);
-  retreat(1);
+  const std::string& res = *(this->end() - 1);
+  this->retreat(1);
   return res;
 }
 
index 6a705f4..0807590 100644 (file)
@@ -3,11 +3,13 @@
 
 #if !defined(_WIN32) && !defined(__sun)
 // POSIX APIs are needed
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _POSIX_C_SOURCE 200809L
 #endif
 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
   defined(__QNX__)
 // For isascii
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _XOPEN_SOURCE 700
 #endif
 
 #  include "cmCryptoHash.h"
 #endif
 
-#if defined(CMAKE_USE_ELF_PARSER)
+#if defined(CMake_USE_ELF_PARSER)
 #  include "cmELF.h"
 #endif
 
-#if defined(CMAKE_USE_MACH_PARSER)
+#if defined(CMake_USE_MACH_PARSER)
 #  include "cmMachO.h"
 #endif
 
+#if defined(CMake_USE_XCOFF_PARSER)
+#  include "cmXCOFF.h"
+#endif
+
 #include <algorithm>
 #include <cassert>
 #include <cctype>
@@ -1255,6 +1261,30 @@ void cmSystemTools::ConvertToOutputSlashes(std::string& path)
 #endif
 }
 
+void cmSystemTools::ConvertToLongPath(std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // Try to convert path to a long path only if the path contains character '~'
+  if (path.find('~') == std::string::npos) {
+    return;
+  }
+
+  std::wstring wPath = cmsys::Encoding::ToWide(path);
+  DWORD ret = GetLongPathNameW(wPath.c_str(), nullptr, 0);
+  std::vector<wchar_t> buffer(ret);
+  if (ret != 0) {
+    ret = GetLongPathNameW(wPath.c_str(), buffer.data(),
+                           static_cast<DWORD>(buffer.size()));
+  }
+
+  if (ret != 0) {
+    path = cmsys::Encoding::ToNarrow(buffer.data());
+  }
+#else
+  static_cast<void>(path);
+#endif
+}
+
 std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -2291,7 +2321,7 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
 {
 // For ELF shared libraries use a real parser to get the correct
 // soname.
-#if defined(CMAKE_USE_ELF_PARSER)
+#if defined(CMake_USE_ELF_PARSER)
   cmELF elf(fullPath.c_str());
   if (elf) {
     return elf.GetSOName(soname);
@@ -2321,7 +2351,7 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
 bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
                                             std::string& soname)
 {
-#if defined(CMAKE_USE_MACH_PARSER)
+#if defined(CMake_USE_MACH_PARSER)
   cmMachO macho(fullPath.c_str());
   if (macho) {
     return macho.GetInstallName(soname);
@@ -2334,9 +2364,9 @@ bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
   return false;
 }
 
-#if defined(CMAKE_USE_ELF_PARSER)
-std::string::size_type cmSystemToolsFindRPath(std::string const& have,
-                                              std::string const& want)
+#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER)
+std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
+                                              cm::string_view const& want)
 {
   std::string::size_type pos = 0;
   while (pos < have.size()) {
@@ -2368,7 +2398,7 @@ std::string::size_type cmSystemToolsFindRPath(std::string const& have,
 }
 #endif
 
-#if defined(CMAKE_USE_ELF_PARSER)
+#if defined(CMake_USE_ELF_PARSER)
 struct cmSystemToolsRPathInfo
 {
   unsigned long Position;
@@ -2378,7 +2408,8 @@ struct cmSystemToolsRPathInfo
 };
 #endif
 
-#if defined(CMAKE_USE_ELF_PARSER)
+// FIXME: Dispatch if multiple formats are supported.
+#if defined(CMake_USE_ELF_PARSER)
 bool cmSystemTools::ChangeRPath(std::string const& file,
                                 std::string const& oldRPath,
                                 std::string const& newRPath,
@@ -2550,6 +2581,75 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
   }
   return true;
 }
+#elif defined(CMake_USE_XCOFF_PARSER)
+bool cmSystemTools::ChangeRPath(std::string const& file,
+                                std::string const& oldRPath,
+                                std::string const& newRPath,
+                                bool removeEnvironmentRPath, std::string* emsg,
+                                bool* changed)
+{
+  if (changed) {
+    *changed = false;
+  }
+
+  bool chg = false;
+  cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+  if (cm::optional<cm::string_view> maybeLibPath = xcoff.GetLibPath()) {
+    cm::string_view libPath = *maybeLibPath;
+    // Make sure the current rpath contains the old rpath.
+    std::string::size_type pos = cmSystemToolsFindRPath(libPath, oldRPath);
+    if (pos == std::string::npos) {
+      // If it contains the new rpath instead then it is okay.
+      if (cmSystemToolsFindRPath(libPath, newRPath) != std::string::npos) {
+        return true;
+      }
+      if (emsg) {
+        std::ostringstream e;
+        /* clang-format off */
+        e << "The current RPATH is:\n"
+          << "  " << libPath << "\n"
+          << "which does not contain:\n"
+          << "  " << oldRPath << "\n"
+          << "as was expected.";
+        /* clang-format on */
+        *emsg = e.str();
+      }
+      return false;
+    }
+
+    // The prefix is either empty or ends in a ':'.
+    cm::string_view prefix = libPath.substr(0, pos);
+    if (newRPath.empty() && !prefix.empty()) {
+      prefix.remove_suffix(1);
+    }
+
+    // The suffix is either empty or starts in a ':'.
+    cm::string_view suffix = libPath.substr(pos + oldRPath.length());
+
+    // Construct the new value which preserves the part of the path
+    // not being changed.
+    std::string newLibPath;
+    if (!removeEnvironmentRPath) {
+      newLibPath = std::string(prefix);
+    }
+    newLibPath += newRPath;
+    newLibPath += suffix;
+
+    chg = xcoff.SetLibPath(newLibPath);
+  }
+  if (!xcoff) {
+    if (emsg) {
+      *emsg = xcoff.GetErrorMessage();
+    }
+    return false;
+  }
+
+  // Everything was updated successfully.
+  if (changed) {
+    *changed = chg;
+  }
+  return true;
+}
 #else
 bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
                                 std::string const& /*oldRPath*/,
@@ -2694,7 +2794,8 @@ int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs)
   return cm_strverscmp(lhs.c_str(), rhs.c_str());
 }
 
-#if defined(CMAKE_USE_ELF_PARSER)
+// FIXME: Dispatch if multiple formats are supported.
+#if defined(CMake_USE_ELF_PARSER)
 bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
                                 bool* removed)
 {
@@ -2835,6 +2936,28 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
   }
   return true;
 }
+#elif defined(CMake_USE_XCOFF_PARSER)
+bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
+                                bool* removed)
+{
+  if (removed) {
+    *removed = false;
+  }
+
+  cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+  bool rm = xcoff.RemoveLibPath();
+  if (!xcoff) {
+    if (emsg) {
+      *emsg = xcoff.GetErrorMessage();
+    }
+    return false;
+  }
+
+  if (removed) {
+    *removed = rm;
+  }
+  return true;
+}
 #else
 bool cmSystemTools::RemoveRPath(std::string const& /*file*/,
                                 std::string* /*emsg*/, bool* /*removed*/)
@@ -2843,10 +2966,11 @@ bool cmSystemTools::RemoveRPath(std::string const& /*file*/,
 }
 #endif
 
+// FIXME: Dispatch if multiple formats are supported.
 bool cmSystemTools::CheckRPath(std::string const& file,
                                std::string const& newRPath)
 {
-#if defined(CMAKE_USE_ELF_PARSER)
+#if defined(CMake_USE_ELF_PARSER)
   // Parse the ELF binary.
   cmELF elf(file.c_str());
 
@@ -2868,6 +2992,15 @@ bool cmSystemTools::CheckRPath(std::string const& file,
     }
   }
   return false;
+#elif defined(CMake_USE_XCOFF_PARSER)
+  // Parse the XCOFF binary.
+  cmXCOFF xcoff(file.c_str());
+  if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
+    if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
+      return true;
+    }
+  }
+  return false;
 #else
   (void)file;
   (void)newRPath;
index 1100f05..5bbbb0c 100644 (file)
@@ -287,6 +287,12 @@ public:
   // running cmake needs paths to be in its format
   static std::string ConvertToRunCommandPath(const std::string& path);
 
+  /**
+   * For windows computes the long path for the given path,
+   * For Unix, it is a noop
+   */
+  static void ConvertToLongPath(std::string& path);
+
   /** compute the relative path from local to remote.  local must
       be a directory.  remote can be a file or a directory.
       Both remote and local must be full paths.  Basically, if
index bda2b30..91dcd0e 100644 (file)
@@ -209,11 +209,10 @@ public:
     TLLCommands;
   cmListFileBacktrace Backtrace;
 
-public:
   bool CheckImportedLibName(std::string const& prop,
                             std::string const& value) const;
 
-  std::string ProcessSourceItemCMP0049(const std::string& s);
+  std::string ProcessSourceItemCMP0049(const std::string& s) const;
 };
 
 namespace {
@@ -230,34 +229,35 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
   : impl(cm::make_unique<cmTargetInternals>())
 {
   assert(mf);
-  impl->TargetType = type;
-  impl->Makefile = mf;
-  impl->Name = name;
-  impl->IsGeneratorProvided = false;
-  impl->HaveInstallRule = false;
-  impl->IsDLLPlatform = false;
-  impl->IsAIX = false;
-  impl->IsAndroid = false;
-  impl->IsImportedTarget =
+  this->impl->TargetType = type;
+  this->impl->Makefile = mf;
+  this->impl->Name = name;
+  this->impl->IsGeneratorProvided = false;
+  this->impl->HaveInstallRule = false;
+  this->impl->IsDLLPlatform = false;
+  this->impl->IsAIX = false;
+  this->impl->IsAndroid = false;
+  this->impl->IsImportedTarget =
     (vis == VisibilityImported || vis == VisibilityImportedGlobally);
-  impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
-  impl->BuildInterfaceIncludesAppended = false;
-  impl->PerConfig = (perConfig == PerConfig::Yes);
+  this->impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
+  this->impl->BuildInterfaceIncludesAppended = false;
+  this->impl->PerConfig = (perConfig == PerConfig::Yes);
 
   // Check whether this is a DLL platform.
-  impl->IsDLLPlatform =
-    !impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
+  this->impl->IsDLLPlatform =
+    !this->impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")
+       .empty();
 
   // Check whether we are targeting AIX.
   {
     std::string const& systemName =
-      impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME");
-    impl->IsAIX = (systemName == "AIX" || systemName == "OS400");
+      this->impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+    this->impl->IsAIX = (systemName == "AIX" || systemName == "OS400");
   }
 
   // Check whether we are targeting an Android platform.
-  impl->IsAndroid =
-    (impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android");
+  this->impl->IsAndroid = (this->impl->Makefile->GetSafeDefinition(
+                             "CMAKE_SYSTEM_NAME") == "Android");
 
   std::string defKey;
   defKey.reserve(128);
@@ -373,12 +373,16 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
     initProp("ISPC_INSTRUCTION_SETS");
     initProp("LINK_SEARCH_START_STATIC");
     initProp("LINK_SEARCH_END_STATIC");
+    initProp("OBJC_CLANG_TIDY");
+    initProp("OBJCXX_CLANG_TIDY");
     initProp("Swift_LANGUAGE_VERSION");
     initProp("Swift_MODULE_DIRECTORY");
     initProp("VS_JUST_MY_CODE_DEBUGGING");
     initProp("DISABLE_PRECOMPILE_HEADERS");
     initProp("UNITY_BUILD");
+    initProp("UNITY_BUILD_UNIQUE_ID");
     initProp("OPTIMIZE_DEPENDENCIES");
+    initProp("EXPORT_COMPILE_COMMANDS");
     initPropValue("UNITY_BUILD_BATCH_SIZE", "8");
     initPropValue("UNITY_BUILD_MODE", "BATCH");
     initPropValue("PCH_WARN_INVALID", "ON");
@@ -433,7 +437,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
       for (auto const& prop : configProps) {
         // Interface libraries have no output locations, so honor only
         // the configuration map.
-        if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY &&
+        if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY &&
             strcmp(prop, "MAP_IMPORTED_CONFIG_") != 0) {
           continue;
         }
@@ -446,15 +450,15 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
       // compatibility with previous CMake versions in which executables
       // did not support this variable.  Projects may still specify the
       // property directly.
-      if (impl->TargetType != cmStateEnums::EXECUTABLE &&
-          impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
+      if (this->impl->TargetType != cmStateEnums::EXECUTABLE &&
+          this->impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) {
         std::string property =
           cmStrCat(cmSystemTools::UpperCase(configName), "_POSTFIX");
         initProp(property);
       }
 
-      if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
-          impl->TargetType == cmStateEnums::STATIC_LIBRARY) {
+      if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+          this->impl->TargetType == cmStateEnums::STATIC_LIBRARY) {
         std::string property = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
                                         cmSystemTools::UpperCase(configName));
         initProp(property);
@@ -463,66 +467,67 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
   }
 
   // Save the backtrace of target construction.
-  impl->Backtrace = impl->Makefile->GetBacktrace();
+  this->impl->Backtrace = this->impl->Makefile->GetBacktrace();
 
   if (!this->IsImported()) {
     // Initialize the INCLUDE_DIRECTORIES property based on the current value
     // of the same directory property:
-    cm::append(impl->IncludeDirectoriesEntries,
-               impl->Makefile->GetIncludeDirectoriesEntries());
-    cm::append(impl->IncludeDirectoriesBacktraces,
-               impl->Makefile->GetIncludeDirectoriesBacktraces());
+    cm::append(this->impl->IncludeDirectoriesEntries,
+               this->impl->Makefile->GetIncludeDirectoriesEntries());
+    cm::append(this->impl->IncludeDirectoriesBacktraces,
+               this->impl->Makefile->GetIncludeDirectoriesBacktraces());
 
     {
-      auto const& sysInc = impl->Makefile->GetSystemIncludeDirectories();
-      impl->SystemIncludeDirectories.insert(sysInc.begin(), sysInc.end());
+      auto const& sysInc = this->impl->Makefile->GetSystemIncludeDirectories();
+      this->impl->SystemIncludeDirectories.insert(sysInc.begin(),
+                                                  sysInc.end());
     }
 
-    cm::append(impl->CompileOptionsEntries,
-               impl->Makefile->GetCompileOptionsEntries());
-    cm::append(impl->CompileOptionsBacktraces,
-               impl->Makefile->GetCompileOptionsBacktraces());
+    cm::append(this->impl->CompileOptionsEntries,
+               this->impl->Makefile->GetCompileOptionsEntries());
+    cm::append(this->impl->CompileOptionsBacktraces,
+               this->impl->Makefile->GetCompileOptionsBacktraces());
 
-    cm::append(impl->LinkOptionsEntries,
-               impl->Makefile->GetLinkOptionsEntries());
-    cm::append(impl->LinkOptionsBacktraces,
-               impl->Makefile->GetLinkOptionsBacktraces());
+    cm::append(this->impl->LinkOptionsEntries,
+               this->impl->Makefile->GetLinkOptionsEntries());
+    cm::append(this->impl->LinkOptionsBacktraces,
+               this->impl->Makefile->GetLinkOptionsBacktraces());
 
-    cm::append(impl->LinkDirectoriesEntries,
-               impl->Makefile->GetLinkDirectoriesEntries());
-    cm::append(impl->LinkDirectoriesBacktraces,
-               impl->Makefile->GetLinkDirectoriesBacktraces());
+    cm::append(this->impl->LinkDirectoriesEntries,
+               this->impl->Makefile->GetLinkDirectoriesEntries());
+    cm::append(this->impl->LinkDirectoriesBacktraces,
+               this->impl->Makefile->GetLinkDirectoriesBacktraces());
   }
 
-  if (impl->TargetType == cmStateEnums::EXECUTABLE) {
+  if (this->impl->TargetType == cmStateEnums::EXECUTABLE) {
     initProp("ANDROID_GUI");
     initProp("CROSSCOMPILING_EMULATOR");
     initProp("ENABLE_EXPORTS");
   }
-  if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
-      impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
+  if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+      this->impl->TargetType == cmStateEnums::MODULE_LIBRARY) {
     this->SetProperty("POSITION_INDEPENDENT_CODE", "True");
   } else if (this->CanCompileSources()) {
     initProp("POSITION_INDEPENDENT_CODE");
   }
-  if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
-      impl->TargetType == cmStateEnums::EXECUTABLE) {
+  if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+      this->impl->TargetType == cmStateEnums::EXECUTABLE) {
     initProp("AIX_EXPORT_ALL_SYMBOLS");
     initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
   }
 
   // Record current policies for later use.
-  impl->Makefile->RecordPolicies(impl->PolicyMap);
+  this->impl->Makefile->RecordPolicies(this->impl->PolicyMap);
 
-  if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) {
+  if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) {
     // This policy is checked in a few conditions. The properties relevant
     // to the policy are always ignored for cmStateEnums::INTERFACE_LIBRARY
     // targets,
     // so ensure that the conditions don't lead to nonsense.
-    impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
+    this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW);
   }
 
-  if (impl->TargetType <= cmStateEnums::GLOBAL_TARGET) {
+  if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) {
     initProp("DOTNET_TARGET_FRAMEWORK");
     initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
   }
@@ -555,40 +560,40 @@ cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default;
 
 cmStateEnums::TargetType cmTarget::GetType() const
 {
-  return impl->TargetType;
+  return this->impl->TargetType;
 }
 
 cmMakefile* cmTarget::GetMakefile() const
 {
-  return impl->Makefile;
+  return this->impl->Makefile;
 }
 
 cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const
 {
-  return impl->PolicyMap;
+  return this->impl->PolicyMap;
 }
 
 const std::string& cmTarget::GetName() const
 {
-  return impl->Name;
+  return this->impl->Name;
 }
 
 cmPolicies::PolicyStatus cmTarget::GetPolicyStatus(
   cmPolicies::PolicyID policy) const
 {
-  return impl->PolicyMap.Get(policy);
+  return this->impl->PolicyMap.Get(policy);
 }
 
 cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
 {
-  return impl->Makefile->GetGlobalGenerator();
+  return this->impl->Makefile->GetGlobalGenerator();
 }
 
 BTs<std::string> const* cmTarget::GetLanguageStandardProperty(
   const std::string& propertyName) const
 {
-  auto entry = impl->LanguageStandardProperties.find(propertyName);
-  if (entry != impl->LanguageStandardProperties.end()) {
+  auto entry = this->impl->LanguageStandardProperties.find(propertyName);
+  if (entry != this->impl->LanguageStandardProperties.end()) {
     return &entry->second;
   }
 
@@ -600,17 +605,17 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang,
                                            const std::string& feature)
 {
   cmListFileBacktrace featureBacktrace;
-  for (size_t i = 0; i < impl->CompileFeaturesEntries.size(); i++) {
-    if (impl->CompileFeaturesEntries[i] == feature) {
-      if (i < impl->CompileFeaturesBacktraces.size()) {
-        featureBacktrace = impl->CompileFeaturesBacktraces[i];
+  for (size_t i = 0; i < this->impl->CompileFeaturesEntries.size(); i++) {
+    if (this->impl->CompileFeaturesEntries[i] == feature) {
+      if (i < this->impl->CompileFeaturesBacktraces.size()) {
+        featureBacktrace = this->impl->CompileFeaturesBacktraces[i];
       }
       break;
     }
   }
 
   BTs<std::string>& languageStandardProperty =
-    impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")];
+    this->impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")];
   if (languageStandardProperty.Value != value) {
     languageStandardProperty.Value = value;
     languageStandardProperty.Backtraces.clear();
@@ -620,19 +625,24 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang,
 
 void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf)
 {
-  impl->Utilities.insert(BT<std::pair<std::string, bool>>(
+  this->impl->Utilities.insert(BT<std::pair<std::string, bool>>(
     { name, cross }, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
 }
 
+void cmTarget::AddUtility(BT<std::pair<std::string, bool>> util)
+{
+  this->impl->Utilities.emplace(std::move(util));
+}
+
 std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities()
   const
 {
-  return impl->Utilities;
+  return this->impl->Utilities;
 }
 
 cmListFileBacktrace const& cmTarget::GetBacktrace() const
 {
-  return impl->Backtrace;
+  return this->impl->Backtrace;
 }
 
 bool cmTarget::IsExecutableWithExports() const
@@ -645,74 +655,74 @@ bool cmTarget::IsFrameworkOnApple() const
 {
   return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
            this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
-          impl->Makefile->IsOn("APPLE") &&
+          this->impl->Makefile->IsOn("APPLE") &&
           this->GetPropertyAsBool("FRAMEWORK"));
 }
 
 bool cmTarget::IsAppBundleOnApple() const
 {
   return (this->GetType() == cmStateEnums::EXECUTABLE &&
-          impl->Makefile->IsOn("APPLE") &&
+          this->impl->Makefile->IsOn("APPLE") &&
           this->GetPropertyAsBool("MACOSX_BUNDLE"));
 }
 
 bool cmTarget::IsAndroidGuiExecutable() const
 {
-  return (this->GetType() == cmStateEnums::EXECUTABLE && impl->IsAndroid &&
-          this->GetPropertyAsBool("ANDROID_GUI"));
+  return (this->GetType() == cmStateEnums::EXECUTABLE &&
+          this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI"));
 }
 
 std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
 {
-  return impl->PreBuildCommands;
+  return this->impl->PreBuildCommands;
 }
 
 void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd)
 {
-  impl->PreBuildCommands.push_back(cmd);
+  this->impl->PreBuildCommands.push_back(cmd);
 }
 
 void cmTarget::AddPreBuildCommand(cmCustomCommand&& cmd)
 {
-  impl->PreBuildCommands.push_back(std::move(cmd));
+  this->impl->PreBuildCommands.push_back(std::move(cmd));
 }
 
 std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const
 {
-  return impl->PreLinkCommands;
+  return this->impl->PreLinkCommands;
 }
 
 void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd)
 {
-  impl->PreLinkCommands.push_back(cmd);
+  this->impl->PreLinkCommands.push_back(cmd);
 }
 
 void cmTarget::AddPreLinkCommand(cmCustomCommand&& cmd)
 {
-  impl->PreLinkCommands.push_back(std::move(cmd));
+  this->impl->PreLinkCommands.push_back(std::move(cmd));
 }
 
 std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const
 {
-  return impl->PostBuildCommands;
+  return this->impl->PostBuildCommands;
 }
 
 void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd)
 {
-  impl->PostBuildCommands.push_back(cmd);
+  this->impl->PostBuildCommands.push_back(cmd);
 }
 
 void cmTarget::AddPostBuildCommand(cmCustomCommand&& cmd)
 {
-  impl->PostBuildCommands.push_back(std::move(cmd));
+  this->impl->PostBuildCommands.push_back(std::move(cmd));
 }
 
 void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
 {
   if (!srcs.empty()) {
-    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-    impl->SourceEntries.push_back(cmJoin(srcs, ";"));
-    impl->SourceBacktraces.push_back(lfbt);
+    cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+    this->impl->SourceEntries.push_back(cmJoin(srcs, ";"));
+    this->impl->SourceBacktraces.push_back(lfbt);
   }
 }
 
@@ -723,25 +733,26 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
   for (auto filename : srcs) {
     if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
       if (!filename.empty()) {
-        filename = impl->ProcessSourceItemCMP0049(filename);
+        filename = this->impl->ProcessSourceItemCMP0049(filename);
         if (filename.empty()) {
           return;
         }
       }
-      impl->Makefile->GetOrCreateSource(filename);
+      this->impl->Makefile->GetOrCreateSource(filename);
     }
     srcFiles += sep;
     srcFiles += filename;
     sep = ";";
   }
   if (!srcFiles.empty()) {
-    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-    impl->SourceEntries.push_back(std::move(srcFiles));
-    impl->SourceBacktraces.push_back(lfbt);
+    cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+    this->impl->SourceEntries.push_back(std::move(srcFiles));
+    this->impl->SourceBacktraces.push_back(lfbt);
   }
 }
 
-std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s)
+std::string cmTargetInternals::ProcessSourceItemCMP0049(
+  const std::string& s) const
 {
   std::string src = s;
 
@@ -780,7 +791,7 @@ std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s)
 
 std::string cmTarget::GetSourceCMP0049(const std::string& s)
 {
-  return impl->ProcessSourceItemCMP0049(s);
+  return this->impl->ProcessSourceItemCMP0049(s);
 }
 
 struct CreateLocation
@@ -792,7 +803,7 @@ struct CreateLocation
   {
   }
 
-  cmSourceFileLocation operator()(const std::string& filename)
+  cmSourceFileLocation operator()(const std::string& filename) const
   {
     return cmSourceFileLocation(this->Makefile, filename);
   }
@@ -839,26 +850,28 @@ public:
 
 cmSourceFile* cmTarget::AddSource(const std::string& src, bool before)
 {
-  cmSourceFileLocation sfl(impl->Makefile, src,
+  cmSourceFileLocation sfl(this->impl->Makefile, src,
                            cmSourceFileLocationKind::Known);
-  if (std::find_if(impl->SourceEntries.begin(), impl->SourceEntries.end(),
-                   TargetPropertyEntryFinder(sfl)) ==
-      impl->SourceEntries.end()) {
-    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-    impl->SourceEntries.insert(
-      before ? impl->SourceEntries.begin() : impl->SourceEntries.end(), src);
-    impl->SourceBacktraces.insert(before ? impl->SourceBacktraces.begin()
-                                         : impl->SourceBacktraces.end(),
-                                  lfbt);
+  if (std::find_if(
+        this->impl->SourceEntries.begin(), this->impl->SourceEntries.end(),
+        TargetPropertyEntryFinder(sfl)) == this->impl->SourceEntries.end()) {
+    cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+    this->impl->SourceEntries.insert(before ? this->impl->SourceEntries.begin()
+                                            : this->impl->SourceEntries.end(),
+                                     src);
+    this->impl->SourceBacktraces.insert(
+      before ? this->impl->SourceBacktraces.begin()
+             : this->impl->SourceBacktraces.end(),
+      lfbt);
   }
   if (cmGeneratorExpression::Find(src) != std::string::npos) {
     return nullptr;
   }
-  return impl->Makefile->GetOrCreateSource(src, false,
-                                           cmSourceFileLocationKind::Known);
+  return this->impl->Makefile->GetOrCreateSource(
+    src, false, cmSourceFileLocationKind::Known);
 }
 
-void cmTarget::ClearDependencyInformation(cmMakefile& mf)
+void cmTarget::ClearDependencyInformation(cmMakefile& mf) const
 {
   std::string depname = cmStrCat(this->GetName(), "_LIB_DEPENDS");
   mf.RemoveCacheDefinition(depname);
@@ -873,7 +886,7 @@ std::string cmTarget::GetDebugGeneratorExpressions(
 
   // Get the list of configurations considered to be DEBUG.
   std::vector<std::string> debugConfigs =
-    impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
+    this->impl->Makefile->GetCMakeInstance()->GetDebugConfigs();
 
   std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
 
@@ -899,13 +912,14 @@ bool cmTarget::PushTLLCommandTrace(TLLSignature signature,
                                    cmListFileContext const& lfc)
 {
   bool ret = true;
-  if (!impl->TLLCommands.empty()) {
-    if (impl->TLLCommands.back().first != signature) {
+  if (!this->impl->TLLCommands.empty()) {
+    if (this->impl->TLLCommands.back().first != signature) {
       ret = false;
     }
   }
-  if (impl->TLLCommands.empty() || impl->TLLCommands.back().second != lfc) {
-    impl->TLLCommands.emplace_back(signature, lfc);
+  if (this->impl->TLLCommands.empty() ||
+      this->impl->TLLCommands.back().second != lfc) {
+    this->impl->TLLCommands.emplace_back(signature, lfc);
   }
   return ret;
 }
@@ -915,12 +929,13 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
   const char* sigString =
     (sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain");
   s << "The uses of the " << sigString << " signature are here:\n";
-  cmStateDirectory cmDir = impl->Makefile->GetStateSnapshot().GetDirectory();
-  for (auto const& cmd : impl->TLLCommands) {
+  cmStateDirectory cmDir =
+    this->impl->Makefile->GetStateSnapshot().GetDirectory();
+  for (auto const& cmd : this->impl->TLLCommands) {
     if (cmd.first == sig) {
       cmListFileContext lfc = cmd.second;
       lfc.FilePath = cmDir.ConvertToRelPathIfNotContained(
-        impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
+        this->impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
       s << " * " << lfc << '\n';
     }
   }
@@ -928,59 +943,59 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
 
 std::string const& cmTarget::GetInstallPath() const
 {
-  return impl->InstallPath;
+  return this->impl->InstallPath;
 }
 
 void cmTarget::SetInstallPath(std::string const& name)
 {
-  impl->InstallPath = name;
+  this->impl->InstallPath = name;
 }
 
 std::string const& cmTarget::GetRuntimeInstallPath() const
 {
-  return impl->RuntimeInstallPath;
+  return this->impl->RuntimeInstallPath;
 }
 
 void cmTarget::SetRuntimeInstallPath(std::string const& name)
 {
-  impl->RuntimeInstallPath = name;
+  this->impl->RuntimeInstallPath = name;
 }
 
 bool cmTarget::GetHaveInstallRule() const
 {
-  return impl->HaveInstallRule;
+  return this->impl->HaveInstallRule;
 }
 
 void cmTarget::SetHaveInstallRule(bool hir)
 {
-  impl->HaveInstallRule = hir;
+  this->impl->HaveInstallRule = hir;
 }
 
 void cmTarget::AddInstallGenerator(cmInstallTargetGenerator* g)
 {
-  impl->InstallGenerators.emplace_back(g);
+  this->impl->InstallGenerators.emplace_back(g);
 }
 
 std::vector<cmInstallTargetGenerator*> const& cmTarget::GetInstallGenerators()
   const
 {
-  return impl->InstallGenerators;
+  return this->impl->InstallGenerators;
 }
 
 bool cmTarget::GetIsGeneratorProvided() const
 {
-  return impl->IsGeneratorProvided;
+  return this->impl->IsGeneratorProvided;
 }
 
 void cmTarget::SetIsGeneratorProvided(bool igp)
 {
-  impl->IsGeneratorProvided = igp;
+  this->impl->IsGeneratorProvided = igp;
 }
 
 cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries()
   const
 {
-  return impl->OriginalLinkLibraries;
+  return this->impl->OriginalLinkLibraries;
 }
 
 void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
@@ -1002,11 +1017,11 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
       (tgt &&
        (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
         tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
-      (impl->Name == lib)) {
+      (this->impl->Name == lib)) {
     return;
   }
 
-  impl->OriginalLinkLibraries.emplace_back(lib, llt);
+  this->impl->OriginalLinkLibraries.emplace_back(lib, llt);
 
   // Add the explicit dependency information for libraries. This is
   // simply a set of libraries separated by ";". There should always
@@ -1016,11 +1031,11 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
   // may be purposefully duplicated to handle recursive dependencies,
   // and we removing one instance will break the link line. Duplicates
   // will be appropriately eliminated at emit time.
-  if (impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
-      impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
+  if (this->impl->TargetType >= cmStateEnums::STATIC_LIBRARY &&
+      this->impl->TargetType <= cmStateEnums::MODULE_LIBRARY &&
       (this->GetPolicyStatusCMP0073() == cmPolicies::OLD ||
        this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) {
-    std::string targetEntry = cmStrCat(impl->Name, "_LIB_DEPENDS");
+    std::string targetEntry = cmStrCat(this->impl->Name, "_LIB_DEPENDS");
     std::string dependencies;
     cmProp old_val = mf.GetDefinition(targetEntry);
     if (old_val) {
@@ -1047,102 +1062,102 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
 
 void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs)
 {
-  impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
+  this->impl->SystemIncludeDirectories.insert(incs.begin(), incs.end());
 }
 
 std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const
 {
-  return impl->SystemIncludeDirectories;
+  return this->impl->SystemIncludeDirectories;
 }
 
 cmStringRange cmTarget::GetIncludeDirectoriesEntries() const
 {
-  return cmMakeRange(impl->IncludeDirectoriesEntries);
+  return cmMakeRange(this->impl->IncludeDirectoriesEntries);
 }
 
 cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const
 {
-  return cmMakeRange(impl->IncludeDirectoriesBacktraces);
+  return cmMakeRange(this->impl->IncludeDirectoriesBacktraces);
 }
 
 cmStringRange cmTarget::GetCompileOptionsEntries() const
 {
-  return cmMakeRange(impl->CompileOptionsEntries);
+  return cmMakeRange(this->impl->CompileOptionsEntries);
 }
 
 cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const
 {
-  return cmMakeRange(impl->CompileOptionsBacktraces);
+  return cmMakeRange(this->impl->CompileOptionsBacktraces);
 }
 
 cmStringRange cmTarget::GetCompileFeaturesEntries() const
 {
-  return cmMakeRange(impl->CompileFeaturesEntries);
+  return cmMakeRange(this->impl->CompileFeaturesEntries);
 }
 
 cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const
 {
-  return cmMakeRange(impl->CompileFeaturesBacktraces);
+  return cmMakeRange(this->impl->CompileFeaturesBacktraces);
 }
 
 cmStringRange cmTarget::GetCompileDefinitionsEntries() const
 {
-  return cmMakeRange(impl->CompileDefinitionsEntries);
+  return cmMakeRange(this->impl->CompileDefinitionsEntries);
 }
 
 cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const
 {
-  return cmMakeRange(impl->CompileDefinitionsBacktraces);
+  return cmMakeRange(this->impl->CompileDefinitionsBacktraces);
 }
 
 cmStringRange cmTarget::GetPrecompileHeadersEntries() const
 {
-  return cmMakeRange(impl->PrecompileHeadersEntries);
+  return cmMakeRange(this->impl->PrecompileHeadersEntries);
 }
 
 cmBacktraceRange cmTarget::GetPrecompileHeadersBacktraces() const
 {
-  return cmMakeRange(impl->PrecompileHeadersBacktraces);
+  return cmMakeRange(this->impl->PrecompileHeadersBacktraces);
 }
 
 cmStringRange cmTarget::GetSourceEntries() const
 {
-  return cmMakeRange(impl->SourceEntries);
+  return cmMakeRange(this->impl->SourceEntries);
 }
 
 cmBacktraceRange cmTarget::GetSourceBacktraces() const
 {
-  return cmMakeRange(impl->SourceBacktraces);
+  return cmMakeRange(this->impl->SourceBacktraces);
 }
 
 cmStringRange cmTarget::GetLinkOptionsEntries() const
 {
-  return cmMakeRange(impl->LinkOptionsEntries);
+  return cmMakeRange(this->impl->LinkOptionsEntries);
 }
 
 cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
 {
-  return cmMakeRange(impl->LinkOptionsBacktraces);
+  return cmMakeRange(this->impl->LinkOptionsBacktraces);
 }
 
 cmStringRange cmTarget::GetLinkDirectoriesEntries() const
 {
-  return cmMakeRange(impl->LinkDirectoriesEntries);
+  return cmMakeRange(this->impl->LinkDirectoriesEntries);
 }
 
 cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
 {
-  return cmMakeRange(impl->LinkDirectoriesBacktraces);
+  return cmMakeRange(this->impl->LinkDirectoriesBacktraces);
 }
 
 cmStringRange cmTarget::GetLinkImplementationEntries() const
 {
-  return cmMakeRange(impl->LinkImplementationPropertyEntries);
+  return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
 }
 
 cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const
 {
-  return cmMakeRange(impl->LinkImplementationPropertyBacktraces);
+  return cmMakeRange(this->impl->LinkImplementationPropertyBacktraces);
 }
 
 void cmTarget::SetProperty(const std::string& prop, const char* value)
@@ -1171,154 +1186,154 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
   MAKE_STATIC_PROP(TYPE);
 #undef MAKE_STATIC_PROP
   if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
-    impl->Makefile->IssueMessage(
+    this->impl->Makefile->IssueMessage(
       MessageType::FATAL_ERROR,
       "MANUALLY_ADDED_DEPENDENCIES property is read-only\n");
     return;
   }
   if (prop == propNAME) {
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
-                                 "NAME property is read-only\n");
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                       "NAME property is read-only\n");
     return;
   }
   if (prop == propTYPE) {
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
-                                 "TYPE property is read-only\n");
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                       "TYPE property is read-only\n");
     return;
   }
   if (prop == propEXPORT_NAME && this->IsImported()) {
     std::ostringstream e;
     e << "EXPORT_NAME property can't be set on imported targets (\""
-      << impl->Name << "\")\n";
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << this->impl->Name << "\")\n";
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == propSOURCES && this->IsImported()) {
     std::ostringstream e;
-    e << "SOURCES property can't be set on imported targets (\"" << impl->Name
-      << "\")\n";
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    e << "SOURCES property can't be set on imported targets (\""
+      << this->impl->Name << "\")\n";
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == propIMPORTED_GLOBAL && !this->IsImported()) {
     std::ostringstream e;
     e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\""
-      << impl->Name << "\")\n";
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << this->impl->Name << "\")\n";
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
 
   if (prop == propINCLUDE_DIRECTORIES) {
-    impl->IncludeDirectoriesEntries.clear();
-    impl->IncludeDirectoriesBacktraces.clear();
+    this->impl->IncludeDirectoriesEntries.clear();
+    this->impl->IncludeDirectoriesBacktraces.clear();
     if (value) {
-      impl->IncludeDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->IncludeDirectoriesBacktraces.push_back(lfbt);
+      this->impl->IncludeDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->IncludeDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == propCOMPILE_OPTIONS) {
-    impl->CompileOptionsEntries.clear();
-    impl->CompileOptionsBacktraces.clear();
+    this->impl->CompileOptionsEntries.clear();
+    this->impl->CompileOptionsBacktraces.clear();
     if (value) {
-      impl->CompileOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->CompileOptionsBacktraces.push_back(lfbt);
+      this->impl->CompileOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->CompileOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == propCOMPILE_FEATURES) {
-    impl->CompileFeaturesEntries.clear();
-    impl->CompileFeaturesBacktraces.clear();
+    this->impl->CompileFeaturesEntries.clear();
+    this->impl->CompileFeaturesBacktraces.clear();
     if (value) {
-      impl->CompileFeaturesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->CompileFeaturesBacktraces.push_back(lfbt);
+      this->impl->CompileFeaturesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->CompileFeaturesBacktraces.push_back(lfbt);
     }
   } else if (prop == propCOMPILE_DEFINITIONS) {
-    impl->CompileDefinitionsEntries.clear();
-    impl->CompileDefinitionsBacktraces.clear();
+    this->impl->CompileDefinitionsEntries.clear();
+    this->impl->CompileDefinitionsBacktraces.clear();
     if (value) {
-      impl->CompileDefinitionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->CompileDefinitionsBacktraces.push_back(lfbt);
+      this->impl->CompileDefinitionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->CompileDefinitionsBacktraces.push_back(lfbt);
     }
   } else if (prop == propLINK_OPTIONS) {
-    impl->LinkOptionsEntries.clear();
-    impl->LinkOptionsBacktraces.clear();
+    this->impl->LinkOptionsEntries.clear();
+    this->impl->LinkOptionsBacktraces.clear();
     if (value) {
-      impl->LinkOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->LinkOptionsBacktraces.push_back(lfbt);
+      this->impl->LinkOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->LinkOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == propLINK_DIRECTORIES) {
-    impl->LinkDirectoriesEntries.clear();
-    impl->LinkDirectoriesBacktraces.clear();
+    this->impl->LinkDirectoriesEntries.clear();
+    this->impl->LinkDirectoriesBacktraces.clear();
     if (value) {
-      impl->LinkDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->LinkDirectoriesBacktraces.push_back(lfbt);
+      this->impl->LinkDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->LinkDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == propPRECOMPILE_HEADERS) {
-    impl->PrecompileHeadersEntries.clear();
-    impl->PrecompileHeadersBacktraces.clear();
+    this->impl->PrecompileHeadersEntries.clear();
+    this->impl->PrecompileHeadersBacktraces.clear();
     if (value) {
-      impl->PrecompileHeadersEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->PrecompileHeadersBacktraces.push_back(lfbt);
+      this->impl->PrecompileHeadersEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->PrecompileHeadersBacktraces.push_back(lfbt);
     }
   } else if (prop == propLINK_LIBRARIES) {
-    impl->LinkImplementationPropertyEntries.clear();
-    impl->LinkImplementationPropertyBacktraces.clear();
+    this->impl->LinkImplementationPropertyEntries.clear();
+    this->impl->LinkImplementationPropertyBacktraces.clear();
     if (value) {
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->LinkImplementationPropertyEntries.emplace_back(value);
-      impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->LinkImplementationPropertyEntries.emplace_back(value);
+      this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
     }
   } else if (prop == propSOURCES) {
-    impl->SourceEntries.clear();
-    impl->SourceBacktraces.clear();
+    this->impl->SourceEntries.clear();
+    this->impl->SourceBacktraces.clear();
     if (value) {
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->SourceEntries.emplace_back(value);
-      impl->SourceBacktraces.push_back(lfbt);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->SourceEntries.emplace_back(value);
+      this->impl->SourceBacktraces.push_back(lfbt);
     }
   } else if (prop == propIMPORTED_GLOBAL) {
     if (!cmIsOn(value)) {
       std::ostringstream e;
       e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
-        << impl->Name << "\")\n";
-      impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+        << this->impl->Name << "\")\n";
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
       return;
     }
     /* no need to change anything if value does not change */
-    if (!impl->ImportedGloballyVisible) {
-      impl->ImportedGloballyVisible = true;
+    if (!this->impl->ImportedGloballyVisible) {
+      this->impl->ImportedGloballyVisible = true;
       this->GetGlobalGenerator()->IndexTarget(this);
     }
   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") &&
-             !impl->CheckImportedLibName(prop, value ? value : "")) {
+             !this->impl->CheckImportedLibName(prop, value ? value : "")) {
     /* 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 (\""
-      << impl->Name << "\")\n";
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << this->impl->Name << "\")\n";
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   } else if (prop == propPRECOMPILE_HEADERS_REUSE_FROM) {
     if (this->GetProperty("PRECOMPILE_HEADERS")) {
       std::ostringstream e;
       e << "PRECOMPILE_HEADERS property is already set on target (\""
-        << impl->Name << "\")\n";
-      impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+        << this->impl->Name << "\")\n";
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
       return;
     }
-    auto reusedTarget =
-      impl->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(
-        value);
+    auto* reusedTarget = this->impl->Makefile->GetCMakeInstance()
+                           ->GetGlobalGenerator()
+                           ->FindTarget(value);
     if (!reusedTarget) {
       const std::string e(
         "PRECOMPILE_HEADERS_REUSE_FROM set with non existing target");
-      impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
       return;
     }
 
@@ -1327,7 +1342,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
       reusedFrom = value;
     }
 
-    impl->Properties.SetProperty(prop, reusedFrom.c_str());
+    this->impl->Properties.SetProperty(prop, reusedFrom.c_str());
 
     reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom);
     reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
@@ -1335,18 +1350,18 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
 
     cmProp tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME");
     this->SetProperty("COMPILE_PDB_NAME", cmToCStr(tmp));
-    this->AddUtility(reusedFrom, false, impl->Makefile);
+    this->AddUtility(reusedFrom, false, this->impl->Makefile);
   } else if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
              prop == propCUDA_STANDARD || prop == propOBJC_STANDARD ||
              prop == propOBJCXX_STANDARD) {
     if (value) {
-      impl->LanguageStandardProperties[prop] =
-        BTs<std::string>(value, impl->Makefile->GetBacktrace());
+      this->impl->LanguageStandardProperties[prop] =
+        BTs<std::string>(value, this->impl->Makefile->GetBacktrace());
     } else {
-      impl->LanguageStandardProperties.erase(prop);
+      this->impl->LanguageStandardProperties.erase(prop);
     }
   } else {
-    impl->Properties.SetProperty(prop, value);
+    this->impl->Properties.SetProperty(prop, value);
   }
 }
 
@@ -1354,102 +1369,102 @@ void cmTarget::AppendProperty(const std::string& prop,
                               const std::string& value, bool asString)
 {
   if (prop == "NAME") {
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
-                                 "NAME property is read-only\n");
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                       "NAME property is read-only\n");
     return;
   }
   if (prop == "EXPORT_NAME" && this->IsImported()) {
     std::ostringstream e;
     e << "EXPORT_NAME property can't be set on imported targets (\""
-      << impl->Name << "\")\n";
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << this->impl->Name << "\")\n";
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == "SOURCES" && this->IsImported()) {
     std::ostringstream e;
-    e << "SOURCES property can't be set on imported targets (\"" << impl->Name
-      << "\")\n";
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    e << "SOURCES property can't be set on imported targets (\""
+      << this->impl->Name << "\")\n";
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == "IMPORTED_GLOBAL") {
     std::ostringstream e;
     e << "IMPORTED_GLOBAL property can't be appended, only set on imported "
          "targets (\""
-      << impl->Name << "\")\n";
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      << this->impl->Name << "\")\n";
+    this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
     return;
   }
   if (prop == "INCLUDE_DIRECTORIES") {
     if (!value.empty()) {
-      impl->IncludeDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->IncludeDirectoriesBacktraces.push_back(lfbt);
+      this->impl->IncludeDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->IncludeDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_OPTIONS") {
     if (!value.empty()) {
-      impl->CompileOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->CompileOptionsBacktraces.push_back(lfbt);
+      this->impl->CompileOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->CompileOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_FEATURES") {
     if (!value.empty()) {
-      impl->CompileFeaturesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->CompileFeaturesBacktraces.push_back(lfbt);
+      this->impl->CompileFeaturesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->CompileFeaturesBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_DEFINITIONS") {
     if (!value.empty()) {
-      impl->CompileDefinitionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->CompileDefinitionsBacktraces.push_back(lfbt);
+      this->impl->CompileDefinitionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->CompileDefinitionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_OPTIONS") {
     if (!value.empty()) {
-      impl->LinkOptionsEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->LinkOptionsBacktraces.push_back(lfbt);
+      this->impl->LinkOptionsEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->LinkOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_DIRECTORIES") {
     if (!value.empty()) {
-      impl->LinkDirectoriesEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->LinkDirectoriesBacktraces.push_back(lfbt);
+      this->impl->LinkDirectoriesEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->LinkDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == "PRECOMPILE_HEADERS") {
     if (this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
       std::ostringstream e;
       e << "PRECOMPILE_HEADERS_REUSE_FROM property is already set on target "
            "(\""
-        << impl->Name << "\")\n";
-      impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+        << this->impl->Name << "\")\n";
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
       return;
     }
     if (!value.empty()) {
-      impl->PrecompileHeadersEntries.emplace_back(value);
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->PrecompileHeadersBacktraces.push_back(lfbt);
+      this->impl->PrecompileHeadersEntries.emplace_back(value);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->PrecompileHeadersBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_LIBRARIES") {
     if (!value.empty()) {
-      cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-      impl->LinkImplementationPropertyEntries.emplace_back(value);
-      impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
+      cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+      this->impl->LinkImplementationPropertyEntries.emplace_back(value);
+      this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
     }
   } else if (prop == "SOURCES") {
-    cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
-    impl->SourceEntries.emplace_back(value);
-    impl->SourceBacktraces.push_back(lfbt);
+    cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
+    this->impl->SourceEntries.emplace_back(value);
+    this->impl->SourceBacktraces.push_back(lfbt);
   } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
-                                 prop + " property may not be APPENDed.");
+    this->impl->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR, prop + " property may not be APPENDed.");
   } else if (prop == "C_STANDARD" || prop == "CXX_STANDARD" ||
              prop == "CUDA_STANDARD" || prop == "OBJC_STANDARD" ||
              prop == "OBJCXX_STANDARD") {
-    impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
-                                 prop + " property may not be appended.");
+    this->impl->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR, prop + " property may not be appended.");
   } else {
-    impl->Properties.AppendProperty(prop, value, asString);
+    this->impl->Properties.AppendProperty(prop, value, asString);
   }
 }
 
@@ -1462,17 +1477,17 @@ void cmTarget::AppendBuildInterfaceIncludes()
       !this->IsExecutableWithExports()) {
     return;
   }
-  if (impl->BuildInterfaceIncludesAppended) {
+  if (this->impl->BuildInterfaceIncludesAppended) {
     return;
   }
-  impl->BuildInterfaceIncludesAppended = true;
+  this->impl->BuildInterfaceIncludesAppended = true;
 
-  if (impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
-    std::string dirs = impl->Makefile->GetCurrentBinaryDirectory();
+  if (this->impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) {
+    std::string dirs = this->impl->Makefile->GetCurrentBinaryDirectory();
     if (!dirs.empty()) {
       dirs += ';';
     }
-    dirs += impl->Makefile->GetCurrentSourceDirectory();
+    dirs += this->impl->Makefile->GetCurrentSourceDirectory();
     if (!dirs.empty()) {
       this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
                            ("$<BUILD_INTERFACE:" + dirs + ">"));
@@ -1483,67 +1498,67 @@ void cmTarget::AppendBuildInterfaceIncludes()
 void cmTarget::InsertInclude(std::string const& entry,
                              cmListFileBacktrace const& bt, bool before)
 {
-  auto position = before ? impl->IncludeDirectoriesEntries.begin()
-                         : impl->IncludeDirectoriesEntries.end();
+  auto position = before ? this->impl->IncludeDirectoriesEntries.begin()
+                         : this->impl->IncludeDirectoriesEntries.end();
 
-  auto btPosition = before ? impl->IncludeDirectoriesBacktraces.begin()
-                           : impl->IncludeDirectoriesBacktraces.end();
+  auto btPosition = before ? this->impl->IncludeDirectoriesBacktraces.begin()
+                           : this->impl->IncludeDirectoriesBacktraces.end();
 
-  impl->IncludeDirectoriesEntries.insert(position, entry);
-  impl->IncludeDirectoriesBacktraces.insert(btPosition, bt);
+  this->impl->IncludeDirectoriesEntries.insert(position, entry);
+  this->impl->IncludeDirectoriesBacktraces.insert(btPosition, bt);
 }
 
 void cmTarget::InsertCompileOption(std::string const& entry,
                                    cmListFileBacktrace const& bt, bool before)
 {
-  auto position = before ? impl->CompileOptionsEntries.begin()
-                         : impl->CompileOptionsEntries.end();
+  auto position = before ? this->impl->CompileOptionsEntries.begin()
+                         : this->impl->CompileOptionsEntries.end();
 
-  auto btPosition = before ? impl->CompileOptionsBacktraces.begin()
-                           : impl->CompileOptionsBacktraces.end();
+  auto btPosition = before ? this->impl->CompileOptionsBacktraces.begin()
+                           : this->impl->CompileOptionsBacktraces.end();
 
-  impl->CompileOptionsEntries.insert(position, entry);
-  impl->CompileOptionsBacktraces.insert(btPosition, bt);
+  this->impl->CompileOptionsEntries.insert(position, entry);
+  this->impl->CompileOptionsBacktraces.insert(btPosition, bt);
 }
 
 void cmTarget::InsertCompileDefinition(std::string const& entry,
                                        cmListFileBacktrace const& bt)
 {
-  impl->CompileDefinitionsEntries.push_back(entry);
-  impl->CompileDefinitionsBacktraces.push_back(bt);
+  this->impl->CompileDefinitionsEntries.push_back(entry);
+  this->impl->CompileDefinitionsBacktraces.push_back(bt);
 }
 
 void cmTarget::InsertLinkOption(std::string const& entry,
                                 cmListFileBacktrace const& bt, bool before)
 {
-  auto position =
-    before ? impl->LinkOptionsEntries.begin() : impl->LinkOptionsEntries.end();
+  auto position = before ? this->impl->LinkOptionsEntries.begin()
+                         : this->impl->LinkOptionsEntries.end();
 
-  auto btPosition = before ? impl->LinkOptionsBacktraces.begin()
-                           : impl->LinkOptionsBacktraces.end();
+  auto btPosition = before ? this->impl->LinkOptionsBacktraces.begin()
+                           : this->impl->LinkOptionsBacktraces.end();
 
-  impl->LinkOptionsEntries.insert(position, entry);
-  impl->LinkOptionsBacktraces.insert(btPosition, bt);
+  this->impl->LinkOptionsEntries.insert(position, entry);
+  this->impl->LinkOptionsBacktraces.insert(btPosition, bt);
 }
 
 void cmTarget::InsertLinkDirectory(std::string const& entry,
                                    cmListFileBacktrace const& bt, bool before)
 {
-  auto position = before ? impl->LinkDirectoriesEntries.begin()
-                         : impl->LinkDirectoriesEntries.end();
+  auto position = before ? this->impl->LinkDirectoriesEntries.begin()
+                         : this->impl->LinkDirectoriesEntries.end();
 
-  auto btPosition = before ? impl->LinkDirectoriesBacktraces.begin()
-                           : impl->LinkDirectoriesBacktraces.end();
+  auto btPosition = before ? this->impl->LinkDirectoriesBacktraces.begin()
+                           : this->impl->LinkDirectoriesBacktraces.end();
 
-  impl->LinkDirectoriesEntries.insert(position, entry);
-  impl->LinkDirectoriesBacktraces.insert(btPosition, bt);
+  this->impl->LinkDirectoriesEntries.insert(position, entry);
+  this->impl->LinkDirectoriesBacktraces.insert(btPosition, bt);
 }
 
 void cmTarget::InsertPrecompileHeader(std::string const& entry,
                                       cmListFileBacktrace const& bt)
 {
-  impl->PrecompileHeadersEntries.push_back(entry);
-  impl->PrecompileHeadersBacktraces.push_back(bt);
+  this->impl->PrecompileHeadersEntries.push_back(entry);
+  this->impl->PrecompileHeadersBacktraces.push_back(bt);
 }
 
 static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
@@ -1712,19 +1727,19 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
     if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
         prop == propCUDA_STANDARD || prop == propOBJC_STANDARD ||
         prop == propOBJCXX_STANDARD) {
-      auto propertyIter = impl->LanguageStandardProperties.find(prop);
-      if (propertyIter == impl->LanguageStandardProperties.end()) {
+      auto propertyIter = this->impl->LanguageStandardProperties.find(prop);
+      if (propertyIter == this->impl->LanguageStandardProperties.end()) {
         return nullptr;
       }
       return &(propertyIter->second.Value);
     }
     if (prop == propLINK_LIBRARIES) {
-      if (impl->LinkImplementationPropertyEntries.empty()) {
+      if (this->impl->LinkImplementationPropertyEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->LinkImplementationPropertyEntries, ";");
+      output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";");
       return &output;
     }
     // the type property returns what type the target is
@@ -1732,70 +1747,71 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
       return &cmState::GetTargetTypeName(this->GetType());
     }
     if (prop == propINCLUDE_DIRECTORIES) {
-      if (impl->IncludeDirectoriesEntries.empty()) {
+      if (this->impl->IncludeDirectoriesEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->IncludeDirectoriesEntries, ";");
+      output = cmJoin(this->impl->IncludeDirectoriesEntries, ";");
       return &output;
     }
     if (prop == propCOMPILE_FEATURES) {
-      if (impl->CompileFeaturesEntries.empty()) {
+      if (this->impl->CompileFeaturesEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->CompileFeaturesEntries, ";");
+      output = cmJoin(this->impl->CompileFeaturesEntries, ";");
       return &output;
     }
     if (prop == propCOMPILE_OPTIONS) {
-      if (impl->CompileOptionsEntries.empty()) {
+      if (this->impl->CompileOptionsEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->CompileOptionsEntries, ";");
+      output = cmJoin(this->impl->CompileOptionsEntries, ";");
       return &output;
     }
     if (prop == propCOMPILE_DEFINITIONS) {
-      if (impl->CompileDefinitionsEntries.empty()) {
+      if (this->impl->CompileDefinitionsEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->CompileDefinitionsEntries, ";");
+      output = cmJoin(this->impl->CompileDefinitionsEntries, ";");
       return &output;
     }
     if (prop == propLINK_OPTIONS) {
-      if (impl->LinkOptionsEntries.empty()) {
+      if (this->impl->LinkOptionsEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->LinkOptionsEntries, ";");
+      output = cmJoin(this->impl->LinkOptionsEntries, ";");
       return &output;
     }
     if (prop == propLINK_DIRECTORIES) {
-      if (impl->LinkDirectoriesEntries.empty()) {
+      if (this->impl->LinkDirectoriesEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->LinkDirectoriesEntries, ";");
+      output = cmJoin(this->impl->LinkDirectoriesEntries, ";");
 
       return &output;
     }
     if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
-      if (impl->Utilities.empty()) {
+      if (this->impl->Utilities.empty()) {
         return nullptr;
       }
 
       static std::string output;
       static std::vector<std::string> utilities;
-      utilities.resize(impl->Utilities.size());
+      utilities.resize(this->impl->Utilities.size());
       std::transform(
-        impl->Utilities.cbegin(), impl->Utilities.cend(), utilities.begin(),
+        this->impl->Utilities.cbegin(), this->impl->Utilities.cend(),
+        utilities.begin(),
         [](const BT<std::pair<std::string, bool>>& item) -> std::string {
           return item.Value.first;
         });
@@ -1803,12 +1819,12 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
       return &output;
     }
     if (prop == propPRECOMPILE_HEADERS) {
-      if (impl->PrecompileHeadersEntries.empty()) {
+      if (this->impl->PrecompileHeadersEntries.empty()) {
         return nullptr;
       }
 
       static std::string output;
-      output = cmJoin(impl->PrecompileHeadersEntries, ";");
+      output = cmJoin(this->impl->PrecompileHeadersEntries, ";");
       return &output;
     }
     if (prop == propIMPORTED) {
@@ -1821,24 +1837,25 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
       return &this->GetName();
     }
     if (prop == propBINARY_DIR) {
-      return &impl->Makefile->GetStateSnapshot()
+      return &this->impl->Makefile->GetStateSnapshot()
                 .GetDirectory()
                 .GetCurrentBinary();
     }
     if (prop == propSOURCE_DIR) {
-      return &impl->Makefile->GetStateSnapshot()
+      return &this->impl->Makefile->GetStateSnapshot()
                 .GetDirectory()
                 .GetCurrentSource();
     }
   }
 
-  cmProp retVal = impl->Properties.GetPropertyValue(prop);
+  cmProp retVal = this->impl->Properties.GetPropertyValue(prop);
   if (!retVal) {
-    const bool chain =
-      impl->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TARGET);
+    const bool chain = this->impl->Makefile->GetState()->IsPropertyChained(
+      prop, cmProperty::TARGET);
     if (chain) {
-      return impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
-        prop, chain);
+      return this->impl->Makefile->GetStateSnapshot()
+        .GetDirectory()
+        .GetProperty(prop, chain);
     }
     return nullptr;
   }
@@ -1863,32 +1880,32 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const
 
 cmPropertyMap const& cmTarget::GetProperties() const
 {
-  return impl->Properties;
+  return this->impl->Properties;
 }
 
 bool cmTarget::IsDLLPlatform() const
 {
-  return impl->IsDLLPlatform;
+  return this->impl->IsDLLPlatform;
 }
 
 bool cmTarget::IsAIX() const
 {
-  return impl->IsAIX;
+  return this->impl->IsAIX;
 }
 
 bool cmTarget::IsImported() const
 {
-  return impl->IsImportedTarget;
+  return this->impl->IsImportedTarget;
 }
 
 bool cmTarget::IsImportedGloballyVisible() const
 {
-  return impl->ImportedGloballyVisible;
+  return this->impl->ImportedGloballyVisible;
 }
 
 bool cmTarget::IsPerConfig() const
 {
-  return impl->PerConfig;
+  return this->impl->PerConfig;
 }
 
 bool cmTarget::CanCompileSources() const
@@ -1943,8 +1960,8 @@ const char* cmTarget::GetSuffixVariableInternal(
                     ? "CMAKE_SHARED_LIBRARY_SUFFIX"
                     : "CMAKE_EXECUTABLE_SUFFIX");
         case cmStateEnums::ImportLibraryArtifact:
-          return (impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_SUFFIX"
-                              : "CMAKE_IMPORT_LIBRARY_SUFFIX");
+          return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_SUFFIX"
+                                    : "CMAKE_IMPORT_LIBRARY_SUFFIX");
       }
       break;
     default:
@@ -1984,8 +2001,8 @@ const char* cmTarget::GetPrefixVariableInternal(
                     ? "CMAKE_SHARED_LIBRARY_PREFIX"
                     : "");
         case cmStateEnums::ImportLibraryArtifact:
-          return (impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_PREFIX"
-                              : "CMAKE_IMPORT_LIBRARY_PREFIX");
+          return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_PREFIX"
+                                    : "CMAKE_IMPORT_LIBRARY_PREFIX");
       }
       break;
     default:
@@ -2067,7 +2084,7 @@ std::string cmTarget::ImportedGetFullPath(
 
       switch (this->GetPolicyStatus(cmPolicies::CMP0111)) {
         case cmPolicies::WARN:
-          impl->Makefile->IssueMessage(
+          this->impl->Makefile->IssueMessage(
             MessageType::AUTHOR_WARNING,
             cmPolicies::GetPolicyWarning(cmPolicies::CMP0111) + "\n" +
               message());
@@ -2075,7 +2092,8 @@ std::string cmTarget::ImportedGetFullPath(
         case cmPolicies::OLD:
           break;
         default:
-          impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, message());
+          this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                             message());
       }
     }
 
index d8f66bc..30d9f5d 100644 (file)
@@ -114,7 +114,7 @@ public:
   LinkLibraryVectorType const& GetOriginalLinkLibraries() const;
 
   //! Clear the dependency information recorded for this target, if any.
-  void ClearDependencyInformation(cmMakefile& mf);
+  void ClearDependencyInformation(cmMakefile& mf) const;
 
   void AddLinkLibrary(cmMakefile& mf, std::string const& lib,
                       cmTargetLinkLibraryType llt);
@@ -164,6 +164,7 @@ public:
    */
   void AddUtility(std::string const& name, bool cross,
                   cmMakefile* mf = nullptr);
+  void AddUtility(BT<std::pair<std::string, bool>> util);
   //! Get the utilities used by this target
   std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
 
@@ -171,7 +172,7 @@ public:
   void SetProperty(const std::string& prop, const char* value);
   void SetProperty(const std::string& prop, const std::string& value)
   {
-    SetProperty(prop, value.c_str());
+    this->SetProperty(prop, value.c_str());
   }
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
@@ -287,6 +288,5 @@ private:
   const char* GetPrefixVariableInternal(
     cmStateEnums::ArtifactType artifact) const;
 
-private:
   std::unique_ptr<cmTargetInternals> impl;
 };
index 35635b9..3897499 100644 (file)
@@ -84,8 +84,8 @@ void TargetIncludeDirectoriesImpl::HandleInterfaceContent(
   cmTarget* tgt, const std::vector<std::string>& content, bool prepend,
   bool system)
 {
-  cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, prepend,
-                                                  system);
+  this->cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, prepend,
+                                                        system);
   if (system) {
     std::string joined = this->Join(content);
     tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined);
@@ -101,5 +101,6 @@ bool cmTargetIncludeDirectoriesCommand(std::vector<std::string> const& args,
     args, "INCLUDE_DIRECTORIES",
     TargetIncludeDirectoriesImpl::ArgumentFlags(
       TargetIncludeDirectoriesImpl::PROCESS_BEFORE |
+      TargetIncludeDirectoriesImpl::PROCESS_AFTER |
       TargetIncludeDirectoriesImpl::PROCESS_SYSTEM));
 }
index 0670bd9..a5066cc 100644 (file)
@@ -57,7 +57,7 @@ private:
                               bool prepend, bool system) override
   {
     std::string const& base = this->Makefile->GetCurrentSourceDirectory();
-    cmTargetPropCommandBase::HandleInterfaceContent(
+    this->cmTargetPropCommandBase::HandleInterfaceContent(
       tgt, ConvertToAbsoluteContent(content, base), prepend, system);
   }
 
index 9e30136..e41714a 100644 (file)
@@ -45,15 +45,26 @@ bool cmTargetPropCommandBase::HandleArguments(
     this->HandleMissingTarget(args[0]);
     return false;
   }
-  if ((this->Target->GetType() != cmStateEnums::EXECUTABLE) &&
-      (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) &&
-      (this->Target->GetType() != cmStateEnums::SHARED_LIBRARY) &&
-      (this->Target->GetType() != cmStateEnums::MODULE_LIBRARY) &&
-      (this->Target->GetType() != cmStateEnums::OBJECT_LIBRARY) &&
-      (this->Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
-      (this->Target->GetType() != cmStateEnums::UNKNOWN_LIBRARY)) {
-    this->SetError("called with non-compilable target type");
-    return false;
+  const bool isRegularTarget =
+    (this->Target->GetType() == cmStateEnums::EXECUTABLE) ||
+    (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
+    (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
+    (this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) ||
+    (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
+    (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) ||
+    (this->Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY);
+  const bool isCustomTarget = this->Target->GetType() == cmStateEnums::UTILITY;
+
+  if (prop == "SOURCES") {
+    if (!isRegularTarget && !isCustomTarget) {
+      this->SetError("called with non-compilable target type");
+      return false;
+    }
+  } else {
+    if (!isRegularTarget) {
+      this->SetError("called with non-compilable target type");
+      return false;
+    }
   }
 
   bool system = false;
@@ -76,6 +87,13 @@ bool cmTargetPropCommandBase::HandleArguments(
     }
     prepend = true;
     ++argIndex;
+  } else if ((flags & PROCESS_AFTER) && args[argIndex] == "AFTER") {
+    if (args.size() < 3) {
+      this->SetError("called with incorrect number of arguments");
+      return false;
+    }
+    prepend = false;
+    ++argIndex;
   }
 
   if ((flags & PROCESS_REUSE_FROM) && args[argIndex] == "REUSE_FROM") {
@@ -131,6 +149,11 @@ bool cmTargetPropCommandBase::ProcessContentArgs(
       this->SetError("may only set INTERFACE properties on IMPORTED targets");
       return false;
     }
+    if (this->Target->GetType() == cmStateEnums::UTILITY &&
+        scope != "PRIVATE") {
+      this->SetError("may only set PRIVATE properties on custom targets");
+      return false;
+    }
   }
   return this->PopulateTargetProperies(scope, content, prepend, system);
 }
index 50ac1aa..fc24fe8 100644 (file)
@@ -23,8 +23,9 @@ public:
   {
     NO_FLAGS = 0x0,
     PROCESS_BEFORE = 0x1,
-    PROCESS_SYSTEM = 0x2,
-    PROCESS_REUSE_FROM = 0x3
+    PROCESS_AFTER = 0x2,
+    PROCESS_SYSTEM = 0x3,
+    PROCESS_REUSE_FROM = 0x4
   };
 
   bool HandleArguments(std::vector<std::string> const& args,
index a1fbc9b..26282ef 100644 (file)
@@ -25,8 +25,9 @@ protected:
                               const std::vector<std::string>& content,
                               bool prepend, bool system) override
   {
-    cmTargetPropCommandBase::HandleInterfaceContent(
-      tgt, ConvertToAbsoluteContent(tgt, content, true), prepend, system);
+    this->cmTargetPropCommandBase::HandleInterfaceContent(
+      tgt, this->ConvertToAbsoluteContent(tgt, content, true), prepend,
+      system);
   }
 
 private:
@@ -43,7 +44,8 @@ private:
                            bool /*prepend*/, bool /*system*/) override
   {
     tgt->AppendProperty(
-      "SOURCES", this->Join(ConvertToAbsoluteContent(tgt, content, false)));
+      "SOURCES",
+      this->Join(this->ConvertToAbsoluteContent(tgt, content, false)));
     return true; // Successfully handled.
   }
 
index da4593f..7022c4e 100644 (file)
@@ -147,7 +147,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
 
   // Evaluate command line arguments
   std::vector<std::string> argv =
-    EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config);
+    this->EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config);
 
   // Expand arguments if COMMAND_EXPAND_LISTS is set
   if (this->Test->GetCommandExpandLists()) {
index 67f7e11..b016530 100644 (file)
@@ -3,11 +3,13 @@
 
 #if !defined(_WIN32) && !defined(__sun)
 // POSIX APIs are needed
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _POSIX_C_SOURCE 200809L
 #endif
 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
   defined(__QNX__)
 // For isascii
+// NOLINTNEXTLINE(bugprone-reserved-identifier)
 #  define _XOPEN_SOURCE 700
 #endif
 
@@ -21,7 +23,7 @@
 #include "cmSystemTools.h"
 
 std::string cmTimestamp::CurrentTime(const std::string& formatString,
-                                     bool utcFlag)
+                                     bool utcFlag) const
 {
   time_t currentTimeT = time(nullptr);
   std::string source_date_epoch;
@@ -38,12 +40,12 @@ std::string cmTimestamp::CurrentTime(const std::string& formatString,
     return std::string();
   }
 
-  return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
+  return this->CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag);
 }
 
 std::string cmTimestamp::FileModificationTime(const char* path,
                                               const std::string& formatString,
-                                              bool utcFlag)
+                                              bool utcFlag) const
 {
   std::string real_path =
     cmSystemTools::GetRealPathResolvingWindowsSubst(path);
@@ -53,7 +55,7 @@ std::string cmTimestamp::FileModificationTime(const char* path,
   }
 
   time_t mtime = cmsys::SystemTools::ModifiedTime(real_path);
-  return CreateTimestampFromTimeT(mtime, formatString, utcFlag);
+  return this->CreateTimestampFromTimeT(mtime, formatString, utcFlag);
 }
 
 std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
@@ -90,7 +92,7 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
                                             : static_cast<char>(0);
 
     if (c1 == '%' && c2 != 0) {
-      result += AddTimestampComponent(c2, timeStruct, timeT);
+      result += this->AddTimestampComponent(c2, timeStruct, timeT);
       ++i;
     } else {
       result += c1;
index 8941abe..0e2c200 100644 (file)
 class cmTimestamp
 {
 public:
-  std::string CurrentTime(const std::string& formatString, bool utcFlag);
+  std::string CurrentTime(const std::string& formatString, bool utcFlag) const;
 
   std::string FileModificationTime(const char* path,
                                    const std::string& formatString,
-                                   bool utcFlag);
+                                   bool utcFlag) const;
 
   std::string CreateTimestampFromTimeT(time_t timeT, std::string formatString,
                                        bool utcFlag) const;
diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx
new file mode 100644 (file)
index 0000000..78aa4b2
--- /dev/null
@@ -0,0 +1,122 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmTransformDepfile.h"
+
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h"
+#include "cmLocalGenerator.h"
+#include "cmSystemTools.h"
+
+namespace {
+void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename)
+{
+  for (auto c : filename) {
+    switch (c) {
+      case ' ':
+        fout << "\\ ";
+        break;
+      case '\\':
+        fout << "\\\\";
+        break;
+      default:
+        fout << c;
+        break;
+    }
+  }
+}
+
+void WriteGccDepfile(cmsys::ofstream& fout, const cmLocalGenerator& lg,
+                     const cmGccDepfileContent& content)
+{
+  const auto& binDir = lg.GetBinaryDirectory();
+
+  for (auto const& dep : content) {
+    bool first = true;
+    for (auto const& rule : dep.rules) {
+      if (!first) {
+        fout << " \\\n  ";
+      }
+      first = false;
+      WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, rule));
+    }
+    fout << ':';
+    for (auto const& path : dep.paths) {
+      fout << " \\\n  ";
+      WriteFilenameGcc(fout, lg.MaybeConvertToRelativePath(binDir, path));
+    }
+    fout << '\n';
+  }
+}
+
+// tlog format : always windows paths on Windows regardless the generator
+std::string ConvertToTLogOutputPath(const std::string& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  return cmSystemTools::ConvertToWindowsOutputPath(path);
+#else
+  return cmSystemTools::ConvertToOutputPath(path);
+#endif
+}
+
+void WriteVsTlog(cmsys::ofstream& fout, const cmLocalGenerator& lg,
+                 const cmGccDepfileContent& content)
+{
+  const auto& binDir = lg.GetBinaryDirectory();
+
+  for (auto const& dep : content) {
+    fout << '^';
+    bool first = true;
+    for (auto const& rule : dep.rules) {
+      if (!first) {
+        fout << '|';
+      }
+      first = false;
+      fout << ConvertToTLogOutputPath(
+        lg.MaybeConvertToRelativePath(binDir, rule));
+    }
+    fout << "\r\n";
+    for (auto const& path : dep.paths) {
+      fout << ConvertToTLogOutputPath(
+                lg.MaybeConvertToRelativePath(binDir, path))
+           << "\r\n";
+    }
+  }
+}
+}
+
+bool cmTransformDepfile(cmDepfileFormat format, const cmLocalGenerator& lg,
+                        const std::string& infile, const std::string& outfile)
+{
+  cmGccDepfileContent content;
+  if (cmSystemTools::FileExists(infile)) {
+    auto result =
+      cmReadGccDepfile(infile.c_str(), lg.GetCurrentBinaryDirectory());
+    if (!result) {
+      return false;
+    }
+    content = *std::move(result);
+  }
+
+  cmsys::ofstream fout(outfile.c_str());
+  if (!fout) {
+    return false;
+  }
+  switch (format) {
+    case cmDepfileFormat::GccDepfile:
+      WriteGccDepfile(fout, lg, content);
+      break;
+    case cmDepfileFormat::VsTlog:
+      WriteVsTlog(fout, lg, content);
+      break;
+  }
+  return true;
+}
diff --git a/Source/cmTransformDepfile.h b/Source/cmTransformDepfile.h
new file mode 100644 (file)
index 0000000..c43a45f
--- /dev/null
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <string>
+
+enum class cmDepfileFormat
+{
+  GccDepfile,
+  VsTlog,
+};
+
+class cmLocalGenerator;
+
+bool cmTransformDepfile(cmDepfileFormat format, const cmLocalGenerator& lg,
+                        const std::string& infile, const std::string& outfile);
index 3f89641..8cac74d 100644 (file)
@@ -84,6 +84,14 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
         }
         i++;
         this->CompileOutputVariable = argv[i];
+      } else if (argv[i] == "WORKING_DIRECTORY") {
+        if (argv.size() <= (i + 1)) {
+          cmSystemTools::Error(
+            "WORKING_DIRECTORY specified but there is no variable");
+          return false;
+        }
+        i++;
+        this->WorkingDirectory = argv[i];
       } else {
         tryCompile.push_back(argv[i]);
       }
@@ -102,6 +110,14 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv,
     return false;
   }
 
+  if (!this->WorkingDirectory.empty()) {
+    if (!cmSystemTools::MakeDirectory(this->WorkingDirectory)) {
+      cmSystemTools::Error(cmStrCat("Error creating working directory \"",
+                                    this->WorkingDirectory, "\"."));
+      return false;
+    }
+  }
+
   bool captureRunOutput = false;
   if (!this->OutputVariable.empty()) {
     captureRunOutput = true;
@@ -188,8 +204,9 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs,
     finalCommand += runArgs;
   }
   bool worked = cmSystemTools::RunSingleCommand(
-    finalCommand, out, out, &retVal, nullptr, cmSystemTools::OUTPUT_NONE,
-    cmDuration::zero());
+    finalCommand, out, out, &retVal,
+    this->WorkingDirectory.empty() ? nullptr : this->WorkingDirectory.c_str(),
+    cmSystemTools::OUTPUT_NONE, cmDuration::zero());
   // set the run var
   char retChar[16];
   const char* retStr;
index 070c63c..d45acd8 100644 (file)
@@ -49,4 +49,5 @@ private:
   std::string OutputVariable;
   std::string RunOutputVariable;
   std::string CompileOutputVariable;
+  std::string WorkingDirectory;
 };
index df2f64e..8ea1942 100644 (file)
@@ -59,7 +59,7 @@ uv_loop_t* uv_loop_ptr::get() const
 template <typename T>
 static void handle_default_delete(T* type_handle)
 {
-  auto handle = reinterpret_cast<uv_handle_t*>(type_handle);
+  auto* handle = reinterpret_cast<uv_handle_t*>(type_handle);
   if (handle) {
     assert(!uv_is_closing(handle));
     if (!uv_is_closing(handle)) {
@@ -80,7 +80,7 @@ struct uv_handle_deleter
 template <typename T>
 void uv_handle_ptr_base_<T>::allocate(void* data)
 {
-  reset();
+  this->reset();
 
   /*
     We use calloc since we know all these types are c structs
@@ -88,32 +88,33 @@ void uv_handle_ptr_base_<T>::allocate(void* data)
     but casting from uv_handle_t to certain other types -- namely
     uv_timer_t -- triggers a cast_align warning on certain systems.
   */
-  handle.reset(static_cast<T*>(calloc(1, sizeof(T))), uv_handle_deleter<T>());
-  handle->data = data;
+  this->handle.reset(static_cast<T*>(calloc(1, sizeof(T))),
+                     uv_handle_deleter<T>());
+  this->handle->data = data;
 }
 
 template <typename T>
 void uv_handle_ptr_base_<T>::reset()
 {
-  handle.reset();
+  this->handle.reset();
 }
 
 template <typename T>
 uv_handle_ptr_base_<T>::operator uv_handle_t*()
 {
-  return reinterpret_cast<uv_handle_t*>(handle.get());
+  return reinterpret_cast<uv_handle_t*>(this->handle.get());
 }
 
 template <typename T>
 T* uv_handle_ptr_base_<T>::operator->() const noexcept
 {
-  return handle.get();
+  return this->handle.get();
 }
 
 template <typename T>
 T* uv_handle_ptr_base_<T>::get() const
 {
-  return handle.get();
+  return this->handle.get();
 }
 
 template <typename T>
@@ -146,14 +147,15 @@ struct uv_handle_deleter<uv_async_t>
 
   void operator()(uv_async_t* handle)
   {
-    std::lock_guard<std::mutex> lock(*handleMutex);
+    std::lock_guard<std::mutex> lock(*this->handleMutex);
     handle_default_delete(handle);
   }
 };
 
 void uv_async_ptr::send()
 {
-  auto deleter = std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle);
+  auto* deleter =
+    std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle);
   assert(deleter);
 
   std::lock_guard<std::mutex> lock(*deleter->handleMutex);
@@ -164,8 +166,8 @@ void uv_async_ptr::send()
 
 int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data)
 {
-  allocate(data);
-  return uv_async_init(&loop, handle.get(), async_cb);
+  this->allocate(data);
+  return uv_async_init(&loop, this->handle.get(), async_cb);
 }
 #endif
 
@@ -183,62 +185,62 @@ struct uv_handle_deleter<uv_signal_t>
 
 int uv_signal_ptr::init(uv_loop_t& loop, void* data)
 {
-  allocate(data);
-  return uv_signal_init(&loop, handle.get());
+  this->allocate(data);
+  return uv_signal_init(&loop, this->handle.get());
 }
 
 int uv_signal_ptr::start(uv_signal_cb cb, int signum)
 {
-  assert(handle);
+  assert(this->handle);
   return uv_signal_start(*this, cb, signum);
 }
 
 void uv_signal_ptr::stop()
 {
-  if (handle) {
+  if (this->handle) {
     uv_signal_stop(*this);
   }
 }
 
 int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data)
 {
-  allocate(data);
+  this->allocate(data);
   return uv_pipe_init(&loop, *this, ipc);
 }
 
 uv_pipe_ptr::operator uv_stream_t*() const
 {
-  return reinterpret_cast<uv_stream_t*>(handle.get());
+  return reinterpret_cast<uv_stream_t*>(this->handle.get());
 }
 
 int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options,
                           void* data)
 {
-  allocate(data);
+  this->allocate(data);
   return uv_spawn(&loop, *this, &options);
 }
 
 int uv_timer_ptr::init(uv_loop_t& loop, void* data)
 {
-  allocate(data);
+  this->allocate(data);
   return uv_timer_init(&loop, *this);
 }
 
 int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
 {
-  assert(handle);
+  assert(this->handle);
   return uv_timer_start(*this, cb, timeout, repeat);
 }
 
 #ifndef CMAKE_BOOTSTRAP
 uv_tty_ptr::operator uv_stream_t*() const
 {
-  return reinterpret_cast<uv_stream_t*>(handle.get());
+  return reinterpret_cast<uv_stream_t*>(this->handle.get());
 }
 
 int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data)
 {
-  allocate(data);
+  this->allocate(data);
   return uv_tty_init(&loop, *this, fd, readable);
 }
 #endif
index d9de7f3..8c5ad59 100644 (file)
@@ -78,7 +78,7 @@ template <typename T>
 class uv_handle_ptr_base_
 {
 protected:
-  template <typename _T>
+  template <typename U>
   friend class uv_handle_ptr_base_;
 
   /**
@@ -128,7 +128,7 @@ public:
   // dtors to work.  Some compilers do not like '= default' here.
   uv_handle_ptr_base_() {} // NOLINT(modernize-use-equals-default)
   uv_handle_ptr_base_(std::nullptr_t) {}
-  ~uv_handle_ptr_base_() { reset(); }
+  ~uv_handle_ptr_base_() { this->reset(); }
 
   /**
    * Properly close the handle if needed and sets the inner handle to nullptr
@@ -160,7 +160,7 @@ inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=(
 template <typename T>
 class uv_handle_ptr_ : public uv_handle_ptr_base_<T>
 {
-  template <typename _T>
+  template <typename U>
   friend class uv_handle_ptr_;
 
 public:
index cd52b3f..2513303 100644 (file)
@@ -82,7 +82,7 @@ bool cmUuid::StringToBinary(std::string const& input,
       return false;
     }
     size_t digits = kUuidGroups[i] * 2;
-    if (!StringToBinaryImpl(input.substr(index, digits), output)) {
+    if (!this->StringToBinaryImpl(input.substr(index, digits), output)) {
       return false;
     }
 
@@ -134,12 +134,12 @@ bool cmUuid::StringToBinaryImpl(std::string const& input,
 
   for (size_t i = 0; i < input.size(); i += 2) {
     char c1 = 0;
-    if (!IntFromHexDigit(input[i], c1)) {
+    if (!this->IntFromHexDigit(input[i], c1)) {
       return false;
     }
 
     char c2 = 0;
-    if (!IntFromHexDigit(input[i + 1], c2)) {
+    if (!this->IntFromHexDigit(input[i + 1], c2)) {
       return false;
     }
 
index 9072c9f..456428c 100644 (file)
@@ -24,8 +24,8 @@ public:
 
 /* Encode with room for up to 1000 minor releases between major releases
    and to encode dates until the year 10000 in the patch level.  */
-#define CMake_VERSION_ENCODE__BASE KWIML_INT_UINT64_C(100000000)
+#define CMake_VERSION_ENCODE_BASE KWIML_INT_UINT64_C(100000000)
 #define CMake_VERSION_ENCODE(major, minor, patch)                             \
-  ((((major)*1000u) * CMake_VERSION_ENCODE__BASE) +                           \
-   (((minor) % 1000u) * CMake_VERSION_ENCODE__BASE) +                         \
-   (((patch) % CMake_VERSION_ENCODE__BASE)))
+  ((((major)*1000u) * CMake_VERSION_ENCODE_BASE) +                            \
+   (((minor) % 1000u) * CMake_VERSION_ENCODE_BASE) +                          \
+   (((patch) % CMake_VERSION_ENCODE_BASE)))
index 489e42d..965ac3e 100644 (file)
@@ -676,7 +676,7 @@ void cmVisualStudio10TargetGenerator::Generate()
           cmStrCat(this->DefaultArtifactDir, "\\nasm.props");
         ConvertToWindowsSlash(propsLocal);
         this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true,
-                                      true, true);
+                                      true);
         Elem(e1, "Import").Attribute("Project", propsLocal);
       }
     }
@@ -1020,9 +1020,9 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
             cm::string_view tagName =
               cm::string_view(p).substr(propNamePrefix.length());
             if (!tagName.empty()) {
-              const std::string& value = *props.GetPropertyValue(p);
-              if (!value.empty()) {
-                e2.Element(tagName, value);
+              cmProp value = props.GetPropertyValue(p);
+              if (cmNonempty(value)) {
+                e2.Element(tagName, *value);
               }
             }
           }
@@ -1897,8 +1897,15 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
     }
     // Figure out if there's any additional flags to use
     if (cmProp saf = sf->GetProperty("VS_SHADER_FLAGS")) {
+      cmGeneratorExpression ge;
+      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*saf);
+
       for (const std::string& config : this->Configurations) {
-        toolSettings[config]["AdditionalOptions"] = *saf;
+        std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+        if (!evaluated.empty()) {
+          toolSettings[config]["AdditionalOptions"] = evaluated;
+        }
       }
     }
     // Figure out if debug information should be generated
@@ -2402,27 +2409,30 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
       configDefines += *ccdefs;
     }
 
-    // Add precompile headers compile options.
-    std::string customAndPchOptions = options;
-    const std::string pchSource =
+    // We have pch state in the following situation:
+    // 1. We have SKIP_PRECOMPILE_HEADERS == true
+    // 2. We are creating the pre-compiled header
+    // 3. We are a different language than the linker language AND pch is
+    //    enabled.
+    std::string const& linkLanguage =
+      this->GeneratorTarget->GetLinkerLanguage(config);
+    std::string const& pchSource =
       this->GeneratorTarget->GetPchSource(config, lang);
-    if (!pchSource.empty() && !sf.GetProperty("SKIP_PRECOMPILE_HEADERS")) {
-      std::string pchOptions;
-      if (sf.GetFullPath() == pchSource) {
-        pchOptions =
-          this->GeneratorTarget->GetPchCreateCompileOptions(config, lang);
-      } else {
-        pchOptions =
-          this->GeneratorTarget->GetPchUseCompileOptions(config, lang);
-      }
-      customAndPchOptions = cmStrCat(customAndPchOptions, ';', pchOptions);
-    }
+    const bool skipPCH =
+      pchSource.empty() || sf.GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS");
+    const bool makePCH = (sf.GetFullPath() == pchSource);
+    const bool useSharedPCH = !skipPCH && (lang == linkLanguage);
+    const bool useDifferentLangPCH = !skipPCH && (lang != linkLanguage);
+    const bool useNoPCH = skipPCH && (lang != linkLanguage) &&
+      !this->GeneratorTarget->GetPchHeader(config, linkLanguage).empty();
+    const bool needsPCHFlags =
+      (makePCH || useSharedPCH || useDifferentLangPCH || useNoPCH);
 
     // if we have flags or defines for this config then
     // use them
     if (!flags.empty() || !options.empty() || !configDefines.empty() ||
-        !includes.empty() || compileAs || noWinRT ||
-        !customAndPchOptions.empty()) {
+        !includes.empty() || compileAs || noWinRT || !options.empty() ||
+        needsPCHFlags) {
       cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
       cmIDEFlagTable const* flagtable = nullptr;
       const std::string& srclang = source->GetLanguage();
@@ -2455,15 +2465,37 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
       } else {
         clOptions.Parse(flags);
       }
-      if (!customAndPchOptions.empty()) {
+
+      if (needsPCHFlags) {
+        // Add precompile headers compile options.
+        std::string expandedOptions;
+        std::string pchOptions;
+        if (makePCH) {
+          pchOptions =
+            this->GeneratorTarget->GetPchCreateCompileOptions(config, lang);
+        } else if (useNoPCH) {
+          clOptions.AddFlag("PrecompiledHeader", "NotUsing");
+        } else if (useSharedPCH) {
+          std::string pchHeader =
+            this->GeneratorTarget->GetPchHeader(config, lang);
+          clOptions.AddFlag("ForcedIncludeFiles", pchHeader);
+        } else if (useDifferentLangPCH) {
+          pchOptions =
+            this->GeneratorTarget->GetPchUseCompileOptions(config, lang);
+        }
+        this->LocalGenerator->AppendCompileOptions(expandedOptions,
+                                                   pchOptions);
+        clOptions.Parse(expandedOptions);
+      }
+
+      if (!options.empty()) {
         std::string expandedOptions;
         if (configDependentOptions) {
           this->LocalGenerator->AppendCompileOptions(
             expandedOptions,
-            genexInterpreter.Evaluate(customAndPchOptions, "COMPILE_OPTIONS"));
+            genexInterpreter.Evaluate(options, "COMPILE_OPTIONS"));
         } else {
-          this->LocalGenerator->AppendCompileOptions(expandedOptions,
-                                                     customAndPchOptions);
+          this->LocalGenerator->AppendCompileOptions(expandedOptions, options);
         }
         clOptions.Parse(expandedOptions);
       }
@@ -2786,6 +2818,13 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
     this->GeneratorTarget->GetPchHeader(configName, linkLanguage);
   if (this->MSTools && vcxproj == this->ProjectType && pchHeader.empty()) {
     clOptions.AddFlag("PrecompiledHeader", "NotUsing");
+  } else if (this->MSTools && vcxproj == this->ProjectType &&
+             !pchHeader.empty()) {
+    clOptions.AddFlag("PrecompiledHeader", "Use");
+    clOptions.AddFlag("PrecompiledHeaderFile", pchHeader);
+    std::string pchFile =
+      this->GeneratorTarget->GetPchFile(configName, linkLanguage);
+    clOptions.AddFlag("PrecompiledHeaderOutputFile", pchFile);
   }
 
   // Get preprocessor definitions for this directory.
@@ -4183,8 +4222,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0)
     cmLocalGenerator* lg = dt->GetLocalGenerator();
     std::string name = dt->GetName();
     std::string path;
-    cmProp p = dt->GetProperty("EXTERNAL_MSPROJECT");
-    if (p) {
+    if (cmProp p = dt->GetProperty("EXTERNAL_MSPROJECT")) {
       path = *p;
     } else {
       path = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', dt->GetName(),
@@ -4972,9 +5010,9 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties(
       if (cmHasPrefix(p, propNamePrefix)) {
         std::string tagName = p.substr(propNamePrefix.length());
         if (!tagName.empty()) {
-          const std::string& val = *props.GetPropertyValue(p);
-          if (!val.empty()) {
-            tags[tagName] = val;
+          cmProp val = props.GetPropertyValue(p);
+          if (cmNonempty(val)) {
+            tags[tagName] = *val;
           } else {
             tags.erase(tagName);
           }
index 12aba4f..1d15c27 100644 (file)
@@ -31,7 +31,6 @@ public:
   /// On error the ssize_t argument is a non zero libuv error code
   using EndFunction = std::function<void(ssize_t)>;
 
-public:
   /**
    * Reset to construction state
    */
@@ -50,11 +49,14 @@ public:
   bool startRead(DataFunction dataFunction, EndFunction endFunction);
 
   //! libuv pipe
-  uv_pipe_t* uv_pipe() const { return UVPipe_.get(); }
+  uv_pipe_t* uv_pipe() const { return this->UVPipe_.get(); }
   //! uv_pipe() casted to libuv stream
-  uv_stream_t* uv_stream() const { return static_cast<uv_stream_t*>(UVPipe_); }
+  uv_stream_t* uv_stream() const
+  {
+    return static_cast<uv_stream_t*>(this->UVPipe_);
+  }
   //! uv_pipe() casted to libuv handle
-  uv_handle_t* uv_handle() { return static_cast<uv_handle_t*>(UVPipe_); }
+  uv_handle_t* uv_handle() { return static_cast<uv_handle_t*>(this->UVPipe_); }
 
 private:
   // -- Libuv callbacks
@@ -62,7 +64,6 @@ private:
                       uv_buf_t* buf);
   static void UVData(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
 
-private:
   cm::uv_pipe_ptr UVPipe_;
   std::vector<char> Buffer_;
   DataFunction DataFunction_;
@@ -71,37 +72,37 @@ private:
 
 void cmUVPipeBuffer::reset()
 {
-  if (UVPipe_.get() != nullptr) {
-    EndFunction_ = nullptr;
-    DataFunction_ = nullptr;
-    Buffer_.clear();
-    Buffer_.shrink_to_fit();
-    UVPipe_.reset();
+  if (this->UVPipe_.get() != nullptr) {
+    this->EndFunction_ = nullptr;
+    this->DataFunction_ = nullptr;
+    this->Buffer_.clear();
+    this->Buffer_.shrink_to_fit();
+    this->UVPipe_.reset();
   }
 }
 
 bool cmUVPipeBuffer::init(uv_loop_t* uv_loop)
 {
-  reset();
+  this->reset();
   if (uv_loop == nullptr) {
     return false;
   }
-  int ret = UVPipe_.init(*uv_loop, 0, this);
+  int ret = this->UVPipe_.init(*uv_loop, 0, this);
   return (ret == 0);
 }
 
 bool cmUVPipeBuffer::startRead(DataFunction dataFunction,
                                EndFunction endFunction)
 {
-  if (UVPipe_.get() == nullptr) {
+  if (this->UVPipe_.get() == nullptr) {
     return false;
   }
   if (!dataFunction || !endFunction) {
     return false;
   }
-  DataFunction_ = std::move(dataFunction);
-  EndFunction_ = std::move(endFunction);
-  int ret = uv_read_start(uv_stream(), &cmUVPipeBuffer::UVAlloc,
+  this->DataFunction_ = std::move(dataFunction);
+  this->EndFunction_ = std::move(endFunction);
+  int ret = uv_read_start(this->uv_stream(), &cmUVPipeBuffer::UVAlloc,
                           &cmUVPipeBuffer::UVData);
   return (ret == 0);
 }
@@ -151,12 +152,11 @@ public:
     bool MergedOutput = false;
   };
 
-public:
   // -- Const accessors
-  SetupT const& Setup() const { return Setup_; }
-  cmWorkerPool::ProcessResultT* Result() const { return Setup_.Result; }
-  bool IsStarted() const { return IsStarted_; }
-  bool IsFinished() const { return IsFinished_; }
+  SetupT const& Setup() const { return this->Setup_; }
+  cmWorkerPool::ProcessResultT* Result() const { return this->Setup_.Result; }
+  bool IsStarted() const { return this->IsStarted_; }
+  bool IsFinished() const { return this->IsFinished_; }
 
   // -- Runtime
   void setup(cmWorkerPool::ProcessResultT* result, bool mergedOutput,
@@ -167,13 +167,12 @@ public:
 private:
   // -- Libuv callbacks
   static void UVExit(uv_process_t* handle, int64_t exitStatus, int termSignal);
-  void UVPipeOutData(cmUVPipeBuffer::DataRange data);
+  void UVPipeOutData(cmUVPipeBuffer::DataRange data) const;
   void UVPipeOutEnd(ssize_t error);
-  void UVPipeErrData(cmUVPipeBuffer::DataRange data);
+  void UVPipeErrData(cmUVPipeBuffer::DataRange data) const;
   void UVPipeErrEnd(ssize_t error);
   void UVTryFinish();
 
-private:
   // -- Setup
   SetupT Setup_;
   // -- Runtime
@@ -193,109 +192,113 @@ void cmUVReadOnlyProcess::setup(cmWorkerPool::ProcessResultT* result,
                                 std::vector<std::string> const& command,
                                 std::string const& workingDirectory)
 {
-  Setup_.WorkingDirectory = workingDirectory;
-  Setup_.Command = command;
-  Setup_.Result = result;
-  Setup_.MergedOutput = mergedOutput;
+  this->Setup_.WorkingDirectory = workingDirectory;
+  this->Setup_.Command = command;
+  this->Setup_.Result = result;
+  this->Setup_.MergedOutput = mergedOutput;
 }
 
 bool cmUVReadOnlyProcess::start(uv_loop_t* uv_loop,
                                 std::function<void()> finishedCallback)
 {
-  if (IsStarted() || (Result() == nullptr)) {
+  if (this->IsStarted() || (this->Result() == nullptr)) {
     return false;
   }
 
   // Reset result before the start
-  Result()->reset();
+  this->Result()->reset();
 
   // Fill command string pointers
-  if (!Setup().Command.empty()) {
-    CommandPtr_.reserve(Setup().Command.size() + 1);
-    for (std::string const& arg : Setup().Command) {
-      CommandPtr_.push_back(arg.c_str());
+  if (!this->Setup().Command.empty()) {
+    this->CommandPtr_.reserve(this->Setup().Command.size() + 1);
+    for (std::string const& arg : this->Setup().Command) {
+      this->CommandPtr_.push_back(arg.c_str());
     }
-    CommandPtr_.push_back(nullptr);
+    this->CommandPtr_.push_back(nullptr);
   } else {
-    Result()->ErrorMessage = "Empty command";
+    this->Result()->ErrorMessage = "Empty command";
   }
 
-  if (!Result()->error()) {
-    if (!UVPipeOut_.init(uv_loop)) {
-      Result()->ErrorMessage = "libuv stdout pipe initialization failed";
+  if (!this->Result()->error()) {
+    if (!this->UVPipeOut_.init(uv_loop)) {
+      this->Result()->ErrorMessage = "libuv stdout pipe initialization failed";
     }
   }
-  if (!Result()->error()) {
-    if (!UVPipeErr_.init(uv_loop)) {
-      Result()->ErrorMessage = "libuv stderr pipe initialization failed";
+  if (!this->Result()->error()) {
+    if (!this->UVPipeErr_.init(uv_loop)) {
+      this->Result()->ErrorMessage = "libuv stderr pipe initialization failed";
     }
   }
-  if (!Result()->error()) {
+  if (!this->Result()->error()) {
     // -- Setup process stdio options
     // stdin
-    UVOptionsStdIO_[0].flags = UV_IGNORE;
-    UVOptionsStdIO_[0].data.stream = nullptr;
+    this->UVOptionsStdIO_[0].flags = UV_IGNORE;
+    this->UVOptionsStdIO_[0].data.stream = nullptr;
     // stdout
-    UVOptionsStdIO_[1].flags =
+    this->UVOptionsStdIO_[1].flags =
       static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
-    UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream();
+    this->UVOptionsStdIO_[1].data.stream = this->UVPipeOut_.uv_stream();
     // stderr
-    UVOptionsStdIO_[2].flags =
+    this->UVOptionsStdIO_[2].flags =
       static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
-    UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream();
+    this->UVOptionsStdIO_[2].data.stream = this->UVPipeErr_.uv_stream();
 
     // -- Setup process options
-    std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0);
-    UVOptions_.exit_cb = &cmUVReadOnlyProcess::UVExit;
-    UVOptions_.file = CommandPtr_[0];
-    UVOptions_.args = const_cast<char**>(CommandPtr_.data());
-    UVOptions_.cwd = Setup_.WorkingDirectory.c_str();
-    UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
-    UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size());
-    UVOptions_.stdio = UVOptionsStdIO_.data();
+    std::fill_n(reinterpret_cast<char*>(&this->UVOptions_),
+                sizeof(this->UVOptions_), 0);
+    this->UVOptions_.exit_cb = &cmUVReadOnlyProcess::UVExit;
+    this->UVOptions_.file = this->CommandPtr_[0];
+    this->UVOptions_.args = const_cast<char**>(this->CommandPtr_.data());
+    this->UVOptions_.cwd = this->Setup_.WorkingDirectory.c_str();
+    this->UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
+    this->UVOptions_.stdio_count =
+      static_cast<int>(this->UVOptionsStdIO_.size());
+    this->UVOptions_.stdio = this->UVOptionsStdIO_.data();
 
     // -- Spawn process
-    int uvErrorCode = UVProcess_.spawn(*uv_loop, UVOptions_, this);
+    int uvErrorCode = this->UVProcess_.spawn(*uv_loop, this->UVOptions_, this);
     if (uvErrorCode != 0) {
-      Result()->ErrorMessage = "libuv process spawn failed";
+      this->Result()->ErrorMessage = "libuv process spawn failed";
       if (const char* uvErr = uv_strerror(uvErrorCode)) {
-        Result()->ErrorMessage += ": ";
-        Result()->ErrorMessage += uvErr;
+        this->Result()->ErrorMessage += ": ";
+        this->Result()->ErrorMessage += uvErr;
       }
     }
   }
   // -- Start reading from stdio streams
-  if (!Result()->error()) {
-    if (!UVPipeOut_.startRead(
+  if (!this->Result()->error()) {
+    if (!this->UVPipeOut_.startRead(
           [this](cmUVPipeBuffer::DataRange range) {
             this->UVPipeOutData(range);
           },
           [this](ssize_t error) { this->UVPipeOutEnd(error); })) {
-      Result()->ErrorMessage = "libuv start reading from stdout pipe failed";
+      this->Result()->ErrorMessage =
+        "libuv start reading from stdout pipe failed";
     }
   }
-  if (!Result()->error()) {
-    if (!UVPipeErr_.startRead(
+  if (!this->Result()->error()) {
+    if (!this->UVPipeErr_.startRead(
           [this](cmUVPipeBuffer::DataRange range) {
             this->UVPipeErrData(range);
           },
           [this](ssize_t error) { this->UVPipeErrEnd(error); })) {
-      Result()->ErrorMessage = "libuv start reading from stderr pipe failed";
+      this->Result()->ErrorMessage =
+        "libuv start reading from stderr pipe failed";
     }
   }
 
-  if (!Result()->error()) {
-    IsStarted_ = true;
-    FinishedCallback_ = std::move(finishedCallback);
+  if (!this->Result()->error()) {
+    this->IsStarted_ = true;
+    this->FinishedCallback_ = std::move(finishedCallback);
   } else {
     // Clear libuv handles and finish
-    UVProcess_.reset();
-    UVPipeOut_.reset();
-    UVPipeErr_.reset();
-    CommandPtr_.clear();
+    this->UVProcess_.reset();
+    this->UVPipeOut_.reset();
+    this->UVPipeErr_.reset();
+    this->CommandPtr_.clear();
   }
 
-  return IsStarted();
+  return this->IsStarted();
 }
 
 void cmUVReadOnlyProcess::UVExit(uv_process_t* handle, int64_t exitStatus,
@@ -323,38 +326,38 @@ void cmUVReadOnlyProcess::UVExit(uv_process_t* handle, int64_t exitStatus,
   }
 }
 
-void cmUVReadOnlyProcess::UVPipeOutData(cmUVPipeBuffer::DataRange data)
+void cmUVReadOnlyProcess::UVPipeOutData(cmUVPipeBuffer::DataRange data) const
 {
-  Result()->StdOut.append(data.begin(), data.end());
+  this->Result()->StdOut.append(data.begin(), data.end());
 }
 
 void cmUVReadOnlyProcess::UVPipeOutEnd(ssize_t error)
 {
   // Process pipe error
-  if ((error != 0) && !Result()->error()) {
-    Result()->ErrorMessage = cmStrCat(
+  if ((error != 0) && !this->Result()->error()) {
+    this->Result()->ErrorMessage = cmStrCat(
       "Reading from stdout pipe failed with libuv error code ", error);
   }
   // Try finish
-  UVTryFinish();
+  this->UVTryFinish();
 }
 
-void cmUVReadOnlyProcess::UVPipeErrData(cmUVPipeBuffer::DataRange data)
+void cmUVReadOnlyProcess::UVPipeErrData(cmUVPipeBuffer::DataRange data) const
 {
-  std::string* str =
-    Setup_.MergedOutput ? &Result()->StdOut : &Result()->StdErr;
+  std::string* str = this->Setup_.MergedOutput ? &this->Result()->StdOut
+                                               : &this->Result()->StdErr;
   str->append(data.begin(), data.end());
 }
 
 void cmUVReadOnlyProcess::UVPipeErrEnd(ssize_t error)
 {
   // Process pipe error
-  if ((error != 0) && !Result()->error()) {
-    Result()->ErrorMessage = cmStrCat(
+  if ((error != 0) && !this->Result()->error()) {
+    this->Result()->ErrorMessage = cmStrCat(
       "Reading from stderr pipe failed with libuv error code ", error);
   }
   // Try finish
-  UVTryFinish();
+  this->UVTryFinish();
 }
 
 void cmUVReadOnlyProcess::UVTryFinish()
@@ -362,12 +365,13 @@ void cmUVReadOnlyProcess::UVTryFinish()
   // There still might be data in the pipes after the process has finished.
   // Therefore check if the process is finished AND all pipes are closed
   // before signaling the worker thread to continue.
-  if ((UVProcess_.get() != nullptr) || (UVPipeOut_.uv_pipe() != nullptr) ||
-      (UVPipeErr_.uv_pipe() != nullptr)) {
+  if ((this->UVProcess_.get() != nullptr) ||
+      (this->UVPipeOut_.uv_pipe() != nullptr) ||
+      (this->UVPipeErr_.uv_pipe() != nullptr)) {
     return;
   }
-  IsFinished_ = true;
-  FinishedCallback_();
+  this->IsFinished_ = true;
+  this->FinishedCallback_();
 }
 
 /**
@@ -385,7 +389,7 @@ public:
   /**
    * Set the internal thread
    */
-  void SetThread(std::thread&& aThread) { Thread_ = std::move(aThread); }
+  void SetThread(std::thread&& aThread) { this->Thread_ = std::move(aThread); }
 
   /**
    * Run an external process
@@ -399,7 +403,6 @@ private:
   static void UVProcessStart(uv_async_t* handle);
   void UVProcessFinished();
 
-private:
   // -- Process management
   struct
   {
@@ -414,13 +417,13 @@ private:
 
 cmWorkerPoolWorker::cmWorkerPoolWorker(uv_loop_t& uvLoop)
 {
-  Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this);
+  this->Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this);
 }
 
 cmWorkerPoolWorker::~cmWorkerPoolWorker()
 {
-  if (Thread_.joinable()) {
-    Thread_.join();
+  if (this->Thread_.joinable()) {
+    this->Thread_.join();
   }
 }
 
@@ -433,17 +436,17 @@ bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result,
   }
   // Create process instance
   {
-    std::lock_guard<std::mutex> lock(Proc_.Mutex);
-    Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>();
-    Proc_.ROP->setup(&result, true, command, workingDirectory);
+    std::lock_guard<std::mutex> lock(this->Proc_.Mutex);
+    this->Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>();
+    this->Proc_.ROP->setup(&result, true, command, workingDirectory);
   }
   // Send asynchronous process start request to libuv loop
-  Proc_.Request.send();
+  this->Proc_.Request.send();
   // Wait until the process has been finished and destroyed
   {
-    std::unique_lock<std::mutex> ulock(Proc_.Mutex);
-    while (Proc_.ROP) {
-      Proc_.Condition.wait(ulock);
+    std::unique_lock<std::mutex> ulock(this->Proc_.Mutex);
+    while (this->Proc_.ROP) {
+      this->Proc_.Condition.wait(ulock);
     }
   }
   return !result.error();
@@ -469,12 +472,13 @@ void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle)
 
 void cmWorkerPoolWorker::UVProcessFinished()
 {
-  std::lock_guard<std::mutex> lock(Proc_.Mutex);
-  if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) {
-    Proc_.ROP.reset();
+  std::lock_guard<std::mutex> lock(this->Proc_.Mutex);
+  if (this->Proc_.ROP &&
+      (this->Proc_.ROP->IsFinished() || !this->Proc_.ROP->IsStarted())) {
+    this->Proc_.ROP.reset();
   }
   // Notify idling thread
-  Proc_.Condition.notify_one();
+  this->Proc_.Condition.notify_one();
 }
 
 /**
@@ -511,7 +515,6 @@ public:
   static void UVSlotBegin(uv_async_t* handle);
   static void UVSlotEnd(uv_async_t* handle);
 
-public:
   // -- UV loop
 #ifdef CMAKE_UV_SIGNAL_HACK
   std::unique_ptr<cmUVSignalHackRAII> UVHackRAII;
@@ -539,19 +542,19 @@ public:
 
 void cmWorkerPool::ProcessResultT::reset()
 {
-  ExitStatus = 0;
-  TermSignal = 0;
-  if (!StdOut.empty()) {
-    StdOut.clear();
-    StdOut.shrink_to_fit();
+  this->ExitStatus = 0;
+  this->TermSignal = 0;
+  if (!this->StdOut.empty()) {
+    this->StdOut.clear();
+    this->StdOut.shrink_to_fit();
   }
-  if (!StdErr.empty()) {
-    StdErr.clear();
-    StdErr.shrink_to_fit();
+  if (!this->StdErr.empty()) {
+    this->StdErr.clear();
+    this->StdErr.shrink_to_fit();
   }
-  if (!ErrorMessage.empty()) {
-    ErrorMessage.clear();
-    ErrorMessage.shrink_to_fit();
+  if (!this->ErrorMessage.empty()) {
+    this->ErrorMessage.clear();
+    this->ErrorMessage.shrink_to_fit();
   }
 }
 
@@ -563,56 +566,58 @@ cmWorkerPoolInternal::cmWorkerPoolInternal(cmWorkerPool* pool)
 #ifdef CMAKE_UV_SIGNAL_HACK
   UVHackRAII = cm::make_unique<cmUVSignalHackRAII>();
 #endif
-  UVLoop = cm::make_unique<uv_loop_t>();
-  uv_loop_init(UVLoop.get());
+  this->UVLoop = cm::make_unique<uv_loop_t>();
+  uv_loop_init(this->UVLoop.get());
 }
 
 cmWorkerPoolInternal::~cmWorkerPoolInternal()
 {
-  uv_loop_close(UVLoop.get());
+  uv_loop_close(this->UVLoop.get());
 }
 
 bool cmWorkerPoolInternal::Process()
 {
   // Reset state flags
-  Processing = true;
-  Aborting = false;
+  this->Processing = true;
+  this->Aborting = false;
   // Initialize libuv asynchronous request
-  UVRequestBegin.init(*UVLoop, &cmWorkerPoolInternal::UVSlotBegin, this);
-  UVRequestEnd.init(*UVLoop, &cmWorkerPoolInternal::UVSlotEnd, this);
+  this->UVRequestBegin.init(*this->UVLoop, &cmWorkerPoolInternal::UVSlotBegin,
+                            this);
+  this->UVRequestEnd.init(*this->UVLoop, &cmWorkerPoolInternal::UVSlotEnd,
+                          this);
   // Send begin request
-  UVRequestBegin.send();
+  this->UVRequestBegin.send();
   // Run libuv loop
-  bool success = (uv_run(UVLoop.get(), UV_RUN_DEFAULT) == 0);
+  bool success = (uv_run(this->UVLoop.get(), UV_RUN_DEFAULT) == 0);
   // Update state flags
-  Processing = false;
-  Aborting = false;
+  this->Processing = false;
+  this->Aborting = false;
   return success;
 }
 
 void cmWorkerPoolInternal::Abort()
 {
   // Clear all jobs and set abort flag
-  std::lock_guard<std::mutex> guard(Mutex);
-  if (!Aborting) {
+  std::lock_guard<std::mutex> guard(this->Mutex);
+  if (!this->Aborting) {
     // Register abort and clear queue
-    Aborting = true;
-    Queue.clear();
-    Condition.notify_all();
+    this->Aborting = true;
+    this->Queue.clear();
+    this->Condition.notify_all();
   }
 }
 
 inline bool cmWorkerPoolInternal::PushJob(cmWorkerPool::JobHandleT&& jobHandle)
 {
-  std::lock_guard<std::mutex> guard(Mutex);
-  if (Aborting) {
+  std::lock_guard<std::mutex> guard(this->Mutex);
+  if (this->Aborting) {
     return false;
   }
   // Append the job to the queue
-  Queue.emplace_back(std::move(jobHandle));
+  this->Queue.emplace_back(std::move(jobHandle));
   // Notify an idle worker if there's one
-  if (WorkersIdle != 0) {
-    Condition.notify_one();
+  if (this->WorkersIdle != 0) {
+    this->Condition.notify_one();
   }
   // Return success
   return true;
@@ -652,79 +657,79 @@ void cmWorkerPoolInternal::UVSlotEnd(uv_async_t* handle)
 void cmWorkerPoolInternal::Work(unsigned int workerIndex)
 {
   cmWorkerPool::JobHandleT jobHandle;
-  std::unique_lock<std::mutex> uLock(Mutex);
+  std::unique_lock<std::mutex> uLock(this->Mutex);
   // Increment running workers count
-  ++WorkersRunning;
+  ++this->WorkersRunning;
   // Enter worker main loop
   while (true) {
     // Abort on request
-    if (Aborting) {
+    if (this->Aborting) {
       break;
     }
     // Wait for new jobs on the main CV
-    if (Queue.empty()) {
-      ++WorkersIdle;
-      Condition.wait(uLock);
-      --WorkersIdle;
+    if (this->Queue.empty()) {
+      ++this->WorkersIdle;
+      this->Condition.wait(uLock);
+      --this->WorkersIdle;
       continue;
     }
 
     // If there is a fence currently active or waiting,
     // sleep on the main CV and try again.
-    if (FenceProcessing) {
-      Condition.wait(uLock);
+    if (this->FenceProcessing) {
+      this->Condition.wait(uLock);
       continue;
     }
 
     // Pop next job from queue
-    jobHandle = std::move(Queue.front());
-    Queue.pop_front();
+    jobHandle = std::move(this->Queue.front());
+    this->Queue.pop_front();
 
     // Check for fence jobs
     bool raisedFence = false;
     if (jobHandle->IsFence()) {
-      FenceProcessing = true;
+      this->FenceProcessing = true;
       raisedFence = true;
       // Wait on the Fence CV until all pending jobs are done.
-      while (JobsProcessing != 0 && !Aborting) {
-        ConditionFence.wait(uLock);
+      while (this->JobsProcessing != 0 && !this->Aborting) {
+        this->ConditionFence.wait(uLock);
       }
       // When aborting, explicitly kick all threads alive once more.
-      if (Aborting) {
-        FenceProcessing = false;
-        Condition.notify_all();
+      if (this->Aborting) {
+        this->FenceProcessing = false;
+        this->Condition.notify_all();
         break;
       }
     }
 
     // Unlocked scope for job processing
-    ++JobsProcessing;
+    ++this->JobsProcessing;
     {
       uLock.unlock();
-      jobHandle->Work(Pool, workerIndex); // Process job
-      jobHandle.reset();                  // Destroy job
+      jobHandle->Work(this->Pool, workerIndex); // Process job
+      jobHandle.reset();                        // Destroy job
       uLock.lock();
     }
-    --JobsProcessing;
+    --this->JobsProcessing;
 
     // If this was the thread that entered fence processing
     // originally, notify all idling workers that the fence
     // is done.
     if (raisedFence) {
-      FenceProcessing = false;
-      Condition.notify_all();
+      this->FenceProcessing = false;
+      this->Condition.notify_all();
     }
     // If fence processing is still not done, notify the
     // the fencing worker when all active jobs are done.
-    if (FenceProcessing && JobsProcessing == 0) {
-      ConditionFence.notify_all();
+    if (this->FenceProcessing && this->JobsProcessing == 0) {
+      this->ConditionFence.notify_all();
     }
   }
 
   // Decrement running workers count
-  if (--WorkersRunning == 0) {
+  if (--this->WorkersRunning == 0) {
     // Last worker thread about to finish. Send libuv event.
-    UVRequestEnd.send();
+    this->UVRequestEnd.send();
   }
 }
 
@@ -735,7 +740,7 @@ bool cmWorkerPool::JobT::RunProcess(ProcessResultT& result,
                                     std::string const& workingDirectory)
 {
   // Get worker by index
-  auto* wrk = Pool_->Int_->Workers.at(WorkerIndex_).get();
+  auto* wrk = this->Pool_->Int_->Workers.at(this->WorkerIndex_).get();
   return wrk->RunProcess(result, command, workingDirectory);
 }
 
@@ -748,29 +753,29 @@ cmWorkerPool::~cmWorkerPool() = default;
 
 void cmWorkerPool::SetThreadCount(unsigned int threadCount)
 {
-  if (!Int_->Processing) {
-    ThreadCount_ = (threadCount > 0) ? threadCount : 1u;
+  if (!this->Int_->Processing) {
+    this->ThreadCount_ = (threadCount > 0) ? threadCount : 1u;
   }
 }
 
 bool cmWorkerPool::Process(void* userData)
 {
   // Setup user data
-  UserData_ = userData;
+  this->UserData_ = userData;
   // Run libuv loop
-  bool success = Int_->Process();
+  bool success = this->Int_->Process();
   // Clear user data
-  UserData_ = nullptr;
+  this->UserData_ = nullptr;
   // Return
   return success;
 }
 
 bool cmWorkerPool::PushJob(JobHandleT&& jobHandle)
 {
-  return Int_->PushJob(std::move(jobHandle));
+  return this->Int_->PushJob(std::move(jobHandle));
 }
 
 void cmWorkerPool::Abort()
 {
-  Int_->Abort();
+  this->Int_->Abort();
 }
index 0fb6707..ff25526 100644 (file)
@@ -28,7 +28,8 @@ public:
     void reset();
     bool error() const
     {
-      return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty();
+      return (this->ExitStatus != 0) || (this->TermSignal != 0) ||
+        !this->ErrorMessage.empty();
     }
 
     std::int64_t ExitStatus = 0;
@@ -60,7 +61,7 @@ public:
      * - no jobs later in the queue will be processed before this job was
      *   processed
      */
-    bool IsFence() const { return Fence_; }
+    bool IsFence() const { return this->Fence_; }
 
   protected:
     /**
@@ -80,13 +81,13 @@ public:
      * Get the worker pool.
      * Only valid during the JobT::Process() call!
      */
-    cmWorkerPool* Pool() const { return Pool_; }
+    cmWorkerPool* Pool() const { return this->Pool_; }
 
     /**
      * Get the user data.
      * Only valid during the JobT::Process() call!
      */
-    void* UserData() const { return Pool_->UserData(); };
+    void* UserData() const { return this->Pool_->UserData(); };
 
     /**
      * Get the worker index.
@@ -95,7 +96,7 @@ public:
      * Concurrently processing jobs will never have the same WorkerIndex().
      * Only valid during the JobT::Process() call!
      */
-    unsigned int WorkerIndex() const { return WorkerIndex_; }
+    unsigned int WorkerIndex() const { return this->WorkerIndex_; }
 
     /**
      * Run an external read only process.
@@ -111,12 +112,11 @@ public:
     //! Worker thread entry method.
     void Work(cmWorkerPool* pool, unsigned int workerIndex)
     {
-      Pool_ = pool;
-      WorkerIndex_ = workerIndex;
+      this->Pool_ = pool;
+      this->WorkerIndex_ = workerIndex;
       this->Process();
     }
 
-  private:
     cmWorkerPool* Pool_ = nullptr;
     unsigned int WorkerIndex_ = 0;
     bool Fence_ = false;
@@ -150,10 +150,9 @@ public:
   {
   public:
     //! Does nothing
-    void Process() override { Pool()->Abort(); }
+    void Process() override { this->Pool()->Abort(); }
   };
 
-public:
   // -- Methods
   cmWorkerPool();
   ~cmWorkerPool();
@@ -161,7 +160,7 @@ public:
   /**
    * Number of worker threads.
    */
-  unsigned int ThreadCount() const { return ThreadCount_; }
+  unsigned int ThreadCount() const { return this->ThreadCount_; }
 
   /**
    * Set the number of worker threads.
@@ -184,7 +183,7 @@ public:
    *
    * Only valid during Process().
    */
-  void* UserData() const { return UserData_; }
+  void* UserData() const { return this->UserData_; }
 
   // -- Job processing interface
 
@@ -212,7 +211,7 @@ public:
   template <class T, typename... Args>
   bool EmplaceJob(Args&&... args)
   {
-    return PushJob(cm::make_unique<T>(std::forward<Args>(args)...));
+    return this->PushJob(cm::make_unique<T>(std::forward<Args>(args)...));
   }
 
 private:
index c8adea9..e593621 100644 (file)
@@ -26,7 +26,7 @@ public:
 
   bool SetDirectory(std::string const& newdir);
   void Pop();
-  bool Failed() const { return ResultCode != 0; }
+  bool Failed() const { return this->ResultCode != 0; }
 
   /** \return 0 if the last attempt to set the working directory was
    *          successful. If it failed, the value returned will be the
@@ -34,7 +34,7 @@ public:
    *          of the error code can be obtained by passing the result
    *          to \c std::strerror().
    */
-  int GetLastResult() const { return ResultCode; }
+  int GetLastResult() const { return this->ResultCode; }
 
   std::string const& GetOldDirectory() const { return this->OldDir; }
 
diff --git a/Source/cmXCOFF.cxx b/Source/cmXCOFF.cxx
new file mode 100644 (file)
index 0000000..890636e
--- /dev/null
@@ -0,0 +1,356 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmXCOFF.h"
+
+#include <algorithm>
+#include <cstddef>
+
+#include <cm/memory>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmStringAlgorithms.h"
+
+// Include the XCOFF format information system header.
+#ifdef _AIX
+#  define __XCOFF32__
+#  define __XCOFF64__
+#  include <xcoff.h>
+#else
+#  error "This source may be compiled only on AIX."
+#endif
+
+class cmXCOFFInternal
+{
+public:
+  // Construct and take ownership of the file stream object.
+  cmXCOFFInternal(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
+                  cmXCOFF::Mode mode)
+    : External(external)
+    , Stream(std::move(fin))
+    , Mode(mode)
+  {
+  }
+
+  // Destruct and delete the file stream object.
+  virtual ~cmXCOFFInternal() = default;
+
+  cmXCOFF::Mode GetMode() const { return this->Mode; }
+
+  virtual cm::optional<cm::string_view> GetLibPath() = 0;
+
+  virtual bool SetLibPath(cm::string_view libPath) = 0;
+  virtual bool RemoveLibPath() = 0;
+
+protected:
+  // Data common to all ELF class implementations.
+
+  // The external cmXCOFF object.
+  cmXCOFF* External;
+
+  // The stream from which to read.
+  std::unique_ptr<std::iostream> Stream;
+
+  cmXCOFF::Mode Mode;
+
+  // Helper methods for subclasses.
+  void SetErrorMessage(const char* msg) { this->External->ErrorMessage = msg; }
+};
+
+namespace {
+
+struct XCOFF32
+{
+  typedef struct filehdr filehdr;
+  typedef struct aouthdr aouthdr;
+  typedef struct scnhdr scnhdr;
+  typedef struct ldhdr ldhdr;
+  static const std::size_t aouthdr_size = _AOUTHSZ_EXEC;
+};
+const unsigned char xcoff32_magic[] = { 0x01, 0xDF };
+
+struct XCOFF64
+{
+  typedef struct filehdr_64 filehdr;
+  typedef struct aouthdr_64 aouthdr;
+  typedef struct scnhdr_64 scnhdr;
+  typedef struct ldhdr_64 ldhdr;
+  static const std::size_t aouthdr_size = _AOUTHSZ_EXEC_64;
+};
+const unsigned char xcoff64_magic[] = { 0x01, 0xF7 };
+
+template <typename XCOFF>
+class Impl : public cmXCOFFInternal
+{
+  static_assert(sizeof(typename XCOFF::aouthdr) == XCOFF::aouthdr_size,
+                "aouthdr structure size matches _AOUTHSZ_EXEC macro");
+
+  typename XCOFF::filehdr FileHeader;
+  typename XCOFF::aouthdr AuxHeader;
+  typename XCOFF::scnhdr LoaderSectionHeader;
+  typename XCOFF::ldhdr LoaderHeader;
+
+  std::streamoff LoaderImportFileTablePos = 0;
+  std::vector<char> LoaderImportFileTable;
+
+  bool Read(typename XCOFF::filehdr& x)
+  {
+    // FIXME: Add byte swapping if needed.
+    return static_cast<bool>(
+      this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+  }
+
+  bool Read(typename XCOFF::aouthdr& x)
+  {
+    // FIXME: Add byte swapping if needed.
+    return static_cast<bool>(
+      this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+  }
+
+  bool Read(typename XCOFF::scnhdr& x)
+  {
+    // FIXME: Add byte swapping if needed.
+    return static_cast<bool>(
+      this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+  }
+
+  bool Read(typename XCOFF::ldhdr& x)
+  {
+    // FIXME: Add byte swapping if needed.
+    return static_cast<bool>(
+      this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)));
+  }
+
+  bool WriteLoaderImportFileTableLength(decltype(XCOFF::ldhdr::l_istlen) x)
+  {
+    // FIXME: Add byte swapping if needed.
+    return static_cast<bool>(
+      this->Stream->write(reinterpret_cast<char const*>(&x), sizeof(x)));
+  }
+
+public:
+  Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
+       cmXCOFF::Mode mode);
+
+  cm::optional<cm::string_view> GetLibPath() override;
+  bool SetLibPath(cm::string_view libPath) override;
+  bool RemoveLibPath() override;
+};
+
+template <typename XCOFF>
+Impl<XCOFF>::Impl(cmXCOFF* external, std::unique_ptr<std::iostream> fin,
+                  cmXCOFF::Mode mode)
+  : cmXCOFFInternal(external, std::move(fin), mode)
+{
+  if (!this->Read(this->FileHeader)) {
+    this->SetErrorMessage("Failed to read XCOFF file header.");
+    return;
+  }
+  if (this->FileHeader.f_opthdr != XCOFF::aouthdr_size) {
+    this->SetErrorMessage("XCOFF auxiliary header missing.");
+    return;
+  }
+  if (!this->Read(this->AuxHeader)) {
+    this->SetErrorMessage("Failed to read XCOFF auxiliary header.");
+    return;
+  }
+  if (this->AuxHeader.o_snloader == 0) {
+    this->SetErrorMessage("XCOFF loader section missing.");
+    return;
+  }
+  if (!this->Stream->seekg((this->AuxHeader.o_snloader - 1) *
+                             sizeof(typename XCOFF::scnhdr),
+                           std::ios::cur)) {
+    this->SetErrorMessage("Failed to seek to XCOFF loader section header.");
+    return;
+  }
+  if (!this->Read(this->LoaderSectionHeader)) {
+    this->SetErrorMessage("Failed to read XCOFF loader section header.");
+    return;
+  }
+  if ((this->LoaderSectionHeader.s_flags & STYP_LOADER) == 0) {
+    this->SetErrorMessage("XCOFF loader section header missing STYP_LOADER.");
+    return;
+  }
+  if (!this->Stream->seekg(this->LoaderSectionHeader.s_scnptr,
+                           std::ios::beg)) {
+    this->SetErrorMessage("Failed to seek to XCOFF loader header.");
+    return;
+  }
+  if (!this->Read(this->LoaderHeader)) {
+    this->SetErrorMessage("Failed to read XCOFF loader header.");
+    return;
+  }
+  this->LoaderImportFileTablePos =
+    this->LoaderSectionHeader.s_scnptr + this->LoaderHeader.l_impoff;
+  if (!this->Stream->seekg(this->LoaderImportFileTablePos)) {
+    this->SetErrorMessage(
+      "Failed to seek to XCOFF loader import file id table.");
+    return;
+  }
+  this->LoaderImportFileTable.resize(this->LoaderHeader.l_istlen);
+  if (!this->Stream->read(this->LoaderImportFileTable.data(),
+                          this->LoaderImportFileTable.size())) {
+    this->SetErrorMessage("Failed to read XCOFF loader import file id table.");
+    return;
+  }
+}
+
+template <typename XCOFF>
+cm::optional<cm::string_view> Impl<XCOFF>::GetLibPath()
+{
+  cm::optional<cm::string_view> result;
+  auto end = std::find(this->LoaderImportFileTable.begin(),
+                       this->LoaderImportFileTable.end(), '\0');
+  if (end != this->LoaderImportFileTable.end()) {
+    result = cm::string_view(this->LoaderImportFileTable.data(),
+                             end - this->LoaderImportFileTable.begin());
+  }
+  return result;
+}
+
+template <typename XCOFF>
+bool Impl<XCOFF>::SetLibPath(cm::string_view libPath)
+{
+  // The new LIBPATH must end in the standard AIX LIBPATH.
+#define CM_AIX_LIBPATH "/usr/lib:/lib"
+  std::string libPathBuf;
+  if (libPath != CM_AIX_LIBPATH &&
+      !cmHasLiteralSuffix(libPath, ":" CM_AIX_LIBPATH)) {
+    libPathBuf = std::string(libPath);
+    if (!libPathBuf.empty() && libPathBuf.back() != ':') {
+      libPathBuf.push_back(':');
+    }
+    libPathBuf += CM_AIX_LIBPATH;
+    libPath = libPathBuf;
+  }
+#undef CM_AIX_LIBPATH
+
+  auto oldEnd = std::find(this->LoaderImportFileTable.begin(),
+                          this->LoaderImportFileTable.end(), '\0');
+  if (oldEnd == this->LoaderImportFileTable.end()) {
+    this->SetErrorMessage("XCOFF loader import file id table is invalid.");
+    return false;
+  }
+  if ((this->LoaderImportFileTable.begin() + libPath.size()) > oldEnd) {
+    this->SetErrorMessage("XCOFF loader import file id table is too small.");
+    return false;
+  }
+
+  {
+    std::vector<char> ift;
+    ift.reserve(this->LoaderImportFileTable.size());
+    // Start with the new LIBPATH.
+    ift.insert(ift.end(), libPath.begin(), libPath.end());
+    // Add the rest of the original table.
+    ift.insert(ift.end(), oldEnd, this->LoaderImportFileTable.end());
+    // If the new table is shorter, zero out the leftover space.
+    ift.resize(this->LoaderImportFileTable.size(), 0);
+    this->LoaderHeader.l_istlen =
+      static_cast<decltype(XCOFF::ldhdr::l_istlen)>(ift.size());
+    this->LoaderImportFileTable = std::move(ift);
+  }
+
+  if (!this->Stream->seekp(this->LoaderSectionHeader.s_scnptr +
+                             offsetof(typename XCOFF::ldhdr, l_istlen),
+                           std::ios::beg)) {
+    this->SetErrorMessage(
+      "Failed to seek to XCOFF loader header import file id table length.");
+    return false;
+  }
+  if (!this->WriteLoaderImportFileTableLength(this->LoaderHeader.l_istlen)) {
+    this->SetErrorMessage(
+      "Failed to write XCOFF loader header import file id table length.");
+    return false;
+  }
+  if (!this->Stream->seekp(this->LoaderImportFileTablePos, std::ios::beg)) {
+    this->SetErrorMessage(
+      "Failed to seek to XCOFF loader import file id table.");
+    return false;
+  }
+  if (!this->Stream->write(this->LoaderImportFileTable.data(),
+                           this->LoaderImportFileTable.size())) {
+    this->SetErrorMessage(
+      "Failed to write XCOFF loader import file id table.");
+    return false;
+  }
+
+  return true;
+}
+
+template <typename XCOFF>
+bool Impl<XCOFF>::RemoveLibPath()
+{
+  return this->SetLibPath({});
+}
+}
+
+//============================================================================
+// External class implementation.
+
+cmXCOFF::cmXCOFF(const char* fname, Mode mode)
+{
+  // Try to open the file.
+  std::ios::openmode fmode = std::ios::in | std::ios::binary;
+  if (mode == Mode::ReadWrite) {
+    fmode |= std::ios::out;
+  }
+  auto f = cm::make_unique<cmsys::fstream>(fname, fmode);
+
+  // Quit now if the file could not be opened.
+  if (!f || !*f) {
+    this->ErrorMessage = "Error opening input file.";
+    return;
+  }
+
+  // Read the XCOFF magic number.
+  unsigned char magic[2];
+  if (!f->read(reinterpret_cast<char*>(magic), sizeof(magic))) {
+    this->ErrorMessage = "Error reading XCOFF magic number.";
+    return;
+  }
+  if (!f->seekg(0)) {
+    this->ErrorMessage = "Error seeking to beginning of file.";
+    return;
+  }
+
+  // Check the XCOFF type.
+  if (magic[0] == xcoff32_magic[0] && magic[1] == xcoff32_magic[1]) {
+    this->Internal = cm::make_unique<Impl<XCOFF32>>(this, std::move(f), mode);
+  } else if (magic[0] == xcoff64_magic[0] && magic[1] == xcoff64_magic[1]) {
+    this->Internal = cm::make_unique<Impl<XCOFF64>>(this, std::move(f), mode);
+  } else {
+    this->ErrorMessage = "File is not a XCOFF32 or XCOFF64 binary.";
+  }
+}
+
+cmXCOFF::~cmXCOFF() = default;
+
+cmXCOFF::cmXCOFF(cmXCOFF&&) = default;
+cmXCOFF& cmXCOFF::operator=(cmXCOFF&&) = default;
+
+bool cmXCOFF::Valid() const
+{
+  return this->Internal && this->ErrorMessage.empty();
+}
+
+cm::optional<cm::string_view> cmXCOFF::GetLibPath() const
+{
+  cm::optional<cm::string_view> result;
+  if (this->Valid()) {
+    result = this->Internal->GetLibPath();
+  }
+  return result;
+}
+
+bool cmXCOFF::SetLibPath(cm::string_view libPath)
+{
+  return this->Valid() && this->Internal->GetMode() == Mode::ReadWrite &&
+    this->Internal->SetLibPath(libPath);
+}
+
+bool cmXCOFF::RemoveLibPath()
+{
+  return this->Valid() && this->Internal->GetMode() == Mode::ReadWrite &&
+    this->Internal->RemoveLibPath();
+}
diff --git a/Source/cmXCOFF.h b/Source/cmXCOFF.h
new file mode 100644 (file)
index 0000000..16cda9d
--- /dev/null
@@ -0,0 +1,65 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+#include <cm/optional>
+#include <cm/string_view>
+
+#if !defined(CMake_USE_XCOFF_PARSER)
+#  error "This file may be included only if CMake_USE_XCOFF_PARSER is enabled."
+#endif
+
+class cmXCOFFInternal;
+
+/** \class cmXCOFF
+ * \brief XCOFF parser.
+ */
+class cmXCOFF
+{
+public:
+  enum class Mode
+  {
+    ReadOnly,
+    ReadWrite
+  };
+
+  /** Construct with the name of the XCOFF input file to parse.  */
+  cmXCOFF(const char* fname, Mode = Mode::ReadOnly);
+
+  /** Destruct.   */
+  ~cmXCOFF();
+
+  cmXCOFF(cmXCOFF&&);
+  cmXCOFF(cmXCOFF const&) = delete;
+  cmXCOFF& operator=(cmXCOFF&&);
+  cmXCOFF& operator=(cmXCOFF const&) = delete;
+
+  /** Get the error message if any.  */
+  std::string const& GetErrorMessage() const { return this->ErrorMessage; }
+
+  /** Boolean conversion.  True if the XCOFF file is valid.  */
+  explicit operator bool() const { return this->Valid(); }
+
+  /** Get the LIBPATH (RPATH) parsed from the file, if any.  */
+  cm::optional<cm::string_view> GetLibPath() const;
+
+  /** Set the LIBPATH (RPATH).
+      Works only if cmXCOFF was constructed with Mode::ReadWrite.  */
+  bool SetLibPath(cm::string_view libPath);
+
+  /** Remove the LIBPATH (RPATH).
+      Works only if cmXCOFF was constructed with Mode::ReadWrite.  */
+  bool RemoveLibPath();
+
+private:
+  friend class cmXCOFFInternal;
+  bool Valid() const;
+  std::unique_ptr<cmXCOFFInternal> Internal;
+  std::string ErrorMessage;
+};
index ac5be3f..dd5e86e 100644 (file)
@@ -81,6 +81,13 @@ public:
   void SetObject(cmXCodeObject* value) { this->Object = value; }
   cmXCodeObject* GetObject() { return this->Object; }
   void AddObject(cmXCodeObject* value) { this->List.push_back(value); }
+  size_t GetObjectCount() { return this->List.size(); }
+  void InsertObject(size_t position, cmXCodeObject* value)
+  {
+    if (position < GetObjectCount()) {
+      this->List.insert(this->List.begin() + position, value);
+    }
+  }
   void PrependObject(cmXCodeObject* value)
   {
     this->List.insert(this->List.begin(), value);
index 8cd5f6e..d31a239 100644 (file)
@@ -28,7 +28,7 @@ cmXMLSafe& cmXMLSafe::Quotes(bool b)
   return *this;
 }
 
-std::string cmXMLSafe::str()
+std::string cmXMLSafe::str() const
 {
   std::ostringstream ss;
   ss << *this;
index 9b4c539..21bd19a 100644 (file)
@@ -24,7 +24,7 @@ public:
   cmXMLSafe& Quotes(bool b = true);
 
   /** Get the escaped data as a string.  */
-  std::string str();
+  std::string str() const;
 
 private:
   char const* Data;
index a16c4c8..6e8eeb7 100644 (file)
@@ -75,7 +75,6 @@ private:
 
   void CloseStartElement();
 
-private:
   static cmXMLSafe SafeAttribute(const char* value) { return { value }; }
 
   static cmXMLSafe SafeAttribute(std::string const& value)
@@ -121,7 +120,6 @@ private:
     return value;
   }
 
-private:
   std::ostream& Output;
   std::stack<std::string, std::vector<std::string>> Elements;
   std::string IndentationElement;
@@ -140,9 +138,9 @@ public:
   cmXMLDocument(cmXMLWriter& xml)
     : xmlwr(xml)
   {
-    xmlwr.StartDocument();
+    this->xmlwr.StartDocument();
   }
-  ~cmXMLDocument() { xmlwr.EndDocument(); }
+  ~cmXMLDocument() { this->xmlwr.EndDocument(); }
   cmXMLDocument(const cmXMLDocument&) = delete;
   cmXMLDocument& operator=(const cmXMLDocument&) = delete;
 
@@ -157,19 +155,19 @@ public:
   cmXMLElement(cmXMLWriter& xml, const char* tag)
     : xmlwr(xml)
   {
-    xmlwr.StartElement(tag);
+    this->xmlwr.StartElement(tag);
   }
   cmXMLElement(cmXMLElement& par, const char* tag)
     : xmlwr(par.xmlwr)
   {
-    xmlwr.StartElement(tag);
+    this->xmlwr.StartElement(tag);
   }
   cmXMLElement(cmXMLDocument& doc, const char* tag)
     : xmlwr(doc.xmlwr)
   {
-    xmlwr.StartElement(tag);
+    this->xmlwr.StartElement(tag);
   }
-  ~cmXMLElement() { xmlwr.EndElement(); }
+  ~cmXMLElement() { this->xmlwr.EndElement(); }
 
   cmXMLElement(const cmXMLElement&) = delete;
   cmXMLElement& operator=(const cmXMLElement&) = delete;
@@ -177,20 +175,20 @@ public:
   template <typename T>
   cmXMLElement& Attribute(const char* name, T const& value)
   {
-    xmlwr.Attribute(name, value);
+    this->xmlwr.Attribute(name, value);
     return *this;
   }
   template <typename T>
   void Content(T const& content)
   {
-    xmlwr.Content(content);
+    this->xmlwr.Content(content);
   }
   template <typename T>
   void Element(std::string const& name, T const& value)
   {
-    xmlwr.Element(name, value);
+    this->xmlwr.Element(name, value);
   }
-  void Comment(const char* comment) { xmlwr.Comment(comment); }
+  void Comment(const char* comment) { this->xmlwr.Comment(comment); }
 
 private:
   cmXMLWriter& xmlwr;
index 122e022..15f83e0 100644 (file)
@@ -35,7 +35,7 @@ codecvt::codecvt(Encoding e)
     case codecvt::None:
     // No encoding
     default:
-      m_noconv = true;
+      this->m_noconv = true;
   }
 }
 
@@ -43,7 +43,7 @@ codecvt::~codecvt() = default;
 
 bool codecvt::do_always_noconv() const throw()
 {
-  return m_noconv;
+  return this->m_noconv;
 }
 
 std::codecvt_base::result codecvt::do_out(mbstate_t& state, const char* from,
@@ -53,7 +53,7 @@ std::codecvt_base::result codecvt::do_out(mbstate_t& state, const char* from,
 {
   from_next = from;
   to_next = to;
-  if (m_noconv) {
+  if (this->m_noconv) {
     return std::codecvt_base::noconv;
   }
 #if defined(_WIN32)
@@ -130,7 +130,7 @@ std::codecvt_base::result codecvt::do_unshift(mbstate_t& state, char* to,
                                               char*& to_next) const
 {
   to_next = to;
-  if (m_noconv) {
+  if (this->m_noconv) {
     return std::codecvt_base::noconv;
   }
 #if defined(_WIN32)
index e655634..4b57395 100644 (file)
@@ -29,6 +29,7 @@
 #include "cm_sys_stat.h"
 
 #include "cmCMakePresetsFile.h"
+#include "cmCommandLineArgument.h"
 #include "cmCommands.h"
 #include "cmDocumentation.h"
 #include "cmDocumentationEntry.h"
@@ -132,6 +133,13 @@ namespace {
 using JsonValueMapType = std::unordered_map<std::string, Json::Value>;
 #endif
 
+auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool {
+  return true;
+};
+
+using CommandArgument =
+  cmCommandLineArgument<bool(std::string const& value, cmake* state)>;
+
 } // namespace
 
 static bool cmakeCheckStampFile(const std::string& stampName);
@@ -200,8 +208,9 @@ cmake::cmake(Role role, cmState::Mode mode)
     };
 
     // The "c" extension MUST precede the "C" extension.
-    setupExts(this->CLikeSourceFileExtensions,
-              { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "m", "M", "mm" });
+    setupExts(
+      this->CLikeSourceFileExtensions,
+      { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M", "mm" });
     setupExts(this->HeaderFileExtensions,
               { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" });
     setupExts(this->CudaFileExtensions, { "cu" });
@@ -263,7 +272,7 @@ Json::Value cmake::ReportCapabilitiesJson() const
   }
   obj["generators"] = generators;
   obj["fileApi"] = cmFileAPI::ReportCapabilities();
-  obj["serverMode"] = true;
+  obj["serverMode"] = false;
 
   return obj;
 }
@@ -386,152 +395,145 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args)
 {
   auto findPackageMode = false;
   auto seenScriptOption = false;
-  for (unsigned int i = 1; i < args.size(); ++i) {
-    std::string const& arg = args[i];
-    if (cmHasLiteralPrefix(arg, "-D")) {
-      std::string entry = arg.substr(2);
-      if (entry.empty()) {
-        ++i;
-        if (i < args.size()) {
-          entry = args[i];
-        } else {
-          cmSystemTools::Error("-D must be followed with VAR=VALUE.");
-          return false;
-        }
-      }
-      std::string var;
-      std::string value;
-      cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
-      if (cmState::ParseCacheEntry(entry, var, value, type)) {
+
+  auto DefineLambda = [](std::string const& entry, cmake* state) -> bool {
+    std::string var;
+    std::string value;
+    cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
+    if (cmState::ParseCacheEntry(entry, var, value, type)) {
 #ifndef CMAKE_BOOTSTRAP
-        this->UnprocessedPresetVariables.erase(var);
+      state->UnprocessedPresetVariables.erase(var);
 #endif
-        this->ProcessCacheArg(var, value, type);
-      } else {
-        cmSystemTools::Error("Parse error in command line argument: " + arg +
-                             "\n" + "Should be: VAR:type=value\n");
-        return false;
-      }
-    } else if (cmHasLiteralPrefix(arg, "-W")) {
-      std::string entry = arg.substr(2);
-      if (entry.empty()) {
-        ++i;
-        if (i < args.size()) {
-          entry = args[i];
-        } else {
-          cmSystemTools::Error("-W must be followed with [no-]<name>.");
-          return false;
-        }
-      }
+      state->ProcessCacheArg(var, value, type);
+    } else {
+      cmSystemTools::Error(cmStrCat("Parse error in command line argument: ",
+                                    entry, "\n Should be: VAR:type=value\n"));
+      return false;
+    }
+    return true;
+  };
 
-      std::string name;
-      bool foundNo = false;
-      bool foundError = false;
-      unsigned int nameStartPosition = 0;
+  auto WarningLambda = [](cm::string_view entry, cmake* state) -> bool {
+    bool foundNo = false;
+    bool foundError = false;
 
-      if (entry.find("no-", nameStartPosition) == 0) {
-        foundNo = true;
-        nameStartPosition += 3;
-      }
+    if (cmHasLiteralPrefix(entry, "no-")) {
+      foundNo = true;
+      entry.remove_prefix(3);
+    }
 
-      if (entry.find("error=", nameStartPosition) == 0) {
-        foundError = true;
-        nameStartPosition += 6;
-      }
+    if (cmHasLiteralPrefix(entry, "error=")) {
+      foundError = true;
+      entry.remove_prefix(6);
+    }
 
-      name = entry.substr(nameStartPosition);
-      if (name.empty()) {
-        cmSystemTools::Error("No warning name provided.");
-        return false;
-      }
+    if (entry.empty()) {
+      cmSystemTools::Error("No warning name provided.");
+      return false;
+    }
 
-      if (!foundNo && !foundError) {
-        // -W<name>
-        this->DiagLevels[name] = std::max(this->DiagLevels[name], DIAG_WARN);
-      } else if (foundNo && !foundError) {
-        // -Wno<name>
-        this->DiagLevels[name] = DIAG_IGNORE;
-      } else if (!foundNo && foundError) {
-        // -Werror=<name>
-        this->DiagLevels[name] = DIAG_ERROR;
-      } else {
-        // -Wno-error=<name>
-        this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN);
-      }
-    } else if (cmHasLiteralPrefix(arg, "-U")) {
-      std::string entryPattern = arg.substr(2);
-      if (entryPattern.empty()) {
-        ++i;
-        if (i < args.size()) {
-          entryPattern = args[i];
-        } else {
-          cmSystemTools::Error("-U must be followed with VAR.");
-          return false;
-        }
+    std::string const name = std::string(entry);
+    if (!foundNo && !foundError) {
+      // -W<name>
+      state->DiagLevels[name] = std::max(state->DiagLevels[name], DIAG_WARN);
+    } else if (foundNo && !foundError) {
+      // -Wno<name>
+      state->DiagLevels[name] = DIAG_IGNORE;
+    } else if (!foundNo && foundError) {
+      // -Werror=<name>
+      state->DiagLevels[name] = DIAG_ERROR;
+    } else {
+      // -Wno-error=<name>
+      // This can downgrade an error to a warning, but should not enable
+      // or disable a warning in the first place.
+      auto dli = state->DiagLevels.find(name);
+      if (dli != state->DiagLevels.end()) {
+        dli->second = std::min(dli->second, DIAG_WARN);
       }
-      cmsys::RegularExpression regex(
-        cmsys::Glob::PatternToRegex(entryPattern, true, true));
-      // go through all cache entries and collect the vars which will be
-      // removed
-      std::vector<std::string> entriesToDelete;
-      std::vector<std::string> cacheKeys = this->State->GetCacheEntryKeys();
-      for (std::string const& ck : cacheKeys) {
-        cmStateEnums::CacheEntryType t = this->State->GetCacheEntryType(ck);
-        if (t != cmStateEnums::STATIC) {
-          if (regex.find(ck)) {
-            entriesToDelete.push_back(ck);
-          }
+    }
+    return true;
+  };
+
+  auto UnSetLambda = [](std::string const& entryPattern,
+                        cmake* state) -> bool {
+    cmsys::RegularExpression regex(
+      cmsys::Glob::PatternToRegex(entryPattern, true, true));
+    // go through all cache entries and collect the vars which will be
+    // removed
+    std::vector<std::string> entriesToDelete;
+    std::vector<std::string> cacheKeys = state->State->GetCacheEntryKeys();
+    for (std::string const& ck : cacheKeys) {
+      cmStateEnums::CacheEntryType t = state->State->GetCacheEntryType(ck);
+      if (t != cmStateEnums::STATIC) {
+        if (regex.find(ck)) {
+          entriesToDelete.push_back(ck);
         }
       }
+    }
 
-      // now remove them from the cache
-      for (std::string const& currentEntry : entriesToDelete) {
+    // now remove them from the cache
+    for (std::string const& currentEntry : entriesToDelete) {
 #ifndef CMAKE_BOOTSTRAP
-        this->UnprocessedPresetVariables.erase(currentEntry);
+      state->UnprocessedPresetVariables.erase(currentEntry);
 #endif
-        this->State->RemoveCacheEntry(currentEntry);
-      }
-    } else if (cmHasLiteralPrefix(arg, "-C")) {
-      std::string path = arg.substr(2);
-      if (path.empty()) {
-        ++i;
-        if (i < args.size()) {
-          path = args[i];
-        } else {
-          cmSystemTools::Error("-C must be followed by a file name.");
-          return false;
-        }
-      }
-      cmSystemTools::Stdout("loading initial cache file " + path + "\n");
-      // Resolve script path specified on command line relative to $PWD.
-      path = cmSystemTools::CollapseFullPath(path);
-      this->ReadListFile(args, path);
-    } else if (cmHasLiteralPrefix(arg, "-P")) {
-      i++;
-      if (i >= args.size()) {
-        cmSystemTools::Error("-P must be followed by a file name.");
-        return false;
-      }
-      std::string path = args[i];
-      if (path.empty()) {
-        cmSystemTools::Error("No cmake script provided.");
-        return false;
-      }
-      // Register fake project commands that hint misuse in script mode.
-      GetProjectCommandsInScriptMode(this->GetState());
-      // Documented behaviour of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be
-      // set to $PWD for -P mode.
-      this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
-      this->SetHomeOutputDirectory(
-        cmSystemTools::GetCurrentWorkingDirectory());
-      this->ReadListFile(args, path);
-      seenScriptOption = true;
-    } else if (arg == "--" && seenScriptOption) {
+      state->State->RemoveCacheEntry(currentEntry);
+    }
+    return true;
+  };
+
+  auto ScriptLambda = [&](std::string const& path, cmake* state) -> bool {
+    // Register fake project commands that hint misuse in script mode.
+    GetProjectCommandsInScriptMode(state->GetState());
+    // Documented behaviour of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be
+    // set to $PWD for -P mode.
+    state->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+    state->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+    state->ReadListFile(args, path);
+    seenScriptOption = true;
+    return true;
+  };
+
+  std::vector<CommandArgument> arguments = {
+    CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
+                     CommandArgument::Values::One, DefineLambda },
+    CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
+                     CommandArgument::Values::One, WarningLambda },
+    CommandArgument{ "-U", "-U must be followed with VAR.",
+                     CommandArgument::Values::One, UnSetLambda },
+    CommandArgument{ "-C", "-C must be followed by a file name.",
+                     CommandArgument::Values::One,
+                     [&](std::string const& value, cmake* state) -> bool {
+                       cmSystemTools::Stdout("loading initial cache file " +
+                                             value + "\n");
+                       // Resolve script path specified on command line
+                       // relative to $PWD.
+                       auto path = cmSystemTools::CollapseFullPath(value);
+                       state->ReadListFile(args, path);
+                       return true;
+                     } },
+    CommandArgument{ "-P", "-P must be followed by a file name.",
+                     CommandArgument::Values::One, ScriptLambda },
+    CommandArgument{ "--find-package", CommandArgument::Values::Zero,
+                     [&](std::string const&, cmake*) -> bool {
+                       findPackageMode = true;
+                       return true;
+                     } },
+  };
+  for (decltype(args.size()) i = 1; i < args.size(); ++i) {
+    std::string const& arg = args[i];
+
+    if (arg == "--" && seenScriptOption) {
       // Stop processing CMake args and avoid possible errors
       // when arbitrary args are given to CMake script.
       break;
-    } else if (cmHasLiteralPrefix(arg, "--find-package")) {
-      findPackageMode = true;
+    }
+    for (auto const& m : arguments) {
+      if (m.matches(arg)) {
+        const bool parsedCorrectly = m.parse(arg, i, args, this);
+        if (!parsedCorrectly) {
+          return false;
+        }
+      }
     }
   }
 
@@ -724,261 +726,375 @@ void cmake::LoadEnvironmentPresets()
   readGeneratorVar("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset);
 }
 
+namespace {
+enum class ListPresets
+{
+  None,
+  Configure,
+  Build,
+  Test,
+  All,
+};
+}
+
 // Parse the args
 void cmake::SetArgs(const std::vector<std::string>& args)
 {
   bool haveToolset = false;
   bool havePlatform = false;
   bool haveBArg = false;
+  bool scriptMode = false;
+  std::string possibleUnknownArg;
 #if !defined(CMAKE_BOOTSTRAP)
   std::string profilingFormat;
   std::string profilingOutput;
   std::string presetName;
-  bool listPresets = false;
+
+  ListPresets listPresets = ListPresets::None;
 #endif
-  for (unsigned int i = 1; i < args.size(); ++i) {
-    std::string const& arg = args[i];
-    if (cmHasLiteralPrefix(arg, "-H") || cmHasLiteralPrefix(arg, "-S")) {
-      std::string path = arg.substr(2);
-      if (path.empty()) {
-        ++i;
-        if (i >= args.size()) {
-          cmSystemTools::Error("No source directory specified for -S");
-          return;
-        }
-        path = args[i];
-        if (path[0] == '-') {
-          cmSystemTools::Error("No source directory specified for -S");
-          return;
-        }
-      }
 
-      path = cmSystemTools::CollapseFullPath(path);
-      cmSystemTools::ConvertToUnixSlashes(path);
-      this->SetHomeDirectory(path);
-      // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
-      // NOLINTNEXTLINE(bugprone-branch-clone)
-    } else if (cmHasLiteralPrefix(arg, "-O")) {
-      // There is no local generate anymore.  Ignore -O option.
-    } else if (cmHasLiteralPrefix(arg, "-B")) {
-      std::string path = arg.substr(2);
-      if (path.empty()) {
-        ++i;
-        if (i >= args.size()) {
-          cmSystemTools::Error("No build directory specified for -B");
-          return;
-        }
-        path = args[i];
-        if (path[0] == '-') {
-          cmSystemTools::Error("No build directory specified for -B");
-          return;
-        }
-      }
+  auto SourceArgLambda = [](std::string const& value, cmake* state) -> bool {
+    std::string path = cmSystemTools::CollapseFullPath(value);
+    cmSystemTools::ConvertToUnixSlashes(path);
+    state->SetHomeDirectory(path);
+    return true;
+  };
+
+  auto BuildArgLambda = [&](std::string const& value, cmake* state) -> bool {
+    std::string path = cmSystemTools::CollapseFullPath(value);
+    cmSystemTools::ConvertToUnixSlashes(path);
+    state->SetHomeOutputDirectory(path);
+    haveBArg = true;
+    return true;
+  };
 
-      path = cmSystemTools::CollapseFullPath(path);
-      cmSystemTools::ConvertToUnixSlashes(path);
-      this->SetHomeOutputDirectory(path);
-      haveBArg = true;
-    } else if ((i < args.size() - 2) &&
-               cmHasLiteralPrefix(arg, "--check-build-system")) {
-      this->CheckBuildSystemArgument = args[++i];
-      this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
-    } else if ((i < args.size() - 1) &&
-               cmHasLiteralPrefix(arg, "--check-stamp-file")) {
-      this->CheckStampFile = args[++i];
-    } else if ((i < args.size() - 1) &&
-               cmHasLiteralPrefix(arg, "--check-stamp-list")) {
-      this->CheckStampList = args[++i];
-    } else if (arg == "--regenerate-during-build"_s) {
-      this->RegenerateDuringBuild = true;
+  auto PlatformLambda = [&](std::string const& value, cmake* state) -> bool {
+    if (havePlatform) {
+      cmSystemTools::Error("Multiple -A options not allowed");
+      return false;
     }
-#if defined(CMAKE_HAVE_VS_GENERATORS)
-    else if ((i < args.size() - 1) &&
-             cmHasLiteralPrefix(arg, "--vs-solution-file")) {
-      this->VSSolutionFile = args[++i];
+    state->SetGeneratorPlatform(value);
+    havePlatform = true;
+    return true;
+  };
+
+  auto ToolsetLamda = [&](std::string const& value, cmake* state) -> bool {
+    if (haveToolset) {
+      cmSystemTools::Error("Multiple -T options not allowed");
+      return false;
     }
+    state->SetGeneratorToolset(value);
+    haveToolset = true;
+    return true;
+  };
+
+  std::vector<CommandArgument> arguments = {
+    CommandArgument{ "-S", "No source directory specified for -S",
+                     CommandArgument::Values::One, SourceArgLambda },
+    CommandArgument{ "-H", "No source directory specified for -H",
+                     CommandArgument::Values::One, SourceArgLambda },
+    CommandArgument{ "-O", CommandArgument::Values::Zero,
+                     IgnoreAndTrueLambda },
+    CommandArgument{ "-B", "No build directory specified for -B",
+                     CommandArgument::Values::One, BuildArgLambda },
+    CommandArgument{ "-P", "-P must be followed by a file name.",
+                     CommandArgument::Values::One,
+                     [&](std::string const&, cmake*) -> bool {
+                       scriptMode = true;
+                       return true;
+                     } },
+    CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
+                     CommandArgument::Values::One, IgnoreAndTrueLambda },
+    CommandArgument{ "-C", "-C must be followed by a file name.",
+                     CommandArgument::Values::One, IgnoreAndTrueLambda },
+    CommandArgument{ "-U", "-U must be followed with VAR.",
+                     CommandArgument::Values::One, IgnoreAndTrueLambda },
+    CommandArgument{ "-W", "-W must be followed with [no-]<name>.",
+                     CommandArgument::Values::One, IgnoreAndTrueLambda },
+    CommandArgument{ "-A", "No platform specified for -A",
+                     CommandArgument::Values::One, PlatformLambda },
+    CommandArgument{ "-T", "No toolset specified for -T",
+                     CommandArgument::Values::One, ToolsetLamda },
+
+    CommandArgument{ "--check-build-system", CommandArgument::Values::Two,
+                     [](std::string const& value, cmake* state) -> bool {
+                       std::vector<std::string> values = cmExpandedList(value);
+                       state->CheckBuildSystemArgument = values[0];
+                       state->ClearBuildSystem = (atoi(values[1].c_str()) > 0);
+                       return true;
+                     } },
+    CommandArgument{ "--check-stamp-file", CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       state->CheckStampFile = value;
+                       return true;
+                     } },
+    CommandArgument{ "--check-stamp-list", CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       state->CheckStampList = value;
+                       return true;
+                     } },
+    CommandArgument{ "--regenerate-during-build",
+                     CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       state->RegenerateDuringBuild = true;
+                       return true;
+                     } },
+
+    CommandArgument{ "--find-package", CommandArgument::Values::Zero,
+                     IgnoreAndTrueLambda },
+
+    CommandArgument{ "--graphviz", "No file specified for --graphviz",
+                     CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       std::string path =
+                         cmSystemTools::CollapseFullPath(value);
+                       cmSystemTools::ConvertToUnixSlashes(path);
+                       state->GraphVizFile = path;
+                       return true;
+                     } },
+
+    CommandArgument{ "--debug-trycompile", CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       std::cout << "debug trycompile on\n";
+                       state->DebugTryCompileOn();
+                       return true;
+                     } },
+    CommandArgument{ "--debug-output", CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       std::cout << "Running with debug output on.\n";
+                       state->SetDebugOutputOn(true);
+                       return true;
+                     } },
+
+    CommandArgument{ "--log-level", "Invalid level specified for --log-level",
+                     CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       const auto logLevel = StringToLogLevel(value);
+                       if (logLevel == LogLevel::LOG_UNDEFINED) {
+                         cmSystemTools::Error(
+                           "Invalid level specified for --log-level");
+                         return false;
+                       }
+                       state->SetLogLevel(logLevel);
+                       state->LogLevelWasSetViaCLI = true;
+                       return true;
+                     } },
+    // This is supported for backward compatibility. This option only
+    // appeared in the 3.15.x release series and was renamed to
+    // --log-level in 3.16.0
+    CommandArgument{ "--loglevel", "Invalid level specified for --loglevel",
+                     CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       const auto logLevel = StringToLogLevel(value);
+                       if (logLevel == LogLevel::LOG_UNDEFINED) {
+                         cmSystemTools::Error(
+                           "Invalid level specified for --loglevel");
+                         return false;
+                       }
+                       state->SetLogLevel(logLevel);
+                       state->LogLevelWasSetViaCLI = true;
+                       return true;
+                     } },
+
+    CommandArgument{ "--log-context", CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       state->SetShowLogContext(true);
+                       return true;
+                     } },
+    CommandArgument{
+      "--debug-find", CommandArgument::Values::Zero,
+      [](std::string const&, cmake* state) -> bool {
+        std::cout << "Running with debug output on for the `find` commands.\n";
+        state->SetDebugFindOutputOn(true);
+        return true;
+      } },
+    CommandArgument{ "--trace-expand", CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       std::cout << "Running with expanded trace output on.\n";
+                       state->SetTrace(true);
+                       state->SetTraceExpand(true);
+                       return true;
+                     } },
+    CommandArgument{ "--trace-format", CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       state->SetTrace(true);
+                       const auto traceFormat = StringToTraceFormat(value);
+                       if (traceFormat == TraceFormat::TRACE_UNDEFINED) {
+                         cmSystemTools::Error(
+                           "Invalid format specified for --trace-format. "
+                           "Valid formats are human, json-v1.");
+                         return false;
+                       }
+                       state->SetTraceFormat(traceFormat);
+                       return true;
+                     } },
+    CommandArgument{ "--trace-source", CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       std::string file(value);
+                       cmSystemTools::ConvertToUnixSlashes(file);
+                       state->AddTraceSource(file);
+                       state->SetTrace(true);
+                       return true;
+                     } },
+    CommandArgument{ "--trace-redirect", CommandArgument::Values::One,
+                     [](std::string const& value, cmake* state) -> bool {
+                       std::string file(value);
+                       cmSystemTools::ConvertToUnixSlashes(file);
+                       state->SetTraceFile(file);
+                       state->SetTrace(true);
+                       return true;
+                     } },
+    CommandArgument{ "--trace", CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       std::cout << "Running with trace output on.\n";
+                       state->SetTrace(true);
+                       state->SetTraceExpand(false);
+                       return true;
+                     } },
+    CommandArgument{ "--warn-uninitialized", CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       std::cout << "Warn about uninitialized values.\n";
+                       state->SetWarnUninitialized(true);
+                       return true;
+                     } },
+    CommandArgument{ "--warn-unused-vars", CommandArgument::Values::Zero,
+                     IgnoreAndTrueLambda }, // Option was removed.
+    CommandArgument{ "--no-warn-unused-cli", CommandArgument::Values::Zero,
+                     [](std::string const&, cmake* state) -> bool {
+                       std::cout
+                         << "Not searching for unused variables given on the "
+                         << "command line.\n";
+                       state->SetWarnUnusedCli(false);
+                       return true;
+                     } },
+    CommandArgument{
+      "--check-system-vars", CommandArgument::Values::Zero,
+      [](std::string const&, cmake* state) -> bool {
+        std::cout << "Also check system files when warning about unused and "
+                  << "uninitialized variables.\n";
+        state->SetCheckSystemVars(true);
+        return true;
+      } }
+  };
+
+#if defined(CMAKE_HAVE_VS_GENERATORS)
+  arguments.emplace_back("--vs-solution-file", CommandArgument::Values::One,
+                         [](std::string const& value, cmake* state) -> bool {
+                           state->VSSolutionFile = value;
+                           return true;
+                         });
 #endif
-    else if (cmHasLiteralPrefix(arg, "-D") || cmHasLiteralPrefix(arg, "-U") ||
-             cmHasLiteralPrefix(arg, "-C")) {
-      // skip for now
-      // in case '-[DUC] argval' var' is given, also skip the next
-      // in case '-[DUC]argval' is given, don't skip the next
-      if (arg.size() == 2) {
-        ++i;
-      }
-      // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165
-      // NOLINTNEXTLINE(bugprone-branch-clone)
-    } else if (cmHasLiteralPrefix(arg, "-P")) {
-      // skip for now
-      i++;
-    } else if (cmHasLiteralPrefix(arg, "--find-package")) {
-      // skip for now
-      i++;
-    } else if (cmHasLiteralPrefix(arg, "-W")) {
-      // skip for now
-    } else if (cmHasLiteralPrefix(arg, "--graphviz=")) {
-      std::string path = arg.substr(strlen("--graphviz="));
-      path = cmSystemTools::CollapseFullPath(path);
-      cmSystemTools::ConvertToUnixSlashes(path);
-      this->GraphVizFile = path;
-      if (this->GraphVizFile.empty()) {
-        cmSystemTools::Error("No file specified for --graphviz");
-        return;
-      }
-    } else if (cmHasLiteralPrefix(arg, "--debug-trycompile")) {
-      std::cout << "debug trycompile on\n";
-      this->DebugTryCompileOn();
-    } else if (cmHasLiteralPrefix(arg, "--debug-output")) {
-      std::cout << "Running with debug output on.\n";
-      this->SetDebugOutputOn(true);
-    } else if (cmHasLiteralPrefix(arg, "--log-level=")) {
-      const auto logLevel =
-        StringToLogLevel(arg.substr(sizeof("--log-level=") - 1));
-      if (logLevel == LogLevel::LOG_UNDEFINED) {
-        cmSystemTools::Error("Invalid level specified for --log-level");
-        return;
-      }
-      this->SetLogLevel(logLevel);
-      this->LogLevelWasSetViaCLI = true;
-    } else if (cmHasLiteralPrefix(arg, "--loglevel=")) {
-      // This is supported for backward compatibility. This option only
-      // appeared in the 3.15.x release series and was renamed to
-      // --log-level in 3.16.0
-      const auto logLevel =
-        StringToLogLevel(arg.substr(sizeof("--loglevel=") - 1));
-      if (logLevel == LogLevel::LOG_UNDEFINED) {
-        cmSystemTools::Error("Invalid level specified for --loglevel");
-        return;
-      }
-      this->SetLogLevel(logLevel);
-      this->LogLevelWasSetViaCLI = true;
-    } else if (arg == "--log-context"_s) {
-      this->SetShowLogContext(true);
-    } else if (cmHasLiteralPrefix(arg, "--debug-find")) {
-      std::cout << "Running with debug output on for the `find` commands.\n";
-      this->SetDebugFindOutputOn(true);
-    } else if (cmHasLiteralPrefix(arg, "--trace-expand")) {
-      std::cout << "Running with expanded trace output on.\n";
-      this->SetTrace(true);
-      this->SetTraceExpand(true);
-    } else if (cmHasLiteralPrefix(arg, "--trace-format=")) {
-      this->SetTrace(true);
-      const auto traceFormat =
-        StringToTraceFormat(arg.substr(strlen("--trace-format=")));
-      if (traceFormat == TraceFormat::TRACE_UNDEFINED) {
-        cmSystemTools::Error("Invalid format specified for --trace-format. "
-                             "Valid formats are human, json-v1.");
-        return;
-      }
-      this->SetTraceFormat(traceFormat);
-    } else if (cmHasLiteralPrefix(arg, "--trace-source=")) {
-      std::string file = arg.substr(strlen("--trace-source="));
-      cmSystemTools::ConvertToUnixSlashes(file);
-      this->AddTraceSource(file);
-      this->SetTrace(true);
-    } else if (cmHasLiteralPrefix(arg, "--trace-redirect=")) {
-      std::string file = arg.substr(strlen("--trace-redirect="));
-      cmSystemTools::ConvertToUnixSlashes(file);
-      this->SetTraceFile(file);
-      this->SetTrace(true);
-    } else if (cmHasLiteralPrefix(arg, "--trace")) {
-      std::cout << "Running with trace output on.\n";
-      this->SetTrace(true);
-      this->SetTraceExpand(false);
-    } else if (cmHasLiteralPrefix(arg, "--warn-uninitialized")) {
-      std::cout << "Warn about uninitialized values.\n";
-      this->SetWarnUninitialized(true);
-    } else if (cmHasLiteralPrefix(arg, "--warn-unused-vars")) {
-      // Option was removed.
-    } else if (cmHasLiteralPrefix(arg, "--no-warn-unused-cli")) {
-      std::cout << "Not searching for unused variables given on the "
-                << "command line.\n";
-      this->SetWarnUnusedCli(false);
-    } else if (cmHasLiteralPrefix(arg, "--check-system-vars")) {
-      std::cout << "Also check system files when warning about unused and "
-                << "uninitialized variables.\n";
-      this->SetCheckSystemVars(true);
-    } else if (cmHasLiteralPrefix(arg, "-A")) {
-      std::string value = arg.substr(2);
-      if (value.empty()) {
-        ++i;
-        if (i >= args.size()) {
-          cmSystemTools::Error("No platform specified for -A");
-          return;
-        }
-        value = args[i];
-      }
-      if (havePlatform) {
-        cmSystemTools::Error("Multiple -A options not allowed");
-        return;
-      }
-      this->SetGeneratorPlatform(value);
-      havePlatform = true;
-    } else if (cmHasLiteralPrefix(arg, "-T")) {
-      std::string value = arg.substr(2);
-      if (value.empty()) {
-        ++i;
-        if (i >= args.size()) {
-          cmSystemTools::Error("No toolset specified for -T");
-          return;
-        }
-        value = args[i];
-      }
-      if (haveToolset) {
-        cmSystemTools::Error("Multiple -T options not allowed");
-        return;
-      }
-      this->SetGeneratorToolset(value);
-      haveToolset = true;
-    } else if (cmHasLiteralPrefix(arg, "-G")) {
-      std::string value = arg.substr(2);
-      if (value.empty()) {
-        ++i;
-        if (i >= args.size()) {
-          cmSystemTools::Error("No generator specified for -G");
-          this->PrintGeneratorList();
-          return;
-        }
-        value = args[i];
-      }
-      if (!this->CreateAndSetGlobalGenerator(value, true)) {
-        return;
-      }
+
 #if !defined(CMAKE_BOOTSTRAP)
-    } else if (cmHasLiteralPrefix(arg, "--profiling-format=")) {
-      profilingFormat = arg.substr(strlen("--profiling-format="));
-      if (profilingFormat.empty()) {
-        cmSystemTools::Error("No format specified for --profiling-format");
-      }
-    } else if (cmHasLiteralPrefix(arg, "--profiling-output=")) {
-      profilingOutput = arg.substr(strlen("--profiling-output="));
-      profilingOutput = cmSystemTools::CollapseFullPath(profilingOutput);
+  arguments.emplace_back("--profiling-format",
+                         "No format specified for --profiling-format",
+                         CommandArgument::Values::One,
+                         [&](std::string const& value, cmake*) -> bool {
+                           profilingFormat = value;
+                           return true;
+                         });
+  arguments.emplace_back(
+    "--profiling-output", "No path specified for --profiling-output",
+    CommandArgument::Values::One,
+    [&](std::string const& value, cmake*) -> bool {
+      profilingOutput = cmSystemTools::CollapseFullPath(value);
       cmSystemTools::ConvertToUnixSlashes(profilingOutput);
-      if (profilingOutput.empty()) {
-        cmSystemTools::Error("No path specified for --profiling-output");
-      }
-    } else if (cmHasLiteralPrefix(arg, "--preset=")) {
-      presetName = arg.substr(strlen("--preset="));
-      if (presetName.empty()) {
-        cmSystemTools::Error("No preset specified for --preset");
+      return true;
+    });
+  arguments.emplace_back("--preset", "No preset specified for --preset",
+                         CommandArgument::Values::One,
+                         [&](std::string const& value, cmake*) -> bool {
+                           presetName = value;
+                           return true;
+                         });
+  arguments.emplace_back(
+    "--list-presets", CommandArgument::Values::ZeroOrOne,
+    [&](std::string const& value, cmake*) -> bool {
+      if (value.empty() || value == "configure") {
+        listPresets = ListPresets::Configure;
+      } else if (value == "build") {
+        listPresets = ListPresets::Build;
+      } else if (value == "test") {
+        listPresets = ListPresets::Test;
+      } else if (value == "all") {
+        listPresets = ListPresets::All;
+      } else {
+        cmSystemTools::Error(
+          "Invalid value specified for --list-presets.\n"
+          "Valid values are configure, build, test, or all. "
+          "When no value is passed the default is configure.");
+        return false;
       }
-    } else if (cmHasLiteralPrefix(arg, "--list-presets")) {
-      listPresets = true;
+
+      return true;
+    });
+
 #endif
+
+  bool badGeneratorName = false;
+  CommandArgument generatorCommand(
+    "-G", "No generator specified for -G", CommandArgument::Values::One,
+    [&](std::string const& value, cmake* state) -> bool {
+      bool valid = state->CreateAndSetGlobalGenerator(value, true);
+      badGeneratorName = !valid;
+      return valid;
+    });
+
+  for (decltype(args.size()) i = 1; i < args.size(); ++i) {
+    // iterate each argument
+    std::string const& arg = args[i];
+
+    // Generator flag has special handling for when to print help
+    // so it becomes the exception
+    if (generatorCommand.matches(arg)) {
+      bool parsed = generatorCommand.parse(arg, i, args, this);
+      if (!parsed && !badGeneratorName) {
+        this->PrintGeneratorList();
+        return;
+      }
+      continue;
     }
-    // no option assume it is the path to the source or an existing build
-    else {
+
+    bool matched = false;
+    bool parsedCorrectly = true; // needs to be true so we can ignore
+                                 // arguments so as -E
+    for (auto const& m : arguments) {
+      if (m.matches(arg)) {
+        matched = true;
+        parsedCorrectly = m.parse(arg, i, args, this);
+        break;
+      }
+    }
+
+    // We have an issue where arguments to a "-P" script mode
+    // can be provided before the "-P" argument. This means
+    // that we need to lazily check this argument after checking
+    // all args.
+    // Additionally it can't be the source/binary tree location
+    if (!parsedCorrectly) {
+      cmSystemTools::Error("Run 'cmake --help' for all supported options.");
+      exit(1);
+    } else if (!matched && cmHasLiteralPrefix(arg, "-")) {
+      possibleUnknownArg = arg;
+    } else if (!matched) {
       this->SetDirectoriesFromFile(arg);
     }
-    // Empty instance, platform and toolset if only a generator is specified
-    if (this->GlobalGenerator) {
-      this->GeneratorInstance = "";
-      if (!this->GeneratorPlatformSet) {
-        this->GeneratorPlatform = "";
-      }
-      if (!this->GeneratorToolsetSet) {
-        this->GeneratorToolset = "";
-      }
+  }
+
+  if (!possibleUnknownArg.empty() && !scriptMode) {
+    cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg));
+    cmSystemTools::Error("Run 'cmake --help' for all supported options.");
+    exit(1);
+  }
+
+  // Empty instance, platform and toolset if only a generator is specified
+  if (this->GlobalGenerator) {
+    this->GeneratorInstance = "";
+    if (!this->GeneratorPlatformSet) {
+      this->GeneratorPlatform = "";
+    }
+    if (!this->GeneratorToolsetSet) {
+      this->GeneratorToolset = "";
     }
   }
 
@@ -1031,7 +1147,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
   }
 
 #if !defined(CMAKE_BOOTSTRAP)
-  if (listPresets || !presetName.empty()) {
+  if (listPresets != ListPresets::None || !presetName.empty()) {
     cmCMakePresetsFile settingsFile;
     auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
     if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
@@ -1040,12 +1156,24 @@ void cmake::SetArgs(const std::vector<std::string>& args)
                  ": ", cmCMakePresetsFile::ResultToString(result)));
       return;
     }
-    if (listPresets) {
-      this->PrintPresetList(settingsFile);
+
+    if (listPresets != ListPresets::None) {
+      if (listPresets == ListPresets::Configure) {
+        this->PrintPresetList(settingsFile);
+      } else if (listPresets == ListPresets::Build) {
+        settingsFile.PrintBuildPresetList();
+      } else if (listPresets == ListPresets::Test) {
+        settingsFile.PrintTestPresetList();
+      } else if (listPresets == ListPresets::All) {
+        settingsFile.PrintAllPresets();
+      }
+
+      this->SetWorkingMode(WorkingMode::HELP_MODE);
       return;
     }
-    auto preset = settingsFile.Presets.find(presetName);
-    if (preset == settingsFile.Presets.end()) {
+
+    auto preset = settingsFile.ConfigurePresets.find(presetName);
+    if (preset == settingsFile.ConfigurePresets.end()) {
       cmSystemTools::Error(cmStrCat("No such preset in ",
                                     this->GetHomeDirectory(), ": \"",
                                     presetName, '"'));
@@ -1474,44 +1602,16 @@ void cmake::PrintPresetList(const cmCMakePresetsFile& file) const
 {
   std::vector<GeneratorInfo> generators;
   this->GetRegisteredGenerators(generators, false);
+  auto filter =
+    [&generators](const cmCMakePresetsFile::ConfigurePreset& preset) -> bool {
+    auto condition = [&preset](const GeneratorInfo& info) -> bool {
+      return info.name == preset.Generator;
+    };
+    auto it = std::find_if(generators.begin(), generators.end(), condition);
+    return it != generators.end();
+  };
 
-  std::vector<cmCMakePresetsFile::UnexpandedPreset> presets;
-  for (auto const& p : file.PresetOrder) {
-    auto const& preset = file.Presets.at(p);
-    if (!preset.Unexpanded.Hidden && preset.Expanded &&
-        std::find_if(generators.begin(), generators.end(),
-                     [&preset](const GeneratorInfo& info) {
-                       return info.name == preset.Unexpanded.Generator;
-                     }) != generators.end()) {
-      presets.push_back(preset.Unexpanded);
-    }
-  }
-
-  if (presets.empty()) {
-    return;
-  }
-
-  std::cout << "Available presets:\n\n";
-
-  auto longestPresetName =
-    std::max_element(presets.begin(), presets.end(),
-                     [](const cmCMakePresetsFile::UnexpandedPreset& a,
-                        const cmCMakePresetsFile::UnexpandedPreset& b) {
-                       return a.Name.length() < b.Name.length();
-                     });
-  auto longestLength = longestPresetName->Name.length();
-
-  for (auto const& preset : presets) {
-    std::cout << "  \"" << preset.Name << '"';
-    auto const& description = preset.DisplayName;
-    if (!description.empty()) {
-      for (std::size_t i = 0; i < longestLength - preset.Name.length(); ++i) {
-        std::cout << ' ';
-      }
-      std::cout << " - " << description;
-    }
-    std::cout << '\n';
-  }
+  file.PrintConfigurePresetList(filter);
 }
 #endif
 
@@ -1951,7 +2051,7 @@ int cmake::ActualConfigure()
     }
   }
 
-  auto& mf = this->GlobalGenerator->GetMakefiles()[0];
+  const auto& mf = this->GlobalGenerator->GetMakefiles()[0];
   if (mf->IsOn("CTEST_USE_LAUNCHERS") &&
       !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) {
     cmSystemTools::Error(
@@ -2115,7 +2215,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
 #endif
   // Add any cache args
   if (!this->SetCacheArgs(args)) {
-    cmSystemTools::Error("Problem processing arguments. Aborting.\n");
+    cmSystemTools::Error("Run 'cmake --help' for all supported options.");
     return -1;
   }
 #ifndef CMAKE_BOOTSTRAP
@@ -2293,12 +2393,12 @@ cmProp cmake::GetCacheDefinition(const std::string& name) const
   return this->State->GetInitializedCacheValue(name);
 }
 
-void cmake::AddScriptingCommands()
+void cmake::AddScriptingCommands() const
 {
   GetScriptingCommands(this->GetState());
 }
 
-void cmake::AddProjectCommands()
+void cmake::AddProjectCommands() const
 {
   GetProjectCommands(this->GetState());
 }
@@ -2573,8 +2673,7 @@ int cmake::CheckBuildSystem()
 
   if (this->ClearBuildSystem) {
     // Get the generator used for this build system.
-    const char* genName =
-      cmToCStr(mf.GetDefinition("CMAKE_DEPENDS_GENERATOR"));
+    std::string genName = mf.GetSafeDefinition("CMAKE_DEPENDS_GENERATOR");
     if (!cmNonempty(genName)) {
       genName = "Unix Makefiles";
     }
@@ -2981,15 +3080,119 @@ std::vector<std::string> cmake::GetDebugConfigs()
   return configs;
 }
 
-int cmake::Build(int jobs, const std::string& dir,
-                 const std::vector<std::string>& targets,
-                 const std::string& config,
-                 const std::vector<std::string>& nativeOptions, bool clean,
-                 bool verbose)
+int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
+                 std::string config, std::vector<std::string> nativeOptions,
+                 bool clean, bool verbose, const std::string& presetName,
+                 bool listPresets)
 {
-
   this->SetHomeDirectory("");
   this->SetHomeOutputDirectory("");
+
+#if !defined(CMAKE_BOOTSTRAP)
+  if (!presetName.empty() || listPresets) {
+    this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+    this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+
+    cmCMakePresetsFile settingsFile;
+    auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
+    if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) {
+      cmSystemTools::Error(
+        cmStrCat("Could not read presets from ", this->GetHomeDirectory(),
+                 ": ", cmCMakePresetsFile::ResultToString(result)));
+      return 1;
+    }
+
+    if (listPresets) {
+      settingsFile.PrintBuildPresetList();
+      return 0;
+    }
+
+    auto presetPair = settingsFile.BuildPresets.find(presetName);
+    if (presetPair == settingsFile.BuildPresets.end()) {
+      cmSystemTools::Error(cmStrCat("No such build preset in ",
+                                    this->GetHomeDirectory(), ": \"",
+                                    presetName, '"'));
+      settingsFile.PrintBuildPresetList();
+      return 1;
+    }
+
+    if (presetPair->second.Unexpanded.Hidden) {
+      cmSystemTools::Error(cmStrCat("Cannot use hidden build preset in ",
+                                    this->GetHomeDirectory(), ": \"",
+                                    presetName, '"'));
+      settingsFile.PrintBuildPresetList();
+      return 1;
+    }
+
+    auto const& expandedPreset = presetPair->second.Expanded;
+    if (!expandedPreset) {
+      cmSystemTools::Error(cmStrCat("Could not evaluate build preset \"",
+                                    presetName,
+                                    "\": Invalid macro expansion"));
+      settingsFile.PrintBuildPresetList();
+      return 1;
+    }
+
+    auto configurePresetPair =
+      settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
+    if (configurePresetPair == settingsFile.ConfigurePresets.end()) {
+      cmSystemTools::Error(cmStrCat("No such configure preset in ",
+                                    this->GetHomeDirectory(), ": \"",
+                                    expandedPreset->ConfigurePreset, '"'));
+      this->PrintPresetList(settingsFile);
+      return 1;
+    }
+
+    if (configurePresetPair->second.Unexpanded.Hidden) {
+      cmSystemTools::Error(cmStrCat("Cannot use hidden configure preset in ",
+                                    this->GetHomeDirectory(), ": \"",
+                                    expandedPreset->ConfigurePreset, '"'));
+      this->PrintPresetList(settingsFile);
+      return 1;
+    }
+
+    auto const& expandedConfigurePreset = configurePresetPair->second.Expanded;
+    if (!expandedConfigurePreset) {
+      cmSystemTools::Error(cmStrCat("Could not evaluate configure preset \"",
+                                    expandedPreset->ConfigurePreset,
+                                    "\": Invalid macro expansion"));
+      return 1;
+    }
+
+    dir = expandedConfigurePreset->BinaryDir;
+
+    this->UnprocessedPresetEnvironment = expandedPreset->Environment;
+    this->ProcessPresetEnvironment();
+
+    if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL && expandedPreset->Jobs) {
+      jobs = *expandedPreset->Jobs;
+    }
+
+    if (targets.empty()) {
+      targets.insert(targets.begin(), expandedPreset->Targets.begin(),
+                     expandedPreset->Targets.end());
+    }
+
+    if (config.empty()) {
+      config = expandedPreset->Configuration;
+    }
+
+    if (!clean && expandedPreset->CleanFirst) {
+      clean = *expandedPreset->CleanFirst;
+    }
+
+    if (!verbose && expandedPreset->Verbose) {
+      verbose = *expandedPreset->Verbose;
+    }
+
+    if (nativeOptions.empty()) {
+      nativeOptions.insert(nativeOptions.begin(),
+                           expandedPreset->NativeToolOptions.begin(),
+                           expandedPreset->NativeToolOptions.end());
+    }
+  }
+#endif
+
   if (!cmSystemTools::FileIsDirectory(dir)) {
     std::cerr << "Error: " << dir << " is not a directory\n";
     return 1;
index 1ecf2c2..82e028c 100644 (file)
@@ -238,7 +238,7 @@ public:
   bool CreateAndSetGlobalGenerator(const std::string& name, bool allowArch);
 
 #ifndef CMAKE_BOOTSTRAP
-  //! Print list of presets
+  //! Print list of configure presets
   void PrintPresetList(const cmCMakePresetsFile& file) const;
 #endif
 
@@ -411,7 +411,7 @@ public:
   WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; }
 
   //! Debug the try compile stuff by not deleting the files
-  bool GetDebugTryCompile() { return this->DebugTryCompile; }
+  bool GetDebugTryCompile() const { return this->DebugTryCompile; }
   void DebugTryCompileOn() { this->DebugTryCompile = true; }
 
   /**
@@ -456,11 +456,11 @@ public:
   void SetShowLogContext(bool b) { this->LogContext = b; }
 
   //! Do we want debug output during the cmake run.
-  bool GetDebugOutput() { return this->DebugOutput; }
+  bool GetDebugOutput() const { return this->DebugOutput; }
   void SetDebugOutputOn(bool b) { this->DebugOutput = b; }
 
   //! Do we want debug output from the find commands during the cmake run.
-  bool GetDebugFindOutput() { return this->DebugFindOutput; }
+  bool GetDebugFindOutput() const { return this->DebugFindOutput; }
   void SetDebugFindOutputOn(bool b) { this->DebugFindOutput = b; }
 
   //! Do we want trace output during the cmake run.
@@ -482,11 +482,11 @@ public:
   void SetTraceFile(std::string const& file);
   void PrintTraceFormatVersion();
 
-  bool GetWarnUninitialized() { return this->WarnUninitialized; }
+  bool GetWarnUninitialized() const { return this->WarnUninitialized; }
   void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; }
-  bool GetWarnUnusedCli() { return this->WarnUnusedCli; }
+  bool GetWarnUnusedCli() const { return this->WarnUnusedCli; }
   void SetWarnUnusedCli(bool b) { this->WarnUnusedCli = b; }
-  bool GetCheckSystemVars() { return this->CheckSystemVars; }
+  bool GetCheckSystemVars() const { return this->CheckSystemVars; }
   void SetCheckSystemVars(bool b) { this->CheckSystemVars = b; }
 
   void MarkCliAsUsed(const std::string& variable);
@@ -556,10 +556,10 @@ public:
     cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
 
   //! run the --build option
-  int Build(int jobs, const std::string& dir,
-            const std::vector<std::string>& targets, const std::string& config,
-            const std::vector<std::string>& nativeOptions, bool clean,
-            bool verbose);
+  int Build(int jobs, std::string dir, std::vector<std::string> targets,
+            std::string config, std::vector<std::string> nativeOptions,
+            bool clean, bool verbose, const std::string& presetName,
+            bool listPresets);
 
   //! run the --open option
   bool Open(const std::string& dir, bool dryRun);
@@ -591,8 +591,8 @@ protected:
   using RegisteredExtraGeneratorsVector =
     std::vector<cmExternalMakefileProjectGeneratorFactory*>;
   RegisteredExtraGeneratorsVector ExtraGenerators;
-  void AddScriptingCommands();
-  void AddProjectCommands();
+  void AddScriptingCommands() const;
+  void AddProjectCommands() const;
   void AddDefaultGenerators();
   void AddDefaultExtraGenerators();
 
@@ -811,6 +811,7 @@ private:
   F(cxx_std_14)                                                               \
   F(cxx_std_17)                                                               \
   F(cxx_std_20)                                                               \
+  F(cxx_std_23)                                                               \
   FOR_EACH_CXX98_FEATURE(F)                                                   \
   FOR_EACH_CXX11_FEATURE(F)                                                   \
   FOR_EACH_CXX14_FEATURE(F)
@@ -820,4 +821,5 @@ private:
   F(cuda_std_11)                                                              \
   F(cuda_std_14)                                                              \
   F(cuda_std_17)                                                              \
-  F(cuda_std_20)
+  F(cuda_std_20)                                                              \
+  F(cuda_std_23)
index f7734a6..88ba011 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <climits>
 #include <cstring>
 #include <iostream>
@@ -19,6 +18,7 @@
 
 #include <cm3p/uv.h>
 
+#include "cmCommandLineArgument.h"
 #include "cmConsoleBuf.h"
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
 #include "cmGlobalGenerator.h"
@@ -64,7 +64,7 @@ const char* cmDocumentationUsageNote[][2] = {
 
 const char* cmDocumentationOptions[][2] = {
   CMAKE_STANDARD_OPTIONS_TABLE,
-  { "--preset=<preset>", "Specify a configure preset." },
+  { "--preset <preset>,--preset=<preset>", "Specify a configure preset." },
   { "--list-presets", "List available presets." },
   { "-E", "CMake command mode." },
   { "-L[A][H]", "List non-advanced cached variables." },
@@ -213,61 +213,114 @@ int do_cmake(int ac, char const* const* av)
   }
 #endif
 
+  bool wizard_mode = false;
   bool sysinfo = false;
   bool list_cached = false;
   bool list_all_cached = false;
   bool list_help = false;
   bool view_only = false;
   cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
-  std::vector<std::string> args;
-  for (int i = 0; i < ac; ++i) {
-    if (strcmp(av[i], "-i") == 0) {
-      /* clang-format off */
-      std::cerr <<
-        "The \"cmake -i\" wizard mode is no longer supported.\n"
-        "Use the -D option to set cache values on the command line.\n"
-        "Use cmake-gui or ccmake for an interactive dialog.\n";
-      /* clang-format on */
-      return 1;
-    }
-    if (strcmp(av[i], "--system-information") == 0) {
-      sysinfo = true;
-    } else if (strcmp(av[i], "-N") == 0) {
-      view_only = true;
-    } else if (strcmp(av[i], "-L") == 0) {
-      list_cached = true;
-    } else if (strcmp(av[i], "-LA") == 0) {
-      list_all_cached = true;
-    } else if (strcmp(av[i], "-LH") == 0) {
-      list_cached = true;
-      list_help = true;
-    } else if (strcmp(av[i], "-LAH") == 0) {
-      list_all_cached = true;
-      list_help = true;
-    } else if (cmHasLiteralPrefix(av[i], "-P")) {
-      if (i == ac - 1) {
-        cmSystemTools::Error("No script specified for argument -P");
-        return 1;
+  std::vector<std::string> parsedArgs;
+
+  using CommandArgument =
+    cmCommandLineArgument<bool(std::string const& value)>;
+  std::vector<CommandArgument> arguments = {
+    CommandArgument{
+      "-i", CommandArgument::Values::Zero,
+      [&wizard_mode](std::string const&) -> bool {
+        /* clang-format off */
+        std::cerr <<
+          "The \"cmake -i\" wizard mode is no longer supported.\n"
+          "Use the -D option to set cache values on the command line.\n"
+          "Use cmake-gui or ccmake for an interactive dialog.\n";
+        /* clang-format on */
+        wizard_mode = true;
+        return true;
+      } },
+    CommandArgument{ "--system-information", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       sysinfo = true;
+                       return true;
+                     } },
+    CommandArgument{ "-N", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       view_only = true;
+                       return true;
+                     } },
+    CommandArgument{ "-LAH", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_all_cached = true;
+                       list_help = true;
+                       return true;
+                     } },
+    CommandArgument{ "-LA", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_all_cached = true;
+                       return true;
+                     } },
+    CommandArgument{ "-LH", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_cached = true;
+                       list_help = true;
+                       return true;
+                     } },
+    CommandArgument{ "-L", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       list_cached = true;
+                       return true;
+                     } },
+    CommandArgument{ "-P", "No script specified for argument -P",
+                     CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       workingMode = cmake::SCRIPT_MODE;
+                       parsedArgs.emplace_back("-P");
+                       parsedArgs.push_back(value);
+                       return true;
+                     } },
+    CommandArgument{ "--find-package", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       workingMode = cmake::FIND_PACKAGE_MODE;
+                       parsedArgs.emplace_back("--find-package");
+                       return true;
+                     } },
+    CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       workingMode = cmake::HELP_MODE;
+                       parsedArgs.emplace_back("--list-presets");
+                       return true;
+                     } },
+  };
+
+  std::vector<std::string> inputArgs;
+  inputArgs.reserve(ac);
+  cm::append(inputArgs, av, av + ac);
+
+  for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
+    std::string const& arg = inputArgs[i];
+    bool matched = false;
+    for (auto const& m : arguments) {
+      if (m.matches(arg)) {
+        matched = true;
+        if (m.parse(arg, i, inputArgs)) {
+          break;
+        }
+        return 1; // failed to parse
       }
-      workingMode = cmake::SCRIPT_MODE;
-      args.emplace_back(av[i]);
-      i++;
-      args.emplace_back(av[i]);
-    } else if (cmHasLiteralPrefix(av[i], "--find-package")) {
-      workingMode = cmake::FIND_PACKAGE_MODE;
-      args.emplace_back(av[i]);
-    } else if (strcmp(av[i], "--list-presets") == 0) {
-      workingMode = cmake::HELP_MODE;
-      args.emplace_back(av[i]);
-    } else {
-      args.emplace_back(av[i]);
+    }
+    if (!matched) {
+      parsedArgs.emplace_back(av[i]);
     }
   }
+
+  if (wizard_mode) {
+    return 1;
+  }
+
   if (sysinfo) {
     cmake cm(cmake::RoleProject, cmState::Project);
     cm.SetHomeDirectory("");
     cm.SetHomeOutputDirectory("");
-    int ret = cm.GetSystemInformation(args);
+    int ret = cm.GetSystemInformation(parsedArgs);
     return ret;
   }
   cmake::Role const role =
@@ -297,7 +350,7 @@ int do_cmake(int ac, char const* const* av)
   });
   cm.SetWorkingMode(workingMode);
 
-  int res = cm.Run(args, view_only);
+  int res = cm.Run(parsedArgs, view_only);
   if (list_cached || list_all_cached) {
     std::cout << "-- Cache values" << std::endl;
     std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys();
@@ -332,16 +385,9 @@ int do_cmake(int ac, char const* const* av)
 }
 
 #ifndef CMAKE_BOOTSTRAP
-int extract_job_number(int& index, char const* current, char const* next,
-                       int len_of_flag)
+int extract_job_number(std::string const& command,
+                       std::string const& jobString)
 {
-  std::string command(current);
-  std::string jobString = command.substr(len_of_flag);
-  if (jobString.empty() && next && isdigit(next[0])) {
-    ++index; // skip parsing the job number
-    jobString = std::string(next);
-  }
-
   int jobs = -1;
   unsigned long numJobs = 0;
   if (jobString.empty()) {
@@ -356,8 +402,8 @@ int extract_job_number(int& index, char const* current, char const* next,
       jobs = int(numJobs);
     }
   } else {
-    std::cerr << "'" << command.substr(0, len_of_flag) << "' invalid number '"
-              << jobString << "' given.\n\n";
+    std::cerr << "'" << command << "' invalid number '" << jobString
+              << "' given.\n\n";
   }
   return jobs;
 }
@@ -374,88 +420,135 @@ int do_build(int ac, char const* const* av)
   std::string config;
   std::string dir;
   std::vector<std::string> nativeOptions;
+  bool nativeOptionsPassed = false;
   bool cleanFirst = false;
   bool foundClean = false;
   bool foundNonClean = false;
   bool verbose = cmSystemTools::HasEnv("VERBOSE");
+  std::string presetName;
+  bool listPresets = false;
 
-  enum Doing
-  {
-    DoingNone,
-    DoingDir,
-    DoingTarget,
-    DoingConfig,
-    DoingNative
+  auto jLambda = [&](std::string const& value) -> bool {
+    jobs = extract_job_number("-j", value);
+    if (jobs < 0) {
+      dir.clear();
+    }
+    return true;
   };
-  Doing doing = DoingDir;
-  for (int i = 2; i < ac; ++i) {
-    if (doing == DoingNative) {
-      nativeOptions.emplace_back(av[i]);
-    } else if (cmHasLiteralPrefix(av[i], "-j")) {
-      const char* nextArg = ((i + 1 < ac) ? av[i + 1] : nullptr);
-      jobs = extract_job_number(i, av[i], nextArg, sizeof("-j") - 1);
-      if (jobs < 0) {
-        dir.clear();
+  auto parallelLambda = [&](std::string const& value) -> bool {
+    jobs = extract_job_number("--parallel", value);
+    if (jobs < 0) {
+      dir.clear();
+    }
+    return true;
+  };
+  auto targetLambda = [&](std::string const& value) -> bool {
+    if (!value.empty()) {
+      std::vector<std::string> values = cmExpandedList(value);
+      for (auto const& v : values) {
+        targets.emplace_back(v);
+        if (v == "clean") {
+          foundClean = true;
+        } else {
+          foundNonClean = true;
+        }
       }
-      doing = DoingNone;
-    } else if (cmHasLiteralPrefix(av[i], "--parallel")) {
-      const char* nextArg = ((i + 1 < ac) ? av[i + 1] : nullptr);
-      jobs = extract_job_number(i, av[i], nextArg, sizeof("--parallel") - 1);
-      if (jobs < 0) {
-        dir.clear();
+      return true;
+    }
+    return false;
+  };
+  auto verboseLambda = [&](std::string const&) -> bool {
+    verbose = true;
+    return true;
+  };
+
+  using CommandArgument =
+    cmCommandLineArgument<bool(std::string const& value)>;
+
+  std::vector<CommandArgument> arguments = {
+    CommandArgument{ "--preset", CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       presetName = value;
+                       return true;
+                     } },
+    CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       listPresets = true;
+                       return true;
+                     } },
+    CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne, jLambda },
+    CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne,
+                     parallelLambda },
+    CommandArgument{ "-t", CommandArgument::Values::OneOrMore, targetLambda },
+    CommandArgument{ "--target", CommandArgument::Values::OneOrMore,
+                     targetLambda },
+    CommandArgument{ "--config", CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       config = value;
+                       return true;
+                     } },
+    CommandArgument{ "--clean-first", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       cleanFirst = true;
+                       return true;
+                     } },
+    CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
+    CommandArgument{ "--verbose", CommandArgument::Values::Zero,
+                     verboseLambda },
+    /* legacy option no-op*/
+    CommandArgument{ "--use-stderr", CommandArgument::Values::Zero,
+                     [](std::string const&) -> bool { return true; } },
+    CommandArgument{ "--", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       nativeOptionsPassed = true;
+                       return true;
+                     } },
+  };
+
+  if (ac >= 3) {
+    std::vector<std::string> inputArgs;
+
+    bool hasPreset = false;
+    for (int i = 2; i < ac; ++i) {
+      if (strcmp(av[i], "--list-presets") == 0 ||
+          cmHasLiteralPrefix(av[i], "--preset=") ||
+          strcmp(av[i], "--preset") == 0) {
+        hasPreset = true;
+        break;
       }
-      doing = DoingNone;
-    } else if ((strcmp(av[i], "--target") == 0) ||
-               (strcmp(av[i], "-t") == 0)) {
-      doing = DoingTarget;
-    } else if (strcmp(av[i], "--config") == 0) {
-      doing = DoingConfig;
-    } else if (strcmp(av[i], "--clean-first") == 0) {
-      cleanFirst = true;
-      doing = DoingNone;
-    } else if ((strcmp(av[i], "--verbose") == 0) ||
-               (strcmp(av[i], "-v") == 0)) {
-      verbose = true;
-      doing = DoingNone;
-    } else if (strcmp(av[i], "--use-stderr") == 0) {
-      /* tolerate legacy option */
-    } else if (strcmp(av[i], "--") == 0) {
-      doing = DoingNative;
+    }
+
+    if (hasPreset) {
+      inputArgs.reserve(ac - 2);
+      cm::append(inputArgs, av + 2, av + ac);
     } else {
-      switch (doing) {
-        case DoingDir:
-          dir = cmSystemTools::CollapseFullPath(av[i]);
-          doing = DoingNone;
-          break;
-        case DoingTarget:
-          if (strlen(av[i]) == 0) {
-            std::cerr << "Warning: Argument number " << i
-                      << " after --target option is empty." << std::endl;
-          } else {
-            targets.emplace_back(av[i]);
-            if (strcmp(av[i], "clean") == 0) {
-              foundClean = true;
-            } else {
-              foundNonClean = true;
-            }
-          }
-          if (foundClean && foundNonClean) {
-            std::cerr << "Error: Building 'clean' and other targets together "
-                         "is not supported."
-                      << std::endl;
-            dir.clear();
-          }
-          break;
-        case DoingConfig:
-          config = av[i];
-          doing = DoingNone;
-          break;
-        default:
-          std::cerr << "Unknown argument " << av[i] << std::endl;
-          dir.clear();
+      dir = cmSystemTools::CollapseFullPath(av[2]);
+
+      inputArgs.reserve(ac - 3);
+      cm::append(inputArgs, av + 3, av + ac);
+    }
+
+    decltype(inputArgs.size()) i = 0;
+    for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) {
+
+      std::string const& arg = inputArgs[i];
+      for (auto const& m : arguments) {
+        if (m.matches(arg) && m.parse(arg, i, inputArgs)) {
           break;
+        }
       }
     }
+
+    if (nativeOptionsPassed) {
+      cm::append(nativeOptions, inputArgs.begin() + i, inputArgs.end());
+    }
+  }
+
+  if (foundClean && foundNonClean) {
+    std::cerr << "Error: Building 'clean' and other targets together "
+                 "is not supported."
+              << std::endl;
+    dir.clear();
   }
 
   if (jobs == cmake::NO_BUILD_PARALLEL_LEVEL) {
@@ -486,12 +579,16 @@ int do_build(int ac, char const* const* av)
     }
   }
 
-  if (dir.empty()) {
+  if (dir.empty() && presetName.empty() && !listPresets) {
     /* clang-format off */
     std::cerr <<
-      "Usage: cmake --build <dir> [options] [-- [native-options]]\n"
+      "Usage: cmake --build [<dir> | --preset <preset>] [options] [-- [native-options]]\n"
       "Options:\n"
       "  <dir>          = Project binary directory to be built.\n"
+      "  --preset <preset>, --preset=<preset>\n"
+      "                 = Specify a build preset.\n"
+      "  --list-presets\n"
+      "                 = List available build presets.\n"
       "  --parallel [<jobs>], -j [<jobs>]\n"
       "                 = Build in parallel using the given number of jobs. \n"
       "                   If <jobs> is omitted the native build tool's \n"
@@ -522,8 +619,10 @@ int do_build(int ac, char const* const* av)
   cm.SetProgressCallback([&cm](const std::string& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
-  return cm.Build(jobs, dir, targets, config, nativeOptions, cleanFirst,
-                  verbose);
+
+  return cm.Build(jobs, std::move(dir), std::move(targets), std::move(config),
+                  std::move(nativeOptions), cleanFirst, verbose, presetName,
+                  listPresets);
 #endif
 }
 
@@ -658,60 +757,59 @@ int do_install(int ac, char const* const* av)
   bool strip = false;
   bool verbose = cmSystemTools::HasEnv("VERBOSE");
 
-  enum Doing
-  {
-    DoingNone,
-    DoingDir,
-    DoingConfig,
-    DoingComponent,
-    DoingPrefix,
-    DoingDefaultDirectoryPermissions,
+  auto verboseLambda = [&](std::string const&) -> bool {
+    verbose = true;
+    return true;
   };
 
-  Doing doing = DoingDir;
+  using CommandArgument =
+    cmCommandLineArgument<bool(std::string const& value)>;
+
+  std::vector<CommandArgument> arguments = {
+    CommandArgument{ "--config", CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       config = value;
+                       return true;
+                     } },
+    CommandArgument{ "--component", CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       component = value;
+                       return true;
+                     } },
+    CommandArgument{ "--default-directory-permissions",
+                     CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       defaultDirectoryPermissions = value;
+                       return true;
+                     } },
+    CommandArgument{ "--prefix", CommandArgument::Values::One,
+                     [&](std::string const& value) -> bool {
+                       prefix = value;
+                       return true;
+                     } },
+    CommandArgument{ "--strip", CommandArgument::Values::Zero,
+                     [&](std::string const&) -> bool {
+                       strip = true;
+                       return true;
+                     } },
+    CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
+    CommandArgument{ "--verbose", CommandArgument::Values::Zero,
+                     verboseLambda }
+  };
 
-  for (int i = 2; i < ac; ++i) {
-    if (strcmp(av[i], "--config") == 0) {
-      doing = DoingConfig;
-    } else if (strcmp(av[i], "--component") == 0) {
-      doing = DoingComponent;
-    } else if (strcmp(av[i], "--prefix") == 0) {
-      doing = DoingPrefix;
-    } else if (strcmp(av[i], "--strip") == 0) {
-      strip = true;
-      doing = DoingNone;
-    } else if ((strcmp(av[i], "--verbose") == 0) ||
-               (strcmp(av[i], "-v") == 0)) {
-      verbose = true;
-      doing = DoingNone;
-    } else if (strcmp(av[i], "--default-directory-permissions") == 0) {
-      doing = DoingDefaultDirectoryPermissions;
-    } else {
-      switch (doing) {
-        case DoingDir:
-          dir = cmSystemTools::CollapseFullPath(av[i]);
-          doing = DoingNone;
-          break;
-        case DoingConfig:
-          config = av[i];
-          doing = DoingNone;
-          break;
-        case DoingComponent:
-          component = av[i];
-          doing = DoingNone;
-          break;
-        case DoingPrefix:
-          prefix = av[i];
-          doing = DoingNone;
-          break;
-        case DoingDefaultDirectoryPermissions:
-          defaultDirectoryPermissions = av[i];
-          doing = DoingNone;
-          break;
-        default:
-          std::cerr << "Unknown argument " << av[i] << std::endl;
-          dir.clear();
+  if (ac >= 3) {
+    dir = cmSystemTools::CollapseFullPath(av[2]);
+
+    std::vector<std::string> inputArgs;
+    inputArgs.reserve(ac - 3);
+    cm::append(inputArgs, av + 3, av + ac);
+    for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
+
+      std::string const& arg = inputArgs[i];
+      for (auto const& m : arguments) {
+        if (m.matches(arg) && m.parse(arg, i, inputArgs)) {
           break;
+        }
       }
     }
   }
index e2ff8b7..6713cc3 100644 (file)
@@ -20,6 +20,7 @@
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmTransformDepfile.h"
 #include "cmUVProcessChain.h"
 #include "cmUtils.hxx"
 #include "cmVersion.h"
 #if !defined(CMAKE_BOOTSTRAP)
 #  include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
 #  include "cmFileTime.h"
-#  include "cmServer.h"
-#  include "cmServerConnection.h"
 
 #  include "bindexplib.h"
 #endif
 
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+#  include <algorithm>
+
+#  include "cmCMakePath.h"
+#  include "cmProcessTools.h"
+#endif
+
 #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) && !defined(__CYGWIN__)
 #  include "cmVisualStudioWCEPlatformParser.h"
 #endif
 #include "cmsys/Directory.hxx"
 #include "cmsys/FStream.hxx"
 #include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
 #include "cmsys/Terminal.h"
 
-class cmConnection;
-
 int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
                               std::vector<std::string>::const_iterator argEnd);
 int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
                              std::vector<std::string>::const_iterator argEnd);
 
+namespace {
 void CMakeCommandUsage(const char* program)
 {
   std::ostringstream errorStream;
@@ -121,7 +127,6 @@ void CMakeCommandUsage(const char* program)
        "(on one volume)\n"
     << "  rm [-rRf] <file/dir>...    - remove files or directories, use -f to "
        "force it, r or R to remove directories and their contents recursively\n"
-    << "  server                    - start cmake in server mode\n"
     << "  sleep <number>...         - sleep for given number of seconds\n"
     << "  tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
     << "                            - create or extract a tar or zip archive\n"
@@ -147,8 +152,7 @@ void CMakeCommandUsage(const char* program)
   cmSystemTools::Error(errorStream.str());
 }
 
-static bool cmTarFilesFrom(std::string const& file,
-                           std::vector<std::string>& files)
+bool cmTarFilesFrom(std::string const& file, std::vector<std::string>& files)
 {
   if (cmSystemTools::FileIsDirectory(file)) {
     std::ostringstream e;
@@ -183,7 +187,7 @@ static bool cmTarFilesFrom(std::string const& file,
   return true;
 }
 
-static void cmCatFile(const std::string& fileToAppend)
+void cmCatFile(const std::string& fileToAppend)
 {
 #ifdef _WIN32
   _setmode(fileno(stdout), _O_BINARY);
@@ -193,7 +197,7 @@ static void cmCatFile(const std::string& fileToAppend)
   std::cout << source.rdbuf();
 }
 
-static bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
+bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
 {
   if (cmSystemTools::FileIsSymlink(dir)) {
     if (!cmSystemTools::RemoveFile(dir)) {
@@ -211,9 +215,122 @@ static bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
   return true;
 }
 
-static int HandleIWYU(const std::string& runCmd,
-                      const std::string& /* sourceFile */,
-                      const std::vector<std::string>& orig_cmd)
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+class CLIncludeParser : public cmProcessTools::LineParser
+{
+public:
+  CLIncludeParser(cm::string_view includePrefix, cmsys::ofstream& depFile,
+                  std::ostream& output)
+    : IncludePrefix(includePrefix)
+    , DepFile(depFile)
+    , Output(output)
+  {
+  }
+
+private:
+  bool ProcessLine() override
+  {
+    if (cmHasPrefix(this->Line, this->IncludePrefix)) {
+      auto path =
+        cmTrimWhitespace(this->Line.c_str() + this->IncludePrefix.size());
+      cmSystemTools::ConvertToLongPath(path);
+      this->DepFile << cmCMakePath(path).GenericString() << std::endl;
+    } else {
+      this->Output << this->Line << std::endl << std::flush;
+    }
+
+    return true;
+  }
+
+  cm::string_view IncludePrefix;
+  cmsys::ofstream& DepFile;
+  std::ostream& Output;
+};
+
+class CLOutputLogger : public cmProcessTools::OutputLogger
+{
+public:
+  CLOutputLogger(std::ostream& log)
+    : cmProcessTools::OutputLogger(log)
+  {
+  }
+
+  bool ProcessLine() override
+  {
+    *this->Log << std::flush;
+    return true;
+  }
+};
+
+int CLCompileAndDependencies(const std::vector<std::string>& args)
+{
+  std::string depFile;
+  std::string currentBinaryDir;
+  std::string filterPrefix;
+  std::vector<std::string> command;
+  for (auto it = args.cbegin() + 2; it != args.cend(); it++) {
+    if (cmHasLiteralPrefix(*it, "--dep-file=")) {
+      depFile = it->substr(11);
+    } else if (cmHasLiteralPrefix(*it, "--working-dir=")) {
+      currentBinaryDir = it->substr(14);
+    } else if (cmHasLiteralPrefix(*it, "--filter-prefix=")) {
+      filterPrefix = it->substr(16);
+    } else if (*it == "--") {
+      command.insert(command.begin(), ++it, args.cend());
+      break;
+    } else {
+      return 1;
+    }
+  }
+
+  std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp(
+    cmsysProcess_New(), cmsysProcess_Delete);
+  std::vector<const char*> argv(command.size() + 1);
+  std::transform(command.begin(), command.end(), argv.begin(),
+                 [](std::string const& s) { return s.c_str(); });
+  argv.back() = nullptr;
+  cmsysProcess_SetCommand(cp.get(), argv.data());
+  cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str());
+
+  cmsys::ofstream fout(depFile.c_str());
+  if (!fout) {
+    return 3;
+  }
+
+  CLIncludeParser includeParser(filterPrefix, fout, std::cout);
+  CLOutputLogger errLogger(std::cerr);
+
+  // Start the process.
+  cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger);
+
+  int status = 0;
+  // handle status of process
+  switch (cmsysProcess_GetState(cp.get())) {
+    case cmsysProcess_State_Exited:
+      status = cmsysProcess_GetExitValue(cp.get());
+      break;
+    case cmsysProcess_State_Exception:
+      status = 1;
+      break;
+    case cmsysProcess_State_Error:
+      status = 2;
+      break;
+    default:
+      break;
+  }
+
+  if (status != 0) {
+    // remove the dependencies file because potentially invalid
+    fout.close();
+    cmSystemTools::RemoveFile(depFile);
+  }
+
+  return status;
+}
+#endif
+
+int HandleIWYU(const std::string& runCmd, const std::string& /* sourceFile */,
+               const std::vector<std::string>& orig_cmd)
 {
   // Construct the iwyu command line by taking what was given
   // and adding all the arguments we give to the compiler.
@@ -238,8 +355,8 @@ static int HandleIWYU(const std::string& runCmd,
   return 0;
 }
 
-static int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
-                      const std::vector<std::string>& orig_cmd)
+int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
+               const std::vector<std::string>& orig_cmd)
 {
   // Construct the clang-tidy command line by taking what was given
   // and adding our compiler command line.  The clang-tidy tool will
@@ -268,9 +385,8 @@ static int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
   return ret;
 }
 
-static int HandleLWYU(const std::string& runCmd,
-                      const std::string& /* sourceFile */,
-                      const std::vector<std::string>&)
+int HandleLWYU(const std::string& runCmd, const std::string& /* sourceFile */,
+               const std::vector<std::string>&)
 {
   // Construct the ldd -r -u (link what you use lwyu) command line
   // ldd -u -r lwuy target
@@ -301,9 +417,8 @@ static int HandleLWYU(const std::string& runCmd,
   return 0;
 }
 
-static int HandleCppLint(const std::string& runCmd,
-                         const std::string& sourceFile,
-                         const std::vector<std::string>&)
+int HandleCppLint(const std::string& runCmd, const std::string& sourceFile,
+                  const std::vector<std::string>&)
 {
   // Construct the cpplint command line.
   std::vector<std::string> cpplint_cmd = cmExpandedList(runCmd, true);
@@ -329,9 +444,8 @@ static int HandleCppLint(const std::string& runCmd,
   return 0;
 }
 
-static int HandleCppCheck(const std::string& runCmd,
-                          const std::string& sourceFile,
-                          const std::vector<std::string>& orig_cmd)
+int HandleCppCheck(const std::string& runCmd, const std::string& sourceFile,
+                   const std::vector<std::string>& orig_cmd)
 {
   // Construct the cpplint command line.
   std::vector<std::string> cppcheck_cmd = cmExpandedList(runCmd, true);
@@ -394,7 +508,7 @@ struct CoCompiler
   bool NoOriginalCommand;
 };
 
-static const std::array<CoCompiler, 5> CoCompilers = {
+const std::array<CoCompiler, 5> CoCompilers = {
   { // Table of options and handlers.
     { "--cppcheck=", HandleCppCheck, false },
     { "--cpplint=", HandleCppLint, false },
@@ -408,6 +522,7 @@ struct CoCompileJob
   std::string Command;
   CoCompileHandler Handler;
 };
+}
 
 // called when args[0] == "__run_co_compile"
 int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args)
@@ -589,7 +704,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
       } else if (args[2] == "--ignore-eol") {
         filesDiffer = cmsys::SystemTools::TextFilesDiffer(args[3], args[4]);
       } else {
-        ::CMakeCommandUsage(args[0].c_str());
+        CMakeCommandUsage(args[0].c_str());
         return 2;
       }
 
@@ -624,8 +739,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
           }
         }
         if (outValid) {
-          // The def file already exists and all input files are older than the
-          // existing def file.
+          // The def file already exists and all input files are older than
+          // the existing def file.
           return 0;
         }
       }
@@ -639,7 +754,6 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
         std::string const& a = args[4];
         if (cmHasLiteralPrefix(a, "--nm=")) {
           deffile.SetNmPath(a.substr(5));
-          std::cerr << a.substr(5) << "\n";
         } else {
           std::cerr << "unknown argument: " << a << "\n";
         }
@@ -1156,6 +1270,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
         cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
         snapshot.GetDirectory().SetCurrentBinary(startOutDir);
         snapshot.GetDirectory().SetCurrentSource(startDir);
+        snapshot.GetDirectory().SetRelativePathTopSource(homeDir.c_str());
+        snapshot.GetDirectory().SetRelativePathTopBinary(homeOutDir.c_str());
         cmMakefile mf(cm.GetGlobalGenerator(), snapshot);
         auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf);
 
@@ -1165,12 +1281,19 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
       return 1;
     }
 
+#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES)
+    // Internal CMake compiler dependencies filtering
+    if (args[1] == "cmake_cl_compile_depends") {
+      return CLCompileAndDependencies(args);
+    }
+#endif
+
     // Internal CMake link script support.
     if (args[1] == "cmake_link_script" && args.size() >= 3) {
       return cmcmd::ExecuteLinkScript(args);
     }
 
-#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_NINJA)
+#if !defined(CMAKE_BOOTSTRAP)
     // Internal CMake ninja dependency scanning support.
     if (args[1] == "cmake_ninja_depends") {
       return cmcmd_cmake_ninja_depends(args.begin() + 2, args.end());
@@ -1359,47 +1482,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
     }
 
     if (args[1] == "server") {
-      const std::string pipePrefix = "--pipe=";
-      bool supportExperimental = false;
-      bool isDebug = false;
-      std::string pipe;
-
-      for (auto const& arg : cmMakeRange(args).advance(2)) {
-        if (arg == "--experimental") {
-          supportExperimental = true;
-        } else if (arg == "--debug") {
-          pipe.clear();
-          isDebug = true;
-        } else if (cmHasPrefix(arg, pipePrefix)) {
-          isDebug = false;
-          pipe = arg.substr(pipePrefix.size());
-          if (pipe.empty()) {
-            cmSystemTools::Error("No pipe given after --pipe=");
-            return 2;
-          }
-        } else {
-          cmSystemTools::Error("Unknown argument for server mode");
-          return 1;
-        }
-      }
-#if !defined(CMAKE_BOOTSTRAP)
-      cmConnection* conn;
-      if (isDebug) {
-        conn = new cmServerStdIoConnection;
-      } else {
-        conn = new cmServerPipeConnection(pipe);
-      }
-      cmServer server(conn, supportExperimental);
-      std::string errorMessage;
-      if (server.Serve(&errorMessage)) {
-        return 0;
-      }
-      cmSystemTools::Error(errorMessage);
-#else
-      static_cast<void>(supportExperimental);
-      static_cast<void>(isDebug);
-      cmSystemTools::Error("CMake was not built with server mode enabled");
-#endif
+      cmSystemTools::Error(
+        "CMake server mode has been removed in favor of the file-api.");
       return 1;
     }
 
@@ -1435,9 +1519,48 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
       return cmcmd::WindowsCEEnvironment("9.0", args[2]);
     }
 #endif
+
+    // Internal depfile transformation
+    if (args[1] == "cmake_transform_depfile" && args.size() == 10) {
+      auto format = cmDepfileFormat::GccDepfile;
+      if (args[3] == "gccdepfile") {
+        format = cmDepfileFormat::GccDepfile;
+      } else if (args[3] == "vstlog") {
+        format = cmDepfileFormat::VsTlog;
+      } else {
+        return 1;
+      }
+      // Create a cmake object instance to process dependencies.
+      // All we need is the `set` command.
+      cmake cm(cmake::RoleScript, cmState::Unknown);
+      std::string homeDir;
+      std::string startDir;
+      std::string homeOutDir;
+      std::string startOutDir;
+      homeDir = cmSystemTools::CollapseFullPath(args[4]);
+      startDir = cmSystemTools::CollapseFullPath(args[5]);
+      homeOutDir = cmSystemTools::CollapseFullPath(args[6]);
+      startOutDir = cmSystemTools::CollapseFullPath(args[7]);
+      cm.SetHomeDirectory(homeDir);
+      cm.SetHomeOutputDirectory(homeOutDir);
+      cm.GetCurrentSnapshot().SetDefaultDefinitions();
+      if (auto ggd = cm.CreateGlobalGenerator(args[2])) {
+        cm.SetGlobalGenerator(std::move(ggd));
+        cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
+        snapshot.GetDirectory().SetCurrentBinary(startOutDir);
+        snapshot.GetDirectory().SetCurrentSource(startDir);
+        snapshot.GetDirectory().SetRelativePathTopSource(homeDir.c_str());
+        snapshot.GetDirectory().SetRelativePathTopBinary(homeOutDir.c_str());
+        cmMakefile mf(cm.GetGlobalGenerator(), snapshot);
+        auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf);
+
+        return cmTransformDepfile(format, *lgd, args[8], args[9]) ? 0 : 2;
+      }
+      return 1;
+    }
   }
 
-  ::CMakeCommandUsage(args[0].c_str());
+  CMakeCommandUsage(args[0].c_str());
   return 1;
 }
 
@@ -1737,7 +1860,6 @@ int cmcmd::WindowsCEEnvironment(const char* version, const std::string& name)
 int cmcmd::RunPreprocessor(const std::vector<std::string>& command,
                            const std::string& intermediate_file)
 {
-
   cmUVProcessChainBuilder builder;
 
   uv_fs_t fs_req;
@@ -1762,14 +1884,13 @@ int cmcmd::RunPreprocessor(const std::vector<std::string>& command,
   }
   auto status = process.GetStatus();
   if (!status[0] || status[0]->ExitStatus != 0) {
-    auto errorStream = process.ErrorStream();
+    auto* errorStream = process.ErrorStream();
     if (errorStream) {
       std::cerr << errorStream->rdbuf();
     }
 
     return 1;
   }
-
   return 0;
 }
 
@@ -1787,19 +1908,56 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args)
     std::cerr << "Invalid cmake_llvm_rc arguments";
     return 1;
   }
+
   const std::string& intermediate_file = args[3];
   const std::string& source_file = args[2];
   std::vector<std::string> preprocess;
   std::vector<std::string> resource_compile;
   std::vector<std::string>* pArgTgt = &preprocess;
+
+  static const cmsys::RegularExpression llvm_rc_only_single_arg("^[-/](N|Y)");
+  static const cmsys::RegularExpression llvm_rc_only_double_arg(
+    "^[-/](C|LN|L)(.)?");
+  static const cmsys::RegularExpression common_double_arg(
+    "^[-/](D|U|I|FO|fo|Fo)(.)?");
+  bool acceptNextArg = false;
+  bool skipNextArg = false;
   for (std::string const& arg : cmMakeRange(args).advance(4)) {
-    // We use ++ as seperator between the preprocessing step definition and the
-    // rc compilation step becase we need to prepend a -- to seperate the
+    if (skipNextArg) {
+      skipNextArg = false;
+      continue;
+    }
+    // We use ++ as seperator between the preprocessing step definition and
+    // the rc compilation step becase we need to prepend a -- to seperate the
     // source file properly from other options when using clang-cl for
     // preprocessing.
     if (arg == "++") {
       pArgTgt = &resource_compile;
+      skipNextArg = false;
+      acceptNextArg = true;
     } else {
+      cmsys::RegularExpressionMatch match;
+      if (!acceptNextArg) {
+        if (common_double_arg.find(arg.c_str(), match)) {
+          acceptNextArg = match.match(2).empty();
+        } else {
+          if (llvm_rc_only_single_arg.find(arg.c_str(), match)) {
+            if (pArgTgt == &preprocess) {
+              continue;
+            }
+          } else if (llvm_rc_only_double_arg.find(arg.c_str(), match)) {
+            if (pArgTgt == &preprocess) {
+              skipNextArg = match.match(2).empty();
+              continue;
+            }
+            acceptNextArg = match.match(2).empty();
+          } else if (pArgTgt == &resource_compile) {
+            continue;
+          }
+        }
+      } else {
+        acceptNextArg = false;
+      }
       if (arg.find("SOURCE_DIR") != std::string::npos) {
         std::string sourceDirArg = arg;
         cmSystemTools::ReplaceString(
@@ -1819,10 +1977,15 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args)
     std::cerr << "Empty resource compilation command";
     return 1;
   }
+  // Since we might have skipped the last argument to llvm-rc
+  // we need to make sure the llvm-rc source file is present in the
+  // commandline
+  if (resource_compile.back() != intermediate_file) {
+    resource_compile.push_back(intermediate_file);
+  }
 
   auto result = RunPreprocessor(preprocess, intermediate_file);
   if (result != 0) {
-
     cmSystemTools::RemoveFile(intermediate_file);
     return result;
   }
@@ -1849,7 +2012,7 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args)
   }
   auto status = process.GetStatus();
   if (!status[0] || status[0]->ExitStatus != 0) {
-    auto errorStream = process.ErrorStream();
+    auto* errorStream = process.ErrorStream();
     if (errorStream) {
       std::cerr << errorStream->rdbuf();
     }
@@ -1986,7 +2149,7 @@ static bool RunCommand(const char* comment,
               << NumberFormatter(exitFormat, retCode)
               << ") with the following output:\n"
               << output;
-  } else {
+  } else if (verbose) {
     // always print the output of the command, unless
     // it is the dumb rc command banner
     if (output.find("Resource Compiler Version") == std::string::npos) {
@@ -2084,7 +2247,7 @@ int cmVSLink::Link()
     if (this->Verbose) {
       std::cout << "Visual Studio Incremental Link with embedded manifests\n";
     }
-    return LinkIncremental();
+    return this->LinkIncremental();
   }
   if (this->Verbose) {
     if (!this->Incremental) {
@@ -2093,7 +2256,7 @@ int cmVSLink::Link()
       std::cout << "Visual Studio Incremental Link without manifests\n";
     }
   }
-  return LinkNonIncremental();
+  return this->LinkNonIncremental();
 }
 
 static bool mtRetIsUpdate(int mtRet)
@@ -2109,8 +2272,8 @@ int cmVSLink::LinkIncremental()
   // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx
 
   //    1.  Compiler compiles the application and generates the *.obj files.
-  //    2.  An empty manifest file is generated if this is a clean build and if
-  //    not the previous one is reused.
+  //    2.  An empty manifest file is generated if this is a clean build and
+  //    if not the previous one is reused.
   //    3.  The resource compiler (rc.exe) compiles the *.manifest file to a
   //    *.res file.
   //    4.  Linker generates the binary (EXE or DLL) with the /incremental
index d0bc061..3c331d3 100644 (file)
@@ -26,6 +26,9 @@ static const char* cmDocumentationUsage[][2] = { { nullptr,
                                                  { nullptr, nullptr } };
 
 static const char* cmDocumentationOptions[][2] = {
+  { "--preset <preset>, --preset=<preset>",
+    "Read arguments from a test preset." },
+  { "--list-presets", "List available test presets." },
   { "-C <cfg>, --build-config <cfg>", "Choose configuration to test." },
   { "--progress", "Enable short progress output from tests." },
   { "-V,--verbose", "Enable verbose output from tests." },
@@ -111,6 +114,7 @@ static const char* cmDocumentationOptions[][2] = {
   { "--no-subproject-summary",
     "Disable timing summary information for "
     "subprojects." },
+  { "--test-dir <dir>", "Specify the directory in which to look for tests." },
   { "--build-and-test", "Configure, build and run a test." },
   { "--build-target", "Specify a specific target to build." },
   { "--build-nocmake", "Run the build without running cmake first." },
index b424488..55a7fb1 100644 (file)
@@ -167,6 +167,50 @@ protected:
 };
 
 template <typename CharType, typename Traits = std::char_traits<CharType> >
+class basic_fstream
+  : public std::basic_iostream<CharType, Traits>
+  , public basic_efilebuf<CharType, Traits>
+{
+public:
+  typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type
+    internal_buffer_type;
+  typedef std::basic_iostream<CharType, Traits> internal_stream_type;
+
+  basic_fstream()
+    : internal_stream_type(new internal_buffer_type())
+  {
+    this->buf_ =
+      static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
+  }
+  explicit basic_fstream(char const* file_name,
+                         std::ios_base::openmode mode = std::ios_base::in |
+                           std::ios_base::out)
+    : internal_stream_type(new internal_buffer_type())
+  {
+    this->buf_ =
+      static_cast<internal_buffer_type*>(internal_stream_type::rdbuf());
+    open(file_name, mode);
+  }
+
+  void open(char const* file_name,
+            std::ios_base::openmode mode = std::ios_base::in |
+              std::ios_base::out)
+  {
+    this->_set_state(this->_open(file_name, mode), this, this);
+  }
+
+  bool is_open() { return this->_is_open(); }
+
+  void close() { this->_set_state(this->_close(), this, this); }
+
+  using basic_efilebuf<CharType, Traits>::_is_open;
+
+  internal_buffer_type* rdbuf() const { return this->buf_; }
+
+  ~basic_fstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); }
+};
+
+template <typename CharType, typename Traits = std::char_traits<CharType> >
 class basic_ifstream
   : public std::basic_istream<CharType, Traits>
   , public basic_efilebuf<CharType, Traits>
@@ -251,11 +295,13 @@ public:
   ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); }
 };
 
+typedef basic_fstream<char> fstream;
 typedef basic_ifstream<char> ifstream;
 typedef basic_ofstream<char> ofstream;
 
 #  undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT
 #else
+using std::fstream;
 using std::ofstream;
 using std::ifstream;
 #endif
index 1267076..8f01684 100644 (file)
@@ -962,7 +962,10 @@ void kwsysProcess_Execute(kwsysProcess* cp)
       kwsysProcessCleanup(cp, GetLastError());
       return;
     }
-    SetCurrentDirectoryW(cp->WorkingDirectory);
+    if (!SetCurrentDirectoryW(cp->WorkingDirectory)) {
+      kwsysProcessCleanup(cp, GetLastError());
+      return;
+    }
   }
 
   /* Setup the stdin pipe for the first process.  */
index 9c34a56..7743eab 100644 (file)
@@ -447,6 +447,8 @@ public:
     Motorola,
     HP,
     Hygon,
+    Zhaoxin,
+    Apple,
     UnknownManufacturer
   };
 
@@ -1731,7 +1733,8 @@ const char* SystemInformationImplementation::GetVendorID()
     case NexGen:
       return "NexGen Inc., Advanced Micro Devices";
     case IDT:
-      return "IDT\\Centaur, Via Inc.";
+      return "IDT\\Centaur, Via Inc., Shanghai Zhaoxin Semiconductor Co., "
+             "Ltd.";
     case UMC:
       return "United Microelectronics Corp.";
     case Rise:
@@ -1748,6 +1751,10 @@ const char* SystemInformationImplementation::GetVendorID()
       return "Hewlett-Packard";
     case Hygon:
       return "Chengdu Haiguang IC Design Co., Ltd.";
+    case Zhaoxin:
+      return "Shanghai Zhaoxin Semiconductor Co., Ltd.";
+    case Apple:
+      return "Apple";
     case UnknownManufacturer:
     default:
       return "Unknown Manufacturer";
@@ -2109,7 +2116,10 @@ void SystemInformationImplementation::FindManufacturer(
   else if (this->ChipID.Vendor == "NexGenDriven")
     this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
   else if (this->ChipID.Vendor == "CentaurHauls")
-    this->ChipManufacturer = IDT; // IDT/Centaur (now VIA)
+    this->ChipManufacturer = IDT; // original IDT/Centaur/VIA (now Zhaoxin)
+  else if (this->ChipID.Vendor == "  Shanghai  ")
+    this->ChipManufacturer =
+      Zhaoxin; // Shanghai Zhaoxin Semiconductor Co., Ltd.
   else if (this->ChipID.Vendor == "RiseRiseRise")
     this->ChipManufacturer = Rise; // Rise
   else if (this->ChipID.Vendor == "GenuineTMx86")
@@ -2128,6 +2138,8 @@ void SystemInformationImplementation::FindManufacturer(
     this->ChipManufacturer = Motorola; // Motorola Microelectronics
   else if (family.compare(0, 7, "PA-RISC") == 0)
     this->ChipManufacturer = HP; // Hewlett-Packard
+  else if (this->ChipID.Vendor == "Apple")
+    this->ChipManufacturer = Apple; // Apple
   else
     this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
 }
@@ -3223,7 +3235,8 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
               this->ChipID.ProcessorName = "C3";
               break;
             default:
-              this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
+              this->ChipID.ProcessorName =
+                "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
               return false;
           }
           break;
@@ -3232,13 +3245,63 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
             case 6:
               this->ChipID.ProcessorName = "VIA Cyrix III - Samuel";
               break;
+            case 0xf:
+              this->ChipID.ProcessorName = "Zhaoxin zxc";
+              break;
             default:
-              this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
+              this->ChipID.ProcessorName =
+                "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
+              return false;
+          }
+          break;
+        case 7:
+          switch (this->ChipID.Model) {
+            case 0x1b:
+              this->ChipID.ProcessorName = "Zhaoxin kx5000";
+              break;
+            case 0x3b:
+              this->ChipID.ProcessorName = "Zhaoxin kx6000";
+              break;
+            default:
+              this->ChipID.ProcessorName =
+                "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
               return false;
           }
           break;
         default:
-          this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
+          this->ChipID.ProcessorName =
+            "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
+          return false;
+      }
+      break;
+
+    case Zhaoxin:
+      switch (this->ChipID.Family) {
+        case 6:
+          switch (this->ChipID.Model) {
+            case 0x19:
+              this->ChipID.ProcessorName = "Zhaoxin zxc";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown Zhaoxin family";
+              return false;
+          }
+          break;
+        case 7:
+          switch (this->ChipID.Model) {
+            case 0x1b:
+              this->ChipID.ProcessorName = "Zhaoxin kx5000";
+              break;
+            case 0x3b:
+              this->ChipID.ProcessorName = "Zhaoxin kx6000";
+              break;
+            default:
+              this->ChipID.ProcessorName = "Unknown Zhaoxin family";
+              return false;
+          }
+          break;
+        default:
+          this->ChipID.ProcessorName = "Unknown Zhaoxin family";
           return false;
       }
       break;
@@ -4445,33 +4508,62 @@ unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() const
   return this->NumberOfPhysicalCPU;
 }
 
-/** For Mac use sysctlbyname calls to find system info */
+#if defined(__APPLE__)
+static int kw_sysctlbyname_int32(const char* name, int32_t* value)
+{
+  size_t len = sizeof(int32_t);
+  int err = sysctlbyname(name, value, &len, nullptr, 0);
+  if (err == 0) {
+    assert(len == sizeof(int32_t));
+  }
+  return err;
+}
+
+static int kw_sysctlbyname_int64(const char* name, int64_t* value)
+{
+  size_t len = sizeof(int64_t);
+  int err = sysctlbyname(name, value, &len, nullptr, 0);
+  if (err == 0) {
+    assert(len == sizeof(int64_t));
+  }
+  return err;
+}
+#endif
+
+/** For Apple use sysctlbyname calls to find system info */
 bool SystemInformationImplementation::ParseSysCtl()
 {
 #if defined(__APPLE__)
-  char retBuf[128];
+  char tempBuff[128];
+  int32_t tempInt32 = 0;
+  int64_t tempInt64 = 0;
   int err = 0;
-  uint64_t value = 0;
-  size_t len = sizeof(value);
-  sysctlbyname("hw.memsize", &value, &len, nullptr, 0);
-  this->TotalPhysicalMemory = static_cast<size_t>(value / 1048576);
+  size_t len;
+
+  this->TotalPhysicalMemory = 0;
+  err = kw_sysctlbyname_int64("hw.memsize", &tempInt64);
+  if (err == 0) {
+    this->TotalPhysicalMemory = static_cast<size_t>(tempInt64 / 1024 / 1024);
+  }
 
-  // Parse values for Mac
   this->AvailablePhysicalMemory = 0;
   vm_statistics_data_t vmstat;
   mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
   if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat,
                       &count) == KERN_SUCCESS) {
-    len = sizeof(value);
-    err = sysctlbyname("hw.pagesize", &value, &len, nullptr, 0);
-    int64_t available_memory =
-      (vmstat.free_count + vmstat.inactive_count) * value;
-    this->AvailablePhysicalMemory =
-      static_cast<size_t>(available_memory / 1048576);
+    err = kw_sysctlbyname_int64("hw.pagesize", &tempInt64);
+    if (err == 0) {
+      int64_t available_memory =
+        (vmstat.free_count + vmstat.inactive_count) * tempInt64;
+      this->AvailablePhysicalMemory =
+        static_cast<size_t>(available_memory / 1024 / 1024);
+    }
   }
 
-#  ifdef VM_SWAPUSAGE
   // Virtual memory.
+  this->AvailableVirtualMemory = 0;
+  this->TotalVirtualMemory = 0;
+#  ifdef VM_SWAPUSAGE
   int mib[2] = { CTL_VM, VM_SWAPUSAGE };
   unsigned int miblen =
     static_cast<unsigned int>(sizeof(mib) / sizeof(mib[0]));
@@ -4480,78 +4572,98 @@ bool SystemInformationImplementation::ParseSysCtl()
   err = sysctl(mib, miblen, &swap, &len, nullptr, 0);
   if (err == 0) {
     this->AvailableVirtualMemory =
-      static_cast<size_t>(swap.xsu_avail / 1048576);
-    this->TotalVirtualMemory = static_cast<size_t>(swap.xsu_total / 1048576);
+      static_cast<size_t>(swap.xsu_avail / 1024 / 1024);
+    this->TotalVirtualMemory =
+      static_cast<size_t>(swap.xsu_total / 1024 / 1024);
   }
-#  else
-  this->AvailableVirtualMemory = 0;
-  this->TotalVirtualMemory = 0;
 #  endif
 
   // CPU Info
-  len = sizeof(this->NumberOfPhysicalCPU);
-  sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, nullptr, 0);
-  len = sizeof(this->NumberOfLogicalCPU);
-  sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, nullptr, 0);
-
-  int cores_per_package = 0;
-  len = sizeof(cores_per_package);
-  err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len,
-                     nullptr, 0);
-  // That name was not found, default to 1
-  this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
-    err != 0 ? 1 : static_cast<unsigned char>(cores_per_package);
+  this->NumberOfPhysicalCPU = 1;
+  err = kw_sysctlbyname_int32("hw.physicalcpu", &tempInt32);
+  if (err == 0) {
+    this->NumberOfPhysicalCPU = tempInt32;
+  }
+
+  this->NumberOfLogicalCPU = 1;
+  err = kw_sysctlbyname_int32("hw.logicalcpu", &tempInt32);
+  if (err == 0) {
+    this->NumberOfLogicalCPU = tempInt32;
+  }
+
+  this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = 1;
+  err = kw_sysctlbyname_int32("machdep.cpu.cores_per_package", &tempInt32);
+  if (err == 0) {
+    this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = tempInt32;
+  }
 
-  len = sizeof(value);
-  sysctlbyname("hw.cpufrequency", &value, &len, nullptr, 0);
-  this->CPUSpeedInMHz = static_cast<float>(value) / 1000000;
+  this->CPUSpeedInMHz = 0;
+  err = kw_sysctlbyname_int64("hw.cpufrequency", &tempInt64);
+  if (err == 0) {
+    this->CPUSpeedInMHz = static_cast<float>(tempInt64) / 1000000.0f;
+  }
 
   // Chip family
-  len = sizeof(this->ChipID.Family);
-  // Seems only the intel chips will have this name so if this fails it is
-  // probably a PPC machine
-  err =
-    sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, nullptr, 0);
+  // Seems only the Intel chips will have this name so if this fails it is
+  // a PowerPC or ARM, or something unknown
+  this->ChipID.Vendor = "";
+  this->ChipID.Family = 0;
+  this->ChipID.Model = 0;
+  this->ChipID.Revision = 0;
+  err = kw_sysctlbyname_int32("machdep.cpu.family", &tempInt32);
   if (err != 0) // Go back to names we know but are less descriptive
   {
-    this->ChipID.Family = 0;
-    ::memset(retBuf, 0, 128);
-    len = 32;
-    err = sysctlbyname("hw.machine", &retBuf, &len, nullptr, 0);
-    std::string machineBuf(retBuf);
-    if (machineBuf.find_first_of("Power") != std::string::npos) {
-      this->ChipID.Vendor = "IBM";
-      len = sizeof(this->ChipID.Family);
-      err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, nullptr, 0);
-      len = sizeof(this->ChipID.Model);
-      err =
-        sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, nullptr, 0);
-      this->FindManufacturer();
+    ::memset(tempBuff, 0, sizeof(tempBuff));
+    len = sizeof(tempBuff) - 1; // leave a byte for null termination
+    err = sysctlbyname("hw.machine", &tempBuff, &len, nullptr, 0);
+    if (err == 0) {
+      std::string machineBuf(tempBuff);
+      if (machineBuf.find_first_of("Power") != std::string::npos) {
+        this->ChipID.Vendor = "IBM";
+
+        err = kw_sysctlbyname_int32("hw.cputype", &tempInt32);
+        if (err == 0) {
+          this->ChipID.Family = tempInt32;
+        }
+
+        err = kw_sysctlbyname_int32("hw.cpusubtype", &tempInt32);
+        if (err == 0) {
+          this->ChipID.Model = tempInt32;
+        }
+
+        this->FindManufacturer();
+      } else if (machineBuf.find_first_of("arm64") != std::string::npos) {
+        this->ChipID.Vendor = "Apple";
+
+        this->FindManufacturer();
+      }
+    }
+  } else {
+    // Should be an Intel Chip.
+    err = kw_sysctlbyname_int32("machdep.cpu.family", &tempInt32);
+    if (err == 0) {
+      this->ChipID.Family = tempInt32;
     }
-  } else // Should be an Intel Chip.
-  {
-    len = sizeof(this->ChipID.Family);
-    err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len,
-                       nullptr, 0);
 
-    ::memset(retBuf, 0, 128);
-    len = 128;
-    err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, nullptr, 0);
     // Chip Vendor
-    this->ChipID.Vendor = retBuf;
+    ::memset(tempBuff, 0, sizeof(tempBuff));
+    len = sizeof(tempBuff) - 1; // leave a byte for null termination
+    err = sysctlbyname("machdep.cpu.vendor", tempBuff, &len, nullptr, 0);
+    if (err == 0) {
+      this->ChipID.Vendor = tempBuff;
+    }
     this->FindManufacturer();
 
     // Chip Model
-    len = sizeof(value);
-    err = sysctlbyname("machdep.cpu.model", &value, &len, nullptr, 0);
-    this->ChipID.Model = static_cast<int>(value);
+    err = kw_sysctlbyname_int32("machdep.cpu.model", &tempInt32);
+    if (err == 0) {
+      this->ChipID.Model = tempInt32;
+    }
 
     // Chip Stepping
-    len = sizeof(value);
-    value = 0;
-    err = sysctlbyname("machdep.cpu.stepping", &value, &len, nullptr, 0);
-    if (!err) {
-      this->ChipID.Revision = static_cast<int>(value);
+    err = kw_sysctlbyname_int32("machdep.cpu.stepping", &tempInt32);
+    if (err == 0) {
+      this->ChipID.Revision = tempInt32;
     }
 
     // feature string
@@ -4574,36 +4686,36 @@ bool SystemInformationImplementation::ParseSysCtl()
       len = allocSize - 2; // keep space for leading and trailing space
       err = sysctlbyname("machdep.cpu.features", buf + 1, &len, nullptr, 0);
     }
-    if (!err && buf && len) {
+    if (err == 0 && buf && len) {
       // now we can match every flags as space + flag + space
       buf[len + 1] = ' ';
       std::string cpuflags(buf, len + 2);
 
-      if ((cpuflags.find(" FPU ") != std::string::npos)) {
+      if (cpuflags.find(" FPU ") != std::string::npos) {
         this->Features.HasFPU = true;
       }
-      if ((cpuflags.find(" TSC ") != std::string::npos)) {
+      if (cpuflags.find(" TSC ") != std::string::npos) {
         this->Features.HasTSC = true;
       }
-      if ((cpuflags.find(" MMX ") != std::string::npos)) {
+      if (cpuflags.find(" MMX ") != std::string::npos) {
         this->Features.HasMMX = true;
       }
-      if ((cpuflags.find(" SSE ") != std::string::npos)) {
+      if (cpuflags.find(" SSE ") != std::string::npos) {
         this->Features.HasSSE = true;
       }
-      if ((cpuflags.find(" SSE2 ") != std::string::npos)) {
+      if (cpuflags.find(" SSE2 ") != std::string::npos) {
         this->Features.HasSSE2 = true;
       }
-      if ((cpuflags.find(" APIC ") != std::string::npos)) {
+      if (cpuflags.find(" APIC ") != std::string::npos) {
         this->Features.HasAPIC = true;
       }
-      if ((cpuflags.find(" CMOV ") != std::string::npos)) {
+      if (cpuflags.find(" CMOV ") != std::string::npos) {
         this->Features.HasCMOV = true;
       }
-      if ((cpuflags.find(" MTRR ") != std::string::npos)) {
+      if (cpuflags.find(" MTRR ") != std::string::npos) {
         this->Features.HasMTRR = true;
       }
-      if ((cpuflags.find(" ACPI ") != std::string::npos)) {
+      if (cpuflags.find(" ACPI ") != std::string::npos) {
         this->Features.HasACPI = true;
       }
     }
@@ -4611,21 +4723,29 @@ bool SystemInformationImplementation::ParseSysCtl()
   }
 
   // brand string
-  ::memset(retBuf, 0, sizeof(retBuf));
-  len = sizeof(retBuf);
-  err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, nullptr, 0);
-  if (!err) {
-    this->ChipID.ProcessorName = retBuf;
-    this->ChipID.ModelName = retBuf;
+  this->ChipID.ProcessorName = "";
+  this->ChipID.ModelName = "";
+  ::memset(tempBuff, 0, sizeof(tempBuff));
+  len = sizeof(tempBuff) - 1; // leave a byte for null termination
+  err = sysctlbyname("machdep.cpu.brand_string", tempBuff, &len, nullptr, 0);
+  if (err == 0) {
+    this->ChipID.ProcessorName = tempBuff;
+    this->ChipID.ModelName = tempBuff;
   }
 
-  // Cache size
-  len = sizeof(value);
-  err = sysctlbyname("hw.l1icachesize", &value, &len, nullptr, 0);
-  this->Features.L1CacheSize = static_cast<int>(value);
-  len = sizeof(value);
-  err = sysctlbyname("hw.l2cachesize", &value, &len, nullptr, 0);
-  this->Features.L2CacheSize = static_cast<int>(value);
+  // L1 Cache size
+  this->Features.L1CacheSize = 0;
+  err = kw_sysctlbyname_int64("hw.l1icachesize", &tempInt64);
+  if (err == 0) {
+    this->Features.L1CacheSize = static_cast<int>(tempInt64);
+  }
+
+  // L2 Cache size
+  this->Features.L2CacheSize = 0;
+  err = kw_sysctlbyname_int64("hw.l2cachesize", &tempInt64);
+  if (err == 0) {
+    this->Features.L2CacheSize = static_cast<int>(tempInt64);
+  }
 
   return true;
 #else
index afba953..3325e20 100644 (file)
@@ -99,12 +99,50 @@ static int testBOM()
   return 0;
 }
 
+static int testBOMIO()
+{
+  // test various encodings in binary mode
+  for (int i = 0; i < num_test_files; i++) {
+    kwsys::fstream f("bomio.txt",
+                     kwsys::fstream::in | kwsys::fstream::out |
+                       kwsys::fstream::binary | kwsys::fstream::trunc);
+    f.write(reinterpret_cast<const char*>(expected_bom_data[i] + 1),
+            *expected_bom_data[i]);
+    f.write(reinterpret_cast<const char*>(file_data[i] + 1), file_data[i][0]);
+    if (!f.good()) {
+      std::cout << "Unable to write data " << i << std::endl;
+      return 1;
+    }
+    f.seekp(0);
+
+    kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(f);
+    if (bom != expected_bom[i]) {
+      std::cout << "Unexpected BOM " << i << std::endl;
+      return 1;
+    }
+    char data[max_test_file_size];
+    f.read(data, file_data[i][0]);
+    if (!f.good()) {
+      std::cout << "Unable to read data " << i << std::endl;
+      return 1;
+    }
+
+    if (memcmp(data, file_data[i] + 1, file_data[i][0]) != 0) {
+      std::cout << "Incorrect read data " << i << std::endl;
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
 int testFStream(int, char* [])
 {
   int ret = 0;
 
   ret |= testNoFile();
   ret |= testBOM();
+  ret |= testBOMIO();
 
   return ret;
 }
index 5989aea..4dcea9d 100644 (file)
     "flags": []
   },
   {
+    "name":  "DebugType",
+    "switch": "debug:portable",
+    "comment": "",
+    "value": "portable",
+    "flags": []
+  },
+  {
     "name":  "Optimize",
     "switch": "optimize",
     "comment": "",
     "flags": []
   },
   {
+    "name":  "WarningsAsErrors",
+    "switch": "warnaserror:",
+    "comment": "",
+    "value": "",
+    "flags": [
+      "UserValue",
+      "UserRequired",
+      "CommaAppendable"
+    ]
+  },
+  {
     "name":  "WarningLevel",
     "switch": "warn:0",
     "comment": "",
index 66ee76f..110dcc2 100644 (file)
   },
   {
     "name": "TargetMachine",
+    "switch": "MACHINE:ARM64EC",
+    "comment": "MachineARM64EC",
+    "value": "MachineARM64EC",
+    "flags": []
+  },
+  {
+    "name": "TargetMachine",
     "switch": "MACHINE:EBC",
     "comment": "MachineEBC",
     "value": "MachineEBC",
index 5990ed1..a0e85b2 100644 (file)
   },
   {
     "name": "TargetMachine",
+    "switch": "MACHINE:ARM64X",
+    "comment": "MachineARM64X",
+    "value": "MachineARM64X",
+    "flags": []
+  },
+  {
+    "name": "TargetMachine",
     "switch": "MACHINE:EBC",
     "comment": "MachineEBC",
     "value": "MachineEBC",
index 053f1ee..3e47d6a 100644 (file)
@@ -34,7 +34,7 @@ typedef struct /* NOLINT */
 } functionMapEntry;
 
 static functionMapEntry cmakeGeneratedFunctionMapEntries[] = {
-  @CMAKE_FUNCTION_TABLE_ENTIRES@
+  @CMAKE_FUNCTION_TABLE_ENTRIES@
   { CM_NULL, CM_NULL } /* NOLINT */
 };
 
index ea5fc0b..96def00 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(Architecture C)
 
 function(test_for_xcode4 result_var)
index 1735400..da3bb4c 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(ArgumentExpansion)
 
index a574c4e..0a2c819 100644 (file)
@@ -9,7 +9,7 @@ set(SRCS)
 # and also generate assembler files from C:
 if("${CMAKE_GENERATOR}" MATCHES "Makefile|Xcode|Ninja" AND
     NOT CMAKE_OSX_ARCHITECTURES MATCHES ";")
-  if((CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang|HP|SunPro|XL)$") OR (CMAKE_C_COMPILER_ID STREQUAL "Intel"  AND  UNIX)
+  if((CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang|HP|SunPro|XL)$") OR (CMAKE_C_COMPILER_ID MATCHES "Intel"  AND  UNIX)
      AND NOT (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC"))
     set(C_FLAGS "${CMAKE_C_FLAGS}")
     separate_arguments(C_FLAGS)
index c438e1d..c2576f3 100644 (file)
@@ -102,6 +102,12 @@ target_link_libraries(zot zot_pch)
 if(NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
   target_precompile_headers(zot_pch PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/zot_pch.hxx)
 endif()
+if (CMAKE_CXX_DEPENDS_USE_COMPILER AND
+    CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.4")
+  # Mixing pre-compile headers and flags to generate dependencies (-M options family)
+  # causes the compiler to crash
+  set_property(TARGET zot_pch PROPERTY DISABLE_PRECOMPILE_HEADERS ON)
+endif()
 
 # Test the #include line macro transformation rule support.
 set_property(
index b7fd70d..d25ad27 100644 (file)
@@ -52,8 +52,8 @@ int foo(char* exec)
   (void)br;
 
   int res1 = findBundleFile(exec, "Resources/randomResourceFile.plist");
-  int res2 = findBundleFile(exec, "MacOS/SomeRandomFile.txt");
-  int res3 = findBundleFile(exec, "MacOS/README.rst");
+  int res2 = findBundleFile(exec, "Other/SomeRandomFile.txt");
+  int res3 = findBundleFile(exec, "Other/README.rst");
   if (!res1 || !res2 || !res3) {
     return 1;
   }
index 5f91f20..ceb5216 100644 (file)
@@ -16,7 +16,7 @@ set_source_files_properties(
   "${BundleTest_SOURCE_DIR}/SomeRandomFile.txt"
   "${BundleTest_SOURCE_DIR}/../../README.rst"
   PROPERTIES
-  MACOSX_PACKAGE_LOCATION MacOS
+  MACOSX_PACKAGE_LOCATION Other
   )
 
 add_executable(SecondBundle
@@ -35,11 +35,7 @@ install(TARGETS SecondBundle DESTINATION Applications)
 # installed into a location that uses this output name this will fail if the
 # bundle does not respect the name.  Also the executable will not be found by
 # the test driver if this does not work.
-set_target_properties(SecondBundle PROPERTIES
-  OUTPUT_NAME SecondBundleExe
-  XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
-  XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO"
-  )
+set_target_properties(SecondBundle PROPERTIES OUTPUT_NAME SecondBundleExe)
 
 # Express one app bundle in terms of another's SOURCES to verify that
 # the generators do not expose the Info.plist of one to the other.
index 1bedc70..c63461a 100644 (file)
@@ -3,6 +3,15 @@ project(BundleTest)
 set(MACOSX_BUNDLE_INFO_STRING "bundle_info_string")
 set(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
 
+if(CMAKE_GENERATOR STREQUAL "Xcode" AND
+   "${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Darwin;arm64")
+  # Tell Xcode to pretend the linker signed binaries so that
+  # editing with install_name_tool preserves ad-hoc signatures.
+  # See CMake Issue 21854.
+  # This option is supported by codesign on macOS 11 or higher.
+  set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed")
+endif()
+
 add_custom_command(
   OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
   COMMAND /bin/cp
@@ -19,7 +28,7 @@ set_source_files_properties(
   SomeRandomFile.txt
   "${BundleTest_SOURCE_DIR}/../../README.rst"
   PROPERTIES
-  MACOSX_PACKAGE_LOCATION MacOS
+  MACOSX_PACKAGE_LOCATION Other
   )
 
 set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/foobar")
@@ -56,11 +65,7 @@ install(TARGETS BundleTest DESTINATION Applications)
 # installed into a location that uses this output name this will fail if the
 # bundle does not respect the name.  Also the executable will not be found by
 # the test driver if this does not work.
-set_target_properties(BundleTest PROPERTIES
-  OUTPUT_NAME BundleTestExe
-  XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
-  XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO"
-  )
+set_target_properties(BundleTest PROPERTIES OUTPUT_NAME BundleTestExe)
 
 # Test executable versioning if it is supported.
 if(NOT XCODE)
index 69ef535..4a95e2f 100644 (file)
@@ -1,6 +1,15 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(BundleUtilities)
 
+if(CMAKE_GENERATOR STREQUAL "Xcode" AND
+   "${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Darwin;arm64")
+  # Tell Xcode to pretend the linker signed binaries so that
+  # editing with install_name_tool preserves ad-hoc signatures.
+  # See CMake Issue 21854.
+  # This option is supported by codesign on macOS 11 or higher.
+  set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed")
+endif()
+
 ###### the various types of dependencies we can have
 
 # a shared library
index b2b1b73..5f2e8ec 100644 (file)
@@ -1,6 +1,6 @@
 #this is adapted from FireBreath (http://www.firebreath.org)
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(CFBundleTest)
 
index 995b32c..b28d0be 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(add_compile_options)
 
index a5bc1e1..72b3502 100644 (file)
@@ -1,5 +1,5 @@
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(target_compile_definitions)
 
index a7055b1..268c7eb 100644 (file)
@@ -1,5 +1,5 @@
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(target_compile_options)
 
index 8713d99..0702ab5 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(target_include_directories)
 
index 5c704ac..aa8e21a 100644 (file)
@@ -1,3 +1,6 @@
+# Using 2.8 will trigger a deprecation warning.  In this case it's explicitly
+# intentional since the tests checks various policy implementations prior to
+# 2.8.12
 cmake_minimum_required(VERSION 2.8)
 
 project(target_link_libraries)
index 2c77acc..0ebe00e 100644 (file)
@@ -36,8 +36,8 @@ public:
 
   void Parse()
   {
-    NextNonWhitespace();
-    ParseTranslationUnits();
+    this->NextNonWhitespace();
+    this->ParseTranslationUnits();
   }
 
   const TranslationUnitsType& GetTranslationUnits()
@@ -49,51 +49,51 @@ private:
   void ParseTranslationUnits()
   {
     this->TranslationUnits = TranslationUnitsType();
-    ExpectOrDie('[', "at start of compile command file\n");
+    this->ExpectOrDie('[', "at start of compile command file\n");
     do {
-      ParseTranslationUnit();
+      this->ParseTranslationUnit();
       this->TranslationUnits.push_back(this->Command);
-    } while (Expect(','));
-    ExpectOrDie(']', "at end of array");
+    } while (this->Expect(','));
+    this->ExpectOrDie(']', "at end of array");
   }
 
   void ParseTranslationUnit()
   {
     this->Command = CommandType();
-    if (!Expect('{')) {
+    if (!this->Expect('{')) {
       return;
     }
-    if (Expect('}')) {
+    if (this->Expect('}')) {
       return;
     }
     do {
-      ParseString();
+      this->ParseString();
       std::string name = this->String;
-      ExpectOrDie(':', "between name and value");
-      ParseString();
+      this->ExpectOrDie(':', "between name and value");
+      this->ParseString();
       std::string value = this->String;
       this->Command[name] = value;
-    } while (Expect(','));
-    ExpectOrDie('}', "at end of object");
+    } while (this->Expect(','));
+    this->ExpectOrDie('}', "at end of object");
   }
 
   void ParseString()
   {
     this->String = "";
-    if (!Expect('"')) {
+    if (!this->Expect('"')) {
       return;
     }
-    while (!Expect('"')) {
-      Expect('\\');
-      this->String.append(1, C);
-      Next();
+    while (!this->Expect('"')) {
+      this->Expect('\\');
+      this->String.append(1, this->C);
+      this->Next();
     }
   }
 
   bool Expect(char c)
   {
     if (this->C == c) {
-      NextNonWhitespace();
+      this->NextNonWhitespace();
       return true;
     }
     return false;
@@ -101,23 +101,23 @@ private:
 
   void ExpectOrDie(char c, const std::string& message)
   {
-    if (!Expect(c)) {
-      ErrorExit(std::string("'") + c + "' expected " + message + ".");
+    if (!this->Expect(c)) {
+      this->ErrorExit(std::string("'") + c + "' expected " + message + ".");
     }
   }
 
   void NextNonWhitespace()
   {
     do {
-      Next();
-    } while (IsWhitespace());
+      this->Next();
+    } while (this->IsWhitespace());
   }
 
   void Next()
   {
-    this->C = char(Input.get());
+    this->C = char(this->Input.get());
     if (this->Input.bad()) {
-      ErrorExit("Unexpected end of file.");
+      this->ErrorExit("Unexpected end of file.");
     }
   }
 
@@ -127,7 +127,7 @@ private:
     exit(1);
   }
 
-  bool IsWhitespace()
+  bool IsWhitespace() const
   {
     return (this->C == ' ' || this->C == '\t' || this->C == '\n' ||
             this->C == '\r');
index 2aeaf7f..d8932ce 100644 (file)
@@ -26,9 +26,9 @@ public:
     : value(v)
   {
   }
-  ~Wrapper() { delete value; }
+  ~Wrapper() { delete this->value; }
 
-  T* get() const { return value; }
+  T* get() const { return this->value; }
 
 private:
   T* value;
index e79f047..d46e8f3 100644 (file)
@@ -5,6 +5,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/optional>
+
 #include "cmsys/FStream.hxx"
 
 #include "cmGccDepfileReader.h"
@@ -112,17 +114,26 @@ int testGccDepfileReader(int argc, char* argv[])
 
   std::string dataDirPath = argv[1];
   dataDirPath += "/testGccDepfileReader_data";
-  const int numberOfTestFiles = 3;
+  const int numberOfTestFiles = 7; // 6th file doesn't exist
   for (int i = 1; i <= numberOfTestFiles; ++i) {
     const std::string base = dataDirPath + "/deps" + std::to_string(i);
     const std::string depfile = base + ".d";
     const std::string plainDepfile = base + ".txt";
     std::cout << "Comparing " << base << " with " << plainDepfile << std::endl;
     const auto actual = cmReadGccDepfile(depfile.c_str());
-    const auto expected = readPlainDepfile(plainDepfile.c_str());
-    if (!compare(actual, expected)) {
-      dump("actual", actual);
-      dump("expected", expected);
+    if (cmSystemTools::FileExists(plainDepfile)) {
+      if (!actual) {
+        std::cerr << "Reading " << depfile << " should have succeeded\n";
+        return 1;
+      }
+      const auto expected = readPlainDepfile(plainDepfile.c_str());
+      if (!compare(*actual, expected)) {
+        dump("actual", *actual);
+        dump("expected", expected);
+        return 1;
+      }
+    } else if (actual) {
+      std::cerr << "Reading " << depfile << " should have failed\n";
       return 1;
     }
   }
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps4.d b/Tests/CMakeLib/testGccDepfileReader_data/deps4.d
new file mode 100644 (file)
index 0000000..9977a28
--- /dev/null
@@ -0,0 +1 @@
+invalid
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps5.d b/Tests/CMakeLib/testGccDepfileReader_data/deps5.d
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt
new file mode 100644 (file)
index 0000000..6c4a75b
--- /dev/null
@@ -0,0 +1,2 @@
+--RULES--
+--DEPENDENCIES--
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps7.d b/Tests/CMakeLib/testGccDepfileReader_data/deps7.d
new file mode 100644 (file)
index 0000000..92280cf
--- /dev/null
@@ -0,0 +1,6 @@
+out1 \
+  out2: \
+  in1 \
+  in2
+
+out3: in3
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt
new file mode 100644 (file)
index 0000000..86b6600
--- /dev/null
@@ -0,0 +1,10 @@
+--RULES--
+out1
+out2
+--DEPENDENCIES--
+in1
+in2
+--RULES--
+out3
+--DEPENDENCIES--
+in3
index de09c0f..2d7dd7c 100644 (file)
@@ -82,6 +82,18 @@ public:
   int Value = 0;
 };
 
+class NoMoveAssignEventLogger : public EventLogger
+{
+public:
+  using EventLogger::EventLogger;
+
+  NoMoveAssignEventLogger(const NoMoveAssignEventLogger&) = default;
+  NoMoveAssignEventLogger(NoMoveAssignEventLogger&&) = default;
+
+  NoMoveAssignEventLogger& operator=(const NoMoveAssignEventLogger&) = default;
+  NoMoveAssignEventLogger& operator=(NoMoveAssignEventLogger&&) = delete;
+};
+
 #define ASSERT_TRUE(x)                                                        \
   do {                                                                        \
     if (!(x)) {                                                               \
@@ -328,12 +340,28 @@ static bool testCopyAssign(std::vector<Event>& expected)
   o1 = o4; // Intentionally duplicated to test assigning an empty optional to
   // an empty optional
 
+  cm::optional<NoMoveAssignEventLogger> o5{ 1 };
+  auto const* v5 = &*o5;
+  const cm::optional<NoMoveAssignEventLogger> o6{ 2 };
+  auto const* v6 = &*o6;
+  o5 = std::move(o6);
+  const NoMoveAssignEventLogger e7{ 3 };
+  o5 = std::move(e7);
+
   expected = {
     { Event::VALUE_CONSTRUCT, v2, nullptr, 4 },
     { Event::COPY_CONSTRUCT, v1, v2, 4 },
     { Event::VALUE_CONSTRUCT, v3, nullptr, 5 },
     { Event::COPY_ASSIGN, v1, v3, 5 },
     { Event::DESTRUCT, v1, nullptr, 5 },
+    { Event::VALUE_CONSTRUCT, v5, nullptr, 1 },
+    { Event::VALUE_CONSTRUCT, v6, nullptr, 2 },
+    { Event::COPY_ASSIGN, v5, v6, 2 },
+    { Event::VALUE_CONSTRUCT, &e7, nullptr, 3 },
+    { Event::COPY_ASSIGN, v5, &e7, 3 },
+    { Event::DESTRUCT, &e7, nullptr, 3 },
+    { Event::DESTRUCT, v6, nullptr, 2 },
+    { Event::DESTRUCT, v5, nullptr, 3 },
     { Event::DESTRUCT, v3, nullptr, 5 },
     { Event::DESTRUCT, v2, nullptr, 4 },
   };
index 970adaa..4870f65 100644 (file)
@@ -20,6 +20,12 @@ Environment variable ``SOME_ENV_VAR``.
 Environment variable ``some env var`` with space and target.
 Generator ``Some Generator`` with space.
 Generator ``Some Generator`` with space.
+Generator expression ``SOME_GENEX``.
+Generator expression ``$<SOME_GENEX>`` with brackets.
+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 link Link Text.
 Inline link Link Text <With \-escaped Brackets>.
@@ -48,6 +54,22 @@ Bracket Comment Content
 
    Command other_cmd description.
 
+.. cmake:envvar:: some_var
+
+   Environment variable some_var description.
+
+.. envvar:: other_var
+
+   Environment variable other_var description.
+
+.. cmake:genex:: SOME_GENEX
+
+   Generator expression SOME_GENEX description.
+
+.. genex:: $<OTHER_GENEX>
+
+   Generator expression $<OTHER_GENEX> description.
+
 .. cmake:variable:: some_var
 
    Variable some_var description.
index 6462f1b..44931a7 100644 (file)
@@ -27,6 +27,12 @@ Environment variable :envvar:`SOME_ENV_VAR`.
 Environment variable :envvar:`some env var <SOME_ENV_VAR>` with space and target.
 Generator :generator:`Some Generator` with space.
 Generator :cpack_gen:`Some Generator` with space.
+Generator expression :genex:`SOME_GENEX`.
+Generator expression :genex:`$<SOME_GENEX>` with brackets.
+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 link `Link Text <ExternalDest>`_.
 Inline link `Link Text \<With \\-escaped Brackets\> <ExternalDest>`_.
@@ -51,6 +57,22 @@ Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_.
 
    Command other_cmd description.
 
+.. cmake:envvar:: some_var
+
+   Environment variable some_var description.
+
+.. envvar:: other_var
+
+   Environment variable other_var description.
+
+.. cmake:genex:: SOME_GENEX
+
+   Generator expression SOME_GENEX description.
+
+.. genex:: $<OTHER_GENEX>
+
+   Generator expression $<OTHER_GENEX> description.
+
 .. cmake:variable:: some_var
 
    Variable some_var description.
index 61a77cf..a003205 100644 (file)
@@ -181,6 +181,10 @@ bool checkOutput(std::istream& outputStream, std::istream& errorStream)
   }
 
   std::string error = getInput(errorStream);
+  auto qemu_error_pos = error.find("qemu:");
+  if (qemu_error_pos != std::string::npos) {
+    error.resize(qemu_error_pos);
+  }
   if (error.length() != 3 || error.find('1') == std::string::npos ||
       error.find('2') == std::string::npos ||
       error.find('3') == std::string::npos) {
index 1fb47cb..8e7c04f 100644 (file)
@@ -256,8 +256,6 @@ if(BUILD_TESTING)
 
   if(NOT CMake_TEST_EXTERNAL_CMAKE)
     add_subdirectory(CMakeLib)
-
-    add_subdirectory(CMakeServerLib)
   endif()
   add_subdirectory(CMakeOnly)
   add_subdirectory(RunCMake)
@@ -431,6 +429,10 @@ if(BUILD_TESTING)
         set(CMAKE_SKIP_VSGNUFortran TRUE)
       endif()
     endif()
+    if(CMAKE_Fortran_COMPILER_ID STREQUAL IntelLLVM)
+      message(STATUS "Skip VSGNUFortran for ifx until DLLEXPORT support is implemented")
+      set(CMAKE_SKIP_VSGNUFortran TRUE)
+    endif()
     if((CMAKE_C_COMPILER MATCHES lsb)
         AND (CMAKE_Fortran_COMPILER MATCHES ifort))
       message(STATUS "Skip VSGNUFortran for ifort and lsb compilers")
@@ -1155,6 +1157,26 @@ if(BUILD_TESTING)
                                      "components-depend1"
                                      "components-depend2"
                                      "compression")
+      # Run additional tests if dpkg-shlibdeps is available (and is new enough version)
+      find_program(SHLIBDEPS_EXECUTABLE NAMES dpkg-shlibdeps)
+      if(SHLIBDEPS_EXECUTABLE)
+        # Check version of the dpkg-shlibdeps tool
+        execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --version
+          OUTPUT_VARIABLE _TMP_VERSION
+          ERROR_QUIET
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+        if(_TMP_VERSION MATCHES "dpkg-shlibdeps version ([0-9]+\\.[0-9]+\\.[0-9]+)")
+          set(SHLIBDEPS_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
+        else()
+          unset(SHLIBDEPS_EXECUTABLE_VERSION)
+        endif()
+        if(NOT SHLIBDEPS_EXECUTABLE_VERSION VERSION_LESS 1.19 OR
+          (NOT SHLIBDEPS_EXECUTABLE_VERSION VERSION_LESS 1.17 AND NOT CMAKE_BINARY_DIR MATCHES ".*[ ].*"))
+            list(APPEND DEB_CONFIGURATIONS_TO_TEST "shlibdeps-with-private-lib-failure"
+                                                   "shlibdeps-with-private-lib-success")
+        endif()
+      endif()
+
       set(CPackGen "DEB")
       set(CPackRun_CPackGen "-DCPackGen=${CPackGen}")
 
@@ -1281,21 +1303,6 @@ if(BUILD_TESTING)
     set_property(TEST CMakeTestAllGenerators PROPERTY RUN_SERIAL 1)
   endif()
 
-  if(NOT DEFINED CTEST_RUN_CMakeTestMultipleConfigures)
-    set(CTEST_RUN_CMakeTestMultipleConfigures ON)
-  endif()
-
-  if(CTEST_RUN_CMakeTestMultipleConfigures)
-    add_test(CMakeTestMultipleConfigures ${CMAKE_CMAKE_COMMAND}
-        -D dir=${CMake_BINARY_DIR}/Tests/CMakeTestMultipleConfigures
-        -D gen=${CMAKE_GENERATOR}
-        -D CMake_SOURCE_DIR=${CMake_SOURCE_DIR}
-        -P ${CMake_SOURCE_DIR}/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
-      )
-    list(APPEND TEST_BUILD_DIRS
-      "${CMake_BINARY_DIR}/Tests/CMakeTestMultipleConfigures")
-  endif()
-
   if(NOT CMake_TEST_EXTERNAL_CMAKE)
     add_test(LoadedCommandOneConfig  ${CMAKE_CTEST_COMMAND}
       --build-and-test
@@ -1427,6 +1434,7 @@ if(BUILD_TESTING)
             GTK2
             Iconv
             ICU
+            Intl
             JPEG
             JsonCpp
             LAPACK
@@ -1944,7 +1952,7 @@ if(BUILD_TESTING)
     if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" OR NOT "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
       ADD_TEST_MACRO(ForceInclude foo)
     endif()
-    if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
+    if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
       ADD_TEST_MACRO(PrecompiledHeader foo)
     endif()
     set(MSVCRuntimeLibrary_BUILD_OPTIONS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
@@ -2010,12 +2018,19 @@ if(BUILD_TESTING)
         endif()
       endif()
 
-      # For the Watcom WMake generator, avoid the MFC test by default.
       if(CTEST_RUN_MFC)
+        # For the Watcom WMake generator, avoid the MFC test by default.
         if("${CMAKE_GENERATOR}" MATCHES "WMake")
           message(STATUS
             "using the Watcom WMake generator, avoiding MFC test")
           set(CTEST_RUN_MFC OFF)
+        elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM")
+          # clang-cl cannot deal with implicit dependencies in UTF16 files
+          # (see #18311).  IntelLLVM inherits this behavior from Clang.
+          # TODO: maybe clang should also skip the MFC test
+          message(STATUS
+            "using generator other than Visual Studio with clang-cl, avoiding MFC test")
+          set(CTEST_RUN_MFC OFF)
         endif()
       endif()
 
@@ -2926,13 +2941,6 @@ if(BUILD_TESTING)
   ADD_TEST_MACRO(CMakeCommands.link_directories)
   ADD_TEST_MACRO(CMakeCommands.target_link_directories)
 
-  # The cmake server-mode test requires python for a simple client.
-  find_package(PythonInterp QUIET)
-  if(PYTHON_EXECUTABLE)
-    set(Server_BUILD_OPTIONS -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE})
-    ADD_TEST_MACRO(Server Server)
-  endif()
-
   configure_file(
     "${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in"
     "${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake"
@@ -2947,7 +2955,7 @@ if(BUILD_TESTING)
       PASS_REGULAR_EXPRESSION "Failed")
   else()
     set_tests_properties(CTestTestCrash PROPERTIES
-      PASS_REGULAR_EXPRESSION "(Illegal|SegFault|Subprocess aborted)")
+      PASS_REGULAR_EXPRESSION "(Illegal|SegFault|Subprocess aborted|SIGTRAP)")
   endif()
 
   configure_file(
@@ -3402,6 +3410,9 @@ if(BUILD_TESTING)
               ${build_generator_args}
               --build-project helloJavaNativeHeaders
               --build-run-dir "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders/"
+              --build-target install
+              --build-options
+              "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/JavaNativeHeaders/Install"
               --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIG>)
             list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/JavaNativeHeaders")
           endif()
index 1f9d3ac..7ca68ec 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(CheckCXXCompilerFlag)
 
 message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
index 859ec41..4cbccd3 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(CheckStructHasMember)
 
index 2511064..9f30c7d 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 if (NOT MAJOR_TEST_MODULE OR NOT MAJOR_TEST_VERSION)
   message(FATAL_ERROR "test selection variables not set up")
index fe3815e..b23d5e2 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(FindLibraryTest NONE)
 
 set(CMAKE_FIND_DEBUG_MODE 1)
index 0e64ed4..bf4e350 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(FindPathTest NONE)
 
 set(CMAKE_FIND_DEBUG_MODE 1)
diff --git a/Tests/CMakeServerLib/CMakeLists.txt b/Tests/CMakeServerLib/CMakeLists.txt
deleted file mode 100644 (file)
index 2c23c2d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-include_directories(
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMake_BINARY_DIR}/Source
-  ${CMake_SOURCE_DIR}/Source
-  )
-
-set(CMakeServerLib_TESTS
-  testServerBuffering.cpp
-  )
-
-create_test_sourcelist(CMakeLib_TEST_SRCS CMakeServerLibTests.cxx ${CMakeServerLib_TESTS})
-add_executable(CMakeServerLibTests ${CMakeLib_TEST_SRCS})
-target_link_libraries(CMakeServerLibTests CMakeLib CMakeServerLib)
-
-SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY C_CLANG_TIDY "")
-SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY CXX_CLANG_TIDY "")
-
-foreach(testfile ${CMakeServerLib_TESTS})
-  get_filename_component(test "${testfile}" NAME_WE)
-  add_test(CMakeServerLib.${test} CMakeServerLibTests ${test} ${${test}_ARGS})
-endforeach()
diff --git a/Tests/CMakeServerLib/testServerBuffering.cpp b/Tests/CMakeServerLib/testServerBuffering.cpp
deleted file mode 100644 (file)
index 6f22940..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <iostream>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "cmConnection.h"
-#include "cmServerConnection.h"
-
-void print_error(const std::vector<std::string>& input,
-                 const std::vector<std::string>& output)
-{
-  std::cerr << "Responses don't equal input messages input." << std::endl;
-  std::cerr << "Responses: " << std::endl;
-
-  for (auto& msg : output) {
-    std::cerr << "'" << msg << "'" << std::endl;
-  }
-
-  std::cerr << "Input messages" << std::endl;
-  for (auto& msg : input) {
-    std::cerr << "'" << msg << "'" << std::endl;
-  }
-}
-
-std::string trim_newline(const std::string& _buffer)
-{
-  auto buffer = _buffer;
-  while (!buffer.empty() && (buffer.back() == '\n' || buffer.back() == '\r')) {
-    buffer.pop_back();
-  }
-  return buffer;
-}
-
-int testServerBuffering(int, char** const)
-{
-  std::vector<std::string> messages = {
-    "{ \"test\": 10}", "{ \"test\": { \"test2\": false} }",
-    "{ \"test\": [1, 2, 3] }",
-    "{ \"a\": { \"1\": {}, \n\n\n \"2\":[] \t\t\t\t}}"
-  };
-
-  std::string fullMessage;
-  for (auto& msg : messages) {
-    fullMessage += "[== \"CMake Server\" ==[\n";
-    fullMessage += msg;
-    fullMessage += "\n]== \"CMake Server\" ==]\n";
-  }
-
-  // The buffering strategy should cope with any fragmentation, including
-  // just getting the characters one at a time.
-  auto bufferingStrategy =
-    std::unique_ptr<cmConnectionBufferStrategy>(new cmServerBufferStrategy);
-  std::vector<std::string> response;
-  std::string rawBuffer;
-  for (auto& messageChar : fullMessage) {
-    rawBuffer += messageChar;
-    std::string packet = bufferingStrategy->BufferMessage(rawBuffer);
-    do {
-      if (!packet.empty() && packet != "\r\n") {
-        response.push_back(trim_newline(packet));
-      }
-      packet = bufferingStrategy->BufferMessage(rawBuffer);
-    } while (!packet.empty());
-  }
-
-  if (response != messages) {
-    print_error(messages, response);
-    return 1;
-  }
-
-  // We should also be able to deal with getting a bunch at once
-  response.clear();
-  std::string packet = bufferingStrategy->BufferMessage(fullMessage);
-  do {
-    if (!packet.empty() && packet != "\r\n") {
-      response.push_back(trim_newline(packet));
-    }
-    packet = bufferingStrategy->BufferMessage(fullMessage);
-  } while (!packet.empty());
-
-  if (response != messages) {
-    print_error(messages, response);
-    return 1;
-  }
-
-  return 0;
-}
diff --git a/Tests/CMakeTestMultipleConfigures/RunCMake.cmake b/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
deleted file mode 100644 (file)
index a79bfcb..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-if(NOT DEFINED CMake_SOURCE_DIR)
-  message(FATAL_ERROR "CMake_SOURCE_DIR not defined")
-endif()
-
-if(NOT DEFINED dir)
-  message(FATAL_ERROR "dir not defined")
-endif()
-
-if(NOT DEFINED gen)
-  message(FATAL_ERROR "gen not defined")
-endif()
-
-# Call cmake once to get a baseline/reference output build tree: "Build".
-# Then call cmake N more times, each time making a copy of the entire
-# build tree after cmake is done configuring/generating. At the end,
-# analyze the diffs in the generated build trees. Expect no diffs.
-#
-message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
-
-set(N 7)
-
-# First setup source and binary trees:
-#
-execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
-  ${dir}/Source
-)
-
-execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
-  ${dir}/Build
-)
-
-execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory
-  ${CMake_SOURCE_DIR}/Tests/CTestTest/SmallAndFast
-  ${dir}/Source
-)
-
-execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory
-  ${dir}/Build
-)
-
-# Patch SmallAndFast to build a .cxx executable too:
-#
-execute_process(COMMAND ${CMAKE_COMMAND} -E copy
-  ${dir}/Source/echoargs.c
-  ${dir}/Source/echoargs.cxx
-)
-file(APPEND "${dir}/Source/CMakeLists.txt" "\nadd_executable(echoargsCXX echoargs.cxx)\n")
-
-# Loop N times, saving a copy of the configured/generated build tree each time:
-#
-foreach(i RANGE 1 ${N})
-  # Equivalent sequence of shell commands:
-  #
-  message(STATUS "${i}: cd Build && cmake -G \"${gen}\" ../Source && cd .. && cp -r Build b${i}")
-
-  # Run cmake:
-  #
-  execute_process(COMMAND ${CMAKE_COMMAND} -G ${gen} ../Source
-    RESULT_VARIABLE result
-    OUTPUT_VARIABLE stdout
-    ERROR_VARIABLE stderr
-    WORKING_DIRECTORY ${dir}/Build
-    )
-
-  message(STATUS "result='${result}'")
-  message(STATUS "stdout='${stdout}'")
-  message(STATUS "stderr='${stderr}'")
-  message(STATUS "")
-
-  # Save this iteration of the Build directory:
-  #
-  execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
-    ${dir}/b${i}
-    )
-  execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory
-    ${dir}/Build
-    ${dir}/b${i}
-    RESULT_VARIABLE result
-    OUTPUT_VARIABLE stdout
-    ERROR_VARIABLE stderr
-    )
-
-  message(STATUS "result='${result}'")
-  message(STATUS "stdout='${stdout}'")
-  message(STATUS "stderr='${stderr}'")
-  message(STATUS "")
-endforeach()
-
-
-# Function to analyze diffs between two directories.
-# Set DIFF_EXECUTABLE before calling if 'diff' is available.
-#
-function(analyze_directory_diffs d1 d2 diff_count_var)
-  set(diffs 0)
-
-  message(STATUS "Analyzing directory diffs between:")
-  message(STATUS "  d1='${d1}'")
-  message(STATUS "  d2='${d2}'")
-
-  if(NOT "${d1}" STREQUAL "" AND NOT "${d2}" STREQUAL "")
-    message(STATUS "info: analyzing directories")
-
-    file(GLOB_RECURSE files1 RELATIVE "${d1}" "${d1}/*")
-    file(GLOB_RECURSE files2 RELATIVE "${d2}" "${d2}/*")
-
-    if("${files1}" STREQUAL "${files2}")
-      message(STATUS "info: file lists the same")
-      #message(STATUS "  files='${files1}'")
-
-      foreach(f ${files1})
-        execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files
-          ${d1}/${f}
-          ${d2}/${f}
-          RESULT_VARIABLE result
-          OUTPUT_VARIABLE stdout
-          ERROR_VARIABLE stderr
-          )
-        if(result STREQUAL 0)
-          #message(STATUS "info: file '${f}' the same")
-        else()
-          math(EXPR diffs "${diffs} + 1")
-          message(STATUS "warning: file '${f}' differs from d1 to d2")
-          file(READ "${d1}/${f}" f1contents)
-          message(STATUS "contents of file '${d1}/${f}'
-[===[${f1contents}]===]")
-          file(READ "${d2}/${f}" f2contents)
-          message(STATUS "contents of file '${d2}/${f}'
-[===[${f2contents}]===]")
-          if(DIFF_EXECUTABLE)
-            message(STATUS "diff of files '${d1}/${f}' '${d2}/${f}'")
-            message(STATUS "[====[")
-            execute_process(COMMAND ${DIFF_EXECUTABLE} "${d1}/${f}" "${d2}/${f}")
-            message(STATUS "]====]")
-          endif()
-        endif()
-      endforeach()
-    else()
-      math(EXPR diffs "${diffs} + 1")
-      message(STATUS "warning: file *lists* differ - some files exist in d1/not-d2 or not-d1/d2...")
-      message(STATUS "  files1='${files1}'")
-      message(STATUS "  files2='${files2}'")
-    endif()
-  endif()
-
-  set(${diff_count_var} ${diffs} PARENT_SCOPE)
-endfunction()
-
-
-# Analyze diffs between b1:b2, b2:b3, b3:b4, b4:b5 ... bN-1:bN.
-# Expect no diffs.
-#
-find_program(DIFF_EXECUTABLE diff)
-set(total_diffs 0)
-
-foreach(i RANGE 2 ${N})
-  math(EXPR prev "${i} - 1")
-  set(count 0)
-  analyze_directory_diffs(${dir}/b${prev} ${dir}/b${i} count)
-  message(STATUS "diff count='${count}'")
-  message(STATUS "")
-  math(EXPR total_diffs "${total_diffs} + ${count}")
-endforeach()
-
-message(STATUS "CMAKE_COMMAND='${CMAKE_COMMAND}'")
-message(STATUS "total_diffs='${total_diffs}'")
index 348e6d0..6bbbe7d 100644 (file)
@@ -44,10 +44,6 @@ set_property(TEST CMake.FileDownloadBadHash PROPERTY
 
 AddCMakeTest(FileUpload "")
 
-if(HAVE_ELF_H)
-  AddCMakeTest(ELF "")
-endif()
-
 set(EndStuff_PreArgs
   "-Ddir:STRING=${CMAKE_CURRENT_BINARY_DIR}/EndStuffTest"
   )
index 9f40818..e0d826d 100644 (file)
@@ -1,68 +1,40 @@
 message(STATUS "testname='${testname}'")
 
-if(testname STREQUAL bad_else) # fail
-  file(WRITE "${dir}/${testname}.cmake"
-"else()
-")
+function(do_end content)
+  file(WRITE "${dir}/${testname}.cmake" "${content}")
   execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
     RESULT_VARIABLE rv)
   if(NOT rv EQUAL 0)
     message(FATAL_ERROR "${testname} failed")
   endif()
+endfunction()
+
+if(testname STREQUAL bad_else) # fail
+  do_end("else()\n")
 
 elseif(testname STREQUAL bad_elseif) # fail
-  file(WRITE "${dir}/${testname}.cmake"
-"elseif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+  do_end("elseif()\n")
 
 elseif(testname STREQUAL bad_endforeach) # fail
-  endforeach()
+  do_end("endforeach()\n")
 
 elseif(testname STREQUAL bad_endfunction) # fail
-  endfunction()
+  do_end("endfunction()\n")
 
 elseif(testname STREQUAL bad_endif) # fail
-  file(WRITE "${dir}/${testname}.cmake"
-"cmake_minimum_required(VERSION 2.8)
-endif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+  do_end("cmake_minimum_required(VERSION 2.8.12)\nendif()\n")
 
-elseif(testname STREQUAL endif_low_min_version) # pass
-  file(WRITE "${dir}/${testname}.cmake"
-"cmake_minimum_required(VERSION 1.2)
-endif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+elseif(testname STREQUAL endif_low_min_version) # fail
+  do_end("cmake_minimum_required(VERSION 1.2)\nendif()\n")
 
-elseif(testname STREQUAL endif_no_min_version) # pass
-  file(WRITE "${dir}/${testname}.cmake"
-"endif()
-")
-  execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake"
-    RESULT_VARIABLE rv)
-  if(NOT rv EQUAL 0)
-    message(FATAL_ERROR "${testname} failed")
-  endif()
+elseif(testname STREQUAL endif_no_min_version) # fail
+  do_end("endif()\n")
 
 elseif(testname STREQUAL bad_endmacro) # fail
-  endmacro()
+  do_end("endmacro()\n")
 
 elseif(testname STREQUAL bad_endwhile) # fail
-  endwhile()
+  do_end("endwhile()\n")
 
 else() # fail
   message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")
index 69d9a14..e0ce99a 100644 (file)
@@ -136,6 +136,9 @@ __reportIfWrongStatus("${status}" 0)
 # Print status because we check its message too
 message(STATUS "${status}")
 
+# do not use proxy for lookup of invalid site (DNS failure by proxy looks
+# different than DNS failure without proxy)
+set(ENV{no_proxy} "$ENV{no_proxy},badhostname.invalid")
 message(STATUS "FileDownload:11")
 file(DOWNLOAD
   badhostname.invalid
index 785f41d..76737e5 100644 (file)
@@ -142,9 +142,8 @@ set(Find-List-Only-STDERR "three")
 set(Insert-List-Only-STDERR "at least three")
 set(Length-List-Only-STDERR "two")
 set(Remove_At-List-Only-STDERR "at least two")
-set(Remove_Item-List-Only-STDERR "two or more")
 
-foreach(cmd IN ITEMS Find Get Insert Length Remove_At Remove_Item)
+foreach(cmd IN ITEMS Find Get Insert Length Remove_At)
   string(TOUPPER ${cmd} cmd_upper)
   set(${cmd}-List-Only-RESULT 1)
   set(${cmd}-List-Only-STDERR ".*CMake Error at List-${cmd}-List-Only.cmake:1 \\(list\\):.*list sub-command ${cmd_upper} requires ${${cmd}-List-Only-STDERR} arguments.*")
index 4363f1b..b2e2106 100644 (file)
@@ -22,6 +22,13 @@ target_link_libraries(mylibapp mylib)
 add_executable(mylibapp2 mylibapp.cpp)
 target_link_libraries(mylibapp2 mylib)
 
+if (CPackDEBConfiguration MATCHES "shlibdeps-with-private-lib")
+  add_subdirectory("shlibdeps-with-private-lib")
+  add_executable(mylibapp3 mylibapp.cpp)
+  target_compile_definitions(mylibapp3 PRIVATE -DSHLIBDEPS_PRIVATE)
+  target_link_libraries(mylibapp3 myprivatelib)
+endif()
+
 # Create installation targets. Note that we put each kind of file
 # into a different component via COMPONENT. These components will
 # be used to create the installation components.
@@ -39,6 +46,13 @@ install(FILES mylib.h
         DESTINATION include
         COMPONENT headers)
 
+if (CPackDEBConfiguration MATCHES "shlibdeps-with-private-lib")
+  install(TARGETS mylibapp3
+    RUNTIME
+    DESTINATION bin
+    COMPONENT applications)
+endif()
+
 # CPack boilerplate for this project
 set(CPACK_PACKAGE_NAME "MyLib")
 set(CPACK_PACKAGE_CONTACT "None")
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-failure.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-failure.cmake.in
new file mode 100644 (file)
index 0000000..cfe6df5
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+   set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# we set shlibdeps to on
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+# except for the component "headers" that do not contain any binary.
+# the packaging will just fail if this does not work
+set(CPACK_DEBIAN_HEADERS_PACKAGE_SHLIBDEPS OFF)
+
+# Also libraries contains only a static library.
+set(CPACK_DEBIAN_LIBRARIES_PACKAGE_SHLIBDEPS OFF)
diff --git a/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-success.cmake.in b/Tests/CPackComponentsDEB/MyLibCPackConfig-shlibdeps-with-private-lib-success.cmake.in
new file mode 100644 (file)
index 0000000..76aadc9
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# Activate component packaging
+#
+
+if(CPACK_GENERATOR MATCHES "DEB")
+   set(CPACK_DEB_COMPONENT_INSTALL "ON")
+endif()
+
+#
+# Choose grouping way
+#
+#set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE)
+#set(CPACK_COMPONENTS_GROUPING)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+#set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)
+
+# we set shlibdeps to on
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+# except for the component "headers" that do not contain any binary.
+# the packaging will just fail if this does not work
+set(CPACK_DEBIAN_HEADERS_PACKAGE_SHLIBDEPS OFF)
+
+# Also libraries contains only a static library.
+set(CPACK_DEBIAN_LIBRARIES_PACKAGE_SHLIBDEPS OFF)
+
+# Most importantly, we also give a list of additional search directories
+# to allow `dpkg-shlibdeps` to find the private dependency.
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS
+    "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib"
+    "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/Debug"
+    "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/Release"
+    "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/RelWithDebInfo"
+    "${CPACK_PACKAGE_DIRECTORY}/shlibdeps-with-private-lib/MinSizeRel")
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-failure.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-failure.cmake
new file mode 100644 (file)
index 0000000..962a1fb
--- /dev/null
@@ -0,0 +1,19 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+  message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+set(actual_output)
+run_cpack(actual_output
+          CPack_output
+          CPack_error
+          EXPECT_FAILURE
+          CONFIG_ARGS ${config_args}
+          CONFIG_VERBOSE ${config_verbose})
+
+string(REGEX MATCH "dpkg-shlibdeps: error: (cannot|couldn't) find[ \n\t]+library[ \n\t]+libmyprivatelib.so.1[ \n\t]+needed[ \n\t]+by[ \n\t]+./usr/bin/mylibapp3" expected_error ${CPack_error})
+if(NOT expected_error)
+  message(FATAL_ERROR "Did not get the expected error-message!")
+endif()
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-success.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-shlibdeps-with-private-lib-success.cmake
new file mode 100644 (file)
index 0000000..6eff3db
--- /dev/null
@@ -0,0 +1,75 @@
+if(NOT CPackComponentsDEB_SOURCE_DIR)
+  message(FATAL_ERROR "CPackComponentsDEB_SOURCE_DIR not set")
+endif()
+
+include(${CPackComponentsDEB_SOURCE_DIR}/RunCPackVerifyResult.cmake)
+
+
+
+# requirements
+
+# debian now produces lower case names
+set(expected_file_mask "${CPackComponentsDEB_BINARY_DIR}/mylib-*_1.0.3_*.deb")
+set(expected_count 3)
+
+
+set(actual_output)
+run_cpack(actual_output
+          CPack_output
+          CPack_error
+          EXPECTED_FILE_MASK "${expected_file_mask}"
+          CONFIG_ARGS ${config_args}
+          CONFIG_VERBOSE ${config_verbose})
+
+message(STATUS "expected_count='${expected_count}'")
+message(STATUS "expected_file_mask='${expected_file_mask}'")
+message(STATUS "actual_output_files='${actual_output}'")
+
+if(NOT actual_output)
+  message(FATAL_ERROR "error: expected_files do not exist: CPackComponentsDEB test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+endif()
+
+list(LENGTH actual_output actual_count)
+message(STATUS "actual_count='${actual_count}'")
+if(NOT actual_count EQUAL expected_count)
+  message(FATAL_ERROR "error: expected_count=${expected_count} does not match actual_count=${actual_count}: CPackComponents test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error})")
+endif()
+
+
+# dpkg-deb checks for the summary of the packages
+find_program(DPKGDEB_EXECUTABLE dpkg-deb)
+if(DPKGDEB_EXECUTABLE)
+  set(dpkgdeb_output_errors_all "")
+  foreach(_f IN LISTS actual_output)
+
+    # extracts the metadata from the package
+    run_dpkgdeb(dpkg_output
+                FILENAME ${_f}
+                )
+
+    dpkgdeb_return_specific_metaentry(dpkg_package_name
+                                      DPKGDEB_OUTPUT "${dpkg_output}"
+                                      METAENTRY "Package:")
+
+    message(STATUS "package='${dpkg_package_name}'")
+
+    if(dpkg_package_name STREQUAL "mylib-applications")
+      # pass
+    elseif(dpkg_package_name STREQUAL "mylib-headers")
+      # pass
+    elseif(dpkg_package_name STREQUAL "mylib-libraries")
+      # pass
+    else()
+      set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
+                                    "dpkg-deb: ${_f}: component name not found: ${dpkg_package_name}\n")
+    endif()
+
+  endforeach()
+
+
+  if(NOT dpkgdeb_output_errors_all STREQUAL "")
+    message(FATAL_ERROR "dpkg-deb checks failed:\n${dpkgdeb_output_errors_all}")
+  endif()
+else()
+  message("dpkg-deb executable not found - skipping dpkg-deb test")
+endif()
index 3bc8d2a..8f7c198 100644 (file)
@@ -29,7 +29,7 @@ endif()
 # run cpack with some options and returns the list of files generated
 # -output_expected_file: list of files that match the pattern
 function(run_cpack output_expected_file CPack_output_parent CPack_error_parent)
-  set(options )
+  set(options "EXPECT_FAILURE")
   set(oneValueArgs "EXPECTED_FILE_MASK" "CONFIG_VERBOSE")
   set(multiValueArgs "CONFIG_ARGS")
   cmake_parse_arguments(run_cpack_deb "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
@@ -45,17 +45,26 @@ function(run_cpack output_expected_file CPack_output_parent CPack_error_parent)
 
   message("config_args = ${run_cpack_deb_CONFIG_ARGS}")
   message("config_verbose = ${run_cpack_deb_CONFIG_VERBOSE}")
+
+  set(_backup_lang "$ENV{LANG}")
+  set(_backup_lc_all "$ENV{LC_ALL}")
+  set(ENV{LANG} "C")
+  set(ENV{LC_ALL} "C")
   execute_process(COMMAND ${CMAKE_CPACK_COMMAND} ${run_cpack_deb_CONFIG_VERBOSE} -G ${CPackGen} -C "${CONFIG}" ${run_cpack_deb_CONFIG_ARGS}
       RESULT_VARIABLE CPack_result
       OUTPUT_VARIABLE CPack_output
       ERROR_VARIABLE CPack_error
       WORKING_DIRECTORY ${CPackComponentsDEB_BINARY_DIR})
+  set(ENV{LANG} "${_backup_lang}")
+  set(ENV{LC_ALL} "${_backup_lc_all}")
 
   set(${CPack_output_parent} ${CPack_output} PARENT_SCOPE)
   set(${CPack_error_parent}  ${CPack_error} PARENT_SCOPE)
 
-  if (CPack_result)
+  if (CPack_result AND NOT run_cpack_deb_EXPECT_FAILURE)
     message(FATAL_ERROR "error: CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+  elseif (NOT CPack_result AND run_cpack_deb_EXPECT_FAILURE)
+    message(FATAL_ERROR "error: CPack execution succeeded although failure was expected!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
   else ()
     message(STATUS "CPack_output=${CPack_output}")
     message(STATUS "CPack_error=${CPack_error}")
index a438ac7..bb45831 100644 (file)
@@ -1,6 +1,19 @@
-#include "mylib.h"
+#ifndef SHLIBDEPS_PRIVATE
+
+#  include "mylib.h"
 
 int main()
 {
   mylib_function();
 }
+
+#else
+
+#  include "shlibdeps-with-private-lib/myprivatelib.h"
+
+int main()
+{
+  myprivatelib_function();
+}
+
+#endif
diff --git a/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/CMakeLists.txt b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c7ef386
--- /dev/null
@@ -0,0 +1,5 @@
+add_library(myprivatelib SHARED myprivatelib.cpp)
+set_target_properties( myprivatelib PROPERTIES
+    VERSION 1.2.3
+    SOVERSION 1
+)
diff --git a/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.cpp b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.cpp
new file mode 100644 (file)
index 0000000..67110e6
--- /dev/null
@@ -0,0 +1,8 @@
+#include "myprivatelib.h"
+
+#include "stdio.h"
+
+void myprivatelib_function()
+{
+  printf("This is myprivatelib");
+}
diff --git a/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.h b/Tests/CPackComponentsDEB/shlibdeps-with-private-lib/myprivatelib.h
new file mode 100644 (file)
index 0000000..7e4a42d
--- /dev/null
@@ -0,0 +1 @@
+void myprivatelib_function();
index 8ed4d59..64a8ef6 100644 (file)
@@ -17,5 +17,7 @@ set(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}\\\\uninstall.ico")
 set(CPACK_GENERATOR "NSIS")
 set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
 set(CPACK_NSIS_MANIFEST_DPI_AWARE ON)
+set(CPACK_NSIS_BRANDING_TEXT "CMake branding text")
+set(CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION "RIGHT")
 
 include(CPack)
index bfbcf9c..8bfcf26 100644 (file)
@@ -52,3 +52,11 @@ if("${output_index}" EQUAL "-1")
 else()
   message(STATUS "Found DPI-aware")
 endif()
+
+file(STRINGS "${project_file}" line REGEX "^BrandingText /TRIMRIGHT \"CMake branding text\"")
+string(FIND "${line}" "TRIMRIGHT" output_index)
+if("${output_index}" EQUAL "-1")
+  message(FATAL_ERROR "BrandingText not found in the project")
+else()
+  message(STATUS "Found BrandingText")
+endif()
index 5eeb7e9..95daabf 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(CPackTestAllGenerators)
 add_subdirectory(../CTestTest/SmallAndFast SmallAndFast)
 install(FILES RunCPack.cmake DESTINATION .)
index 940e849..2249d70 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(CPackWiXGenerator)
 
index 1818888..a36f374 100644 (file)
@@ -29,6 +29,20 @@ set(expected_out
   uncovered/uncovered2.cpp
 )
 
+# A symbolic link in the path can cause tar to put an equivalent, but not
+# minimal file name to some files in the tar file.  Convert paths to absolute
+# then back to relative to get them in canonical form (or maybe this is a bug
+# in how the tarball is generated?)
+function(to_relative_paths real_paths paths)
+  foreach(file ${paths})
+    file(REAL_PATH "${file}" real_path BASE_DIRECTORY "${CTEST_BINARY_DIRECTORY}")
+    file(RELATIVE_PATH relative_path "${CTEST_BINARY_DIRECTORY}" "${real_path}")
+    list(APPEND local_real_paths "${relative_path}")
+    message(DEBUG "${file} -> ${real_path} -> ${relative_path}")
+  endforeach()
+  set("${real_paths}" "${local_real_paths}" PARENT_SCOPE)
+endfunction()
+
 #------------------------------------------------------------------------------#
 # Test 1: with standard arguments
 #------------------------------------------------------------------------------#
@@ -50,6 +64,7 @@ execute_process(COMMAND
 )
 
 string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
 list(SORT out)
 
 if("${out}" STREQUAL "${expected_out}")
@@ -80,6 +95,7 @@ execute_process(COMMAND
 )
 
 string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
 list(SORT out)
 
 if("${out}" STREQUAL "${expected_out}")
@@ -110,6 +126,7 @@ execute_process(COMMAND
 )
 
 string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
 list(SORT out)
 
 if("${out}" STREQUAL "${expected_out}")
@@ -140,6 +157,7 @@ execute_process(COMMAND
 )
 
 string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
 list(SORT out)
 
 if("${out}" STREQUAL "${expected_out}")
@@ -170,6 +188,7 @@ execute_process(COMMAND
 )
 
 string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
 list(SORT out)
 
 if("${out}" STREQUAL "${expected_out}")
index 5208d2d..d04b3ad 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(CTestLimitDashJ NONE)
 
 # This file demonstrates https://gitlab.kitware.com/cmake/cmake/-/issues/12904
index 85cb30c..06cbafd 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(SmallAndFast)
 
 include(CTest)
index 5389bdf..8e0b611 100644 (file)
@@ -17,21 +17,11 @@ message("Using CVS tools:")
 set(CVS "@CVS_EXECUTABLE@")
 message(" cvs = ${CVS}")
 
-set(REPO ${TOP}/repo)
-
-# The MSYS cvs tool interprets "c:/" as a "machine:" name for SSH.
-# Detect the MSYS cvs and convert the repo path to an MSYS path.
-if(WIN32)
-  if(EXISTS "${CVS}")
-    file(STRINGS "${CVS}" cvs_is_msys LIMIT_COUNT 1 REGEX "[Mm][Ss][Yy][Ss]")
-    if(cvs_is_msys)
-      message("  '${CVS}' is from MSYS (contains '${cvs_is_msys}')")
-      string(REGEX REPLACE "^([A-Za-z]):" "/\\1" REPO "${REPO}")
-    endif()
-  endif()
-endif()
+# Pre-pending :local: prevents cvs from trying to interpret Windows drive
+# letters, like "C:", as host names.
+set(REPO ":local:${TOP}/repo")
 
-set(CVSCMD ${CVS} -d${REPO})
+set(CVSCMD ${CVS} -d "${REPO}")
 
 # CVSNT requires an extra option to 'cvs init'.
 set(CVS_INIT_OPT)
index 7d0fa0f..a3ef4eb 100644 (file)
@@ -32,6 +32,20 @@ if(UNIX)
   set(GIT ${TOP}/git.sh)
 endif()
 
+# Adapt to the system default branch name.
+execute_process(
+  COMMAND ${GIT} config --get init.defaultBranch
+  RESULT_VARIABLE defaultBranchFailed
+  OUTPUT_VARIABLE defaultBranch
+  ERROR_VARIABLE defaultBranchError
+  OUTPUT_STRIP_TRAILING_WHITESPACE
+  ERROR_STRIP_TRAILING_WHITESPACE
+  )
+if(defaultBranch STREQUAL "")
+  set(defaultBranch master)
+endif()
+message("Detected default branch name '${defaultBranch}'")
+
 #-----------------------------------------------------------------------------
 # Create the repository.
 message("Creating repository...")
@@ -64,7 +78,7 @@ run_child(WORKING_DIRECTORY ${TOP}/module
   COMMAND ${GIT} commit -m "Initial content"
   )
 run_child(WORKING_DIRECTORY ${TOP}/module
-  COMMAND ${GIT} push origin master:refs/heads/master
+  COMMAND ${GIT} push origin ${defaultBranch}:refs/heads/${defaultBranch}
   )
 
 #-----------------------------------------------------------------------------
@@ -80,7 +94,7 @@ file(APPEND ${TOP}/import/.git/config "
 ${AUTHOR_CONFIG}")
 create_content(import)
 file(WRITE ${TOP}/import/HEAD "HEAD\n")
-file(WRITE ${TOP}/import/master "master\n")
+file(WRITE ${TOP}/import/${defaultBranch} "${defaultBranch}\n")
 run_child(WORKING_DIRECTORY ${TOP}/import
   COMMAND ${GIT} add .
   )
@@ -94,7 +108,7 @@ run_child(WORKING_DIRECTORY ${TOP}/import
   COMMAND ${GIT} commit -m "Initial content"
   )
 run_child(WORKING_DIRECTORY ${TOP}/import
-  COMMAND ${GIT} push origin master:refs/heads/master
+  COMMAND ${GIT} push origin ${defaultBranch}:refs/heads/${defaultBranch}
   )
 
 #-----------------------------------------------------------------------------
@@ -107,7 +121,7 @@ run_child(WORKING_DIRECTORY ${TOP}/module
   COMMAND ${GIT} commit -m "Changed content"
   )
 run_child(WORKING_DIRECTORY ${TOP}/module
-  COMMAND ${GIT} push origin master:refs/heads/master
+  COMMAND ${GIT} push origin ${defaultBranch}:refs/heads/${defaultBranch}
   )
 
 #-----------------------------------------------------------------------------
@@ -163,7 +177,7 @@ run_child(
   COMMAND ${GIT} rm -- ${files_removed}
   )
 run_child(WORKING_DIRECTORY ${TOP}/user-source/module
-  COMMAND ${GIT} checkout master --
+  COMMAND ${GIT} checkout ${defaultBranch} --
   )
 run_child(
   WORKING_DIRECTORY ${TOP}/user-source
@@ -222,7 +236,7 @@ rewind_source(user-source)
 # modified files) even if ~/.gitconfig sets "branch.master.rebase".
 run_child(
   WORKING_DIRECTORY ${TOP}/user-source
-  COMMAND ${GIT} config branch.master.rebase false
+  COMMAND ${GIT} config branch.${defaultBranch}.rebase false
   )
 
 # Create a modified file.
@@ -254,7 +268,7 @@ create_build_tree(user-source user-binary-custom)
 file(APPEND ${TOP}/user-binary-custom/CTestConfiguration.ini
   "# GIT command configuration
 UpdateCommand: ${GIT}
-GITUpdateCustom: ${GIT};pull;origin;master
+GITUpdateCustom: ${GIT};pull;origin;${defaultBranch}
 ")
 
 # Run the dashboard command line interface.
@@ -304,7 +318,7 @@ create_dashboard_script(dash-binary-custom
   "# git command configuration
 set(CTEST_GIT_COMMAND \"${GIT}\")
 set(CTEST_GIT_UPDATE_OPTIONS)
-set(CTEST_GIT_UPDATE_CUSTOM \${CTEST_GIT_COMMAND} pull origin master)
+set(CTEST_GIT_UPDATE_CUSTOM \${CTEST_GIT_COMMAND} pull origin ${defaultBranch})
 ")
 
 # Run the dashboard script with CTest.
@@ -339,7 +353,7 @@ create_dashboard_script(dash-binary-quiet
   "# git command configuration
 set(CTEST_GIT_COMMAND \"${GIT}\")
 set(CTEST_GIT_UPDATE_OPTIONS)
-set(CTEST_GIT_UPDATE_CUSTOM \${CTEST_GIT_COMMAND} pull origin master)
+set(CTEST_GIT_UPDATE_CUSTOM \${CTEST_GIT_COMMAND} pull origin ${defaultBranch})
 ")
 unset(ctest_update_args)
 
index 87b7f1a..69fa4b6 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(CheckCompilerRelatedVariables)
 
 
index 1d8afbf..8347d5a 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(CompileDefinitions)
 
 # Use compile flags to tell executables which config is built
index ef9198d..cff98e3 100644 (file)
@@ -4,9 +4,12 @@ cmake_policy(SET CMP0057 NEW)
 
 project(CompileFeatures)
 
+set(ext_C c)
+set(ext_CXX cpp)
+
 macro(run_test feature lang)
   if (${feature} IN_LIST CMAKE_${lang}_COMPILE_FEATURES)
-    add_library(test_${feature} OBJECT ${feature})
+    add_library(test_${feature} OBJECT ${feature}.${ext_${lang}})
     set_property(TARGET test_${feature}
       PROPERTY COMPILE_FEATURES "${feature}"
     )
@@ -15,7 +18,7 @@ macro(run_test feature lang)
   endif()
 endmacro()
 
-if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
   get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
   list(FILTER c_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
   foreach(feature ${c_features})
@@ -23,7 +26,7 @@ if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
   endforeach()
 endif()
 
-if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
   get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
   list(FILTER cxx_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
   foreach(feature ${cxx_features})
@@ -268,6 +271,7 @@ if (CMAKE_CXX_COMPILE_FEATURES)
     if (std_flag_idx EQUAL -1)
       add_executable(default_dialect default_dialect.cpp)
       target_compile_definitions(default_dialect PRIVATE
+        DEFAULT_CXX23=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},23>
         DEFAULT_CXX20=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},20>
         DEFAULT_CXX17=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},17>
         DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14>
@@ -349,6 +353,7 @@ else()
       HAVE_CXX_STD_14=$<COMPILE_FEATURES:cxx_std_14>
       HAVE_CXX_STD_17=$<COMPILE_FEATURES:cxx_std_17>
       HAVE_CXX_STD_20=$<COMPILE_FEATURES:cxx_std_20>
+      HAVE_CXX_STD_23=$<COMPILE_FEATURES:cxx_std_23>
     )
   endif()
 
index e6b3ff6..bd504ff 100644 (file)
@@ -18,7 +18,11 @@ struct Outputter;
 #  define CXX_STD __cplusplus
 #endif
 
-#if DEFAULT_CXX20
+#if DEFAULT_CXX23
+#  if CXX_STD <= 202002L
+Outputter<CXX_STD> o;
+#  endif
+#elif DEFAULT_CXX20
 #  if CXX_STD <= 201703L
 Outputter<CXX_STD> o;
 #  endif
index 53dce62..9c3910e 100644 (file)
 #  if HAVE_CXX_STD_17 && !defined(ALLOW_LATER_STANDARDS)
 #    error HAVE_CXX_STD_17 is true with CXX_STANDARD == 11
 #  endif
+#  if HAVE_CXX_STD_20 && !defined(ALLOW_LATER_STANDARDS)
+#    error HAVE_CXX_STD_20 is true with CXX_STANDARD == 11
+#  endif
+#  if HAVE_CXX_STD_23 && !defined(ALLOW_LATER_STANDARDS)
+#    error HAVE_CXX_STD_23 is true with CXX_STANDARD == 11
+#  endif
 #endif
 
 #if !HAVE_OVERRIDE_CONTROL
index 1433462..cd6cacd 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(CompileOptions)
 
index 9eed1c0..a3d98f6 100644 (file)
@@ -5,6 +5,11 @@ if(NOT _isMultiConfig AND NOT CMAKE_BUILD_TYPE)
 endif()
 project(ConfigSources CXX)
 
+if("${CMAKE_CXX_COMPILER_ID};${CMAKE_CXX_SIMULATE_ID}" STREQUAL "Intel;MSVC")
+  string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Z7")
+  string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -Z7")
+endif()
+
 # Source file(s) named with the configuration(s).
 file(GENERATE
   OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp"
@@ -16,6 +21,72 @@ void config_$<CONFIG>() {}
 ]]
   )
 
+# Custom command outputs named with the configuration(s).
+add_custom_command(
+  OUTPUT "custom1_$<CONFIG>.cpp"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in" "custom1_$<CONFIG>.cpp"
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom1.cpp.in
+  VERBATIM
+  )
+# Output path starts in a generator expression.
+add_custom_command(
+  OUTPUT "$<1:custom2_$<CONFIG>.cpp>"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in" "custom2_$<CONFIG>.cpp"
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom2.cpp.in
+  VERBATIM
+  )
+# Source file generated as a custom command's byproduct.
+add_custom_command(
+  OUTPUT custom3.txt
+  BYPRODUCTS "$<1:custom3_$<CONFIG>.cpp>"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in" "custom3_$<CONFIG>.cpp"
+  COMMAND ${CMAKE_COMMAND} -E touch custom3.txt
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom3.cpp.in
+  VERBATIM
+  )
+# Source file generated as a custom target's byproduct.
+add_custom_target(custom4
+  BYPRODUCTS "custom4_$<CONFIG>.cpp"
+  COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/custom4.cpp.in" "custom4_$<CONFIG>.cpp"
+  VERBATIM
+  )
+# Source file generated by appended custom command.
+add_custom_command(
+  OUTPUT "custom5_$<CONFIG>.cpp"
+  COMMAND ${CMAKE_COMMAND} -E echo custom5_$<CONFIG>.cpp
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in
+  VERBATIM
+  )
+add_custom_command(APPEND
+  OUTPUT "custom5_$<CONFIG>.cpp"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/custom5.cpp.in" "custom5_$<CONFIG>.cpp.in"
+  VERBATIM
+  )
+# Appending through any configuration's output affects all configurations.
+if(CMAKE_CONFIGURATION_TYPES MATCHES ";([^;]+)$")
+  set(last_config "${CMAKE_MATCH_1}")
+else()
+  set(last_config ${CMAKE_BUILD_TYPE})
+endif()
+add_custom_command(APPEND
+  OUTPUT "custom5_${last_config}.cpp"
+  COMMAND ${CMAKE_COMMAND} -E copy "custom5_$<CONFIG>.cpp.in" "custom5_$<CONFIG>.cpp"
+  VERBATIM
+  )
+foreach(n RANGE 1 5)
+  set_property(SOURCE custom${n}_Debug.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_DEBUG)
+  foreach(other Release RelWithDebInfo MinSizeRel)
+    set_property(SOURCE custom${n}_${other}.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_OTHER)
+  endforeach()
+endforeach()
+add_library(Custom STATIC
+  custom1_$<CONFIG>.cpp
+  custom2_$<CONFIG>.cpp
+  custom3_$<CONFIG>.cpp custom3.txt
+  custom4_$<CONFIG>.cpp
+  custom5_$<CONFIG>.cpp
+  )
+
 # Per-config sources via INTERFACE_SOURCES.
 add_library(iface INTERFACE)
 target_sources(iface INTERFACE
@@ -34,7 +105,7 @@ add_executable(ConfigSources
   $<$<CONFIG:NotAConfig>:does_not_exist.cpp>
   ${CMAKE_CURRENT_BINARY_DIR}/config_$<CONFIG>.cpp
   )
-target_link_libraries(ConfigSources iface)
+target_link_libraries(ConfigSources Custom iface)
 
 # Per-config sources via LINK_LIBRARIES.
 add_library(iface_debug INTERFACE)
@@ -53,6 +124,7 @@ target_compile_definitions(ConfigSourcesLink PRIVATE
   "$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
   )
 target_link_libraries(ConfigSourcesLink PRIVATE
+  Custom
   "$<$<CONFIG:Debug>:iface_debug>"
   "$<$<NOT:$<CONFIG:Debug>>:iface_other>"
   "$<$<CONFIG:NotAConfig>:iface_does_not_exist>"
@@ -70,7 +142,7 @@ target_compile_definitions(ConfigSourcesLinkIface PRIVATE
   "$<$<CONFIG:Debug>:CFG_DEBUG>"
   "$<$<NOT:$<CONFIG:Debug>>:CFG_OTHER>"
   )
-target_link_libraries(ConfigSourcesLinkIface ConfigSourcesIface)
+target_link_libraries(ConfigSourcesLinkIface Custom ConfigSourcesIface)
 
 # A target with sources in only one configuration that is not the
 # first in CMAKE_CONFIGURATION_TYPES.
diff --git a/Tests/ConfigSources/custom1.cpp.in b/Tests/ConfigSources/custom1.cpp.in
new file mode 100644 (file)
index 0000000..e5f21c7
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom1_debug()
+{
+  return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom1_other()
+{
+  return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom2.cpp.in b/Tests/ConfigSources/custom2.cpp.in
new file mode 100644 (file)
index 0000000..438c1fd
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom2_debug()
+{
+  return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom2_other()
+{
+  return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom3.cpp.in b/Tests/ConfigSources/custom3.cpp.in
new file mode 100644 (file)
index 0000000..4545b69
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom3_debug()
+{
+  return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom3_other()
+{
+  return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom4.cpp.in b/Tests/ConfigSources/custom4.cpp.in
new file mode 100644 (file)
index 0000000..8a8b2a8
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom4_debug()
+{
+  return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom4_other()
+{
+  return 0;
+}
+#endif
diff --git a/Tests/ConfigSources/custom5.cpp.in b/Tests/ConfigSources/custom5.cpp.in
new file mode 100644 (file)
index 0000000..51f40ae
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef CUSTOM_CFG_DEBUG
+int custom5_debug()
+{
+  return 0;
+}
+#endif
+
+#ifdef CUSTOM_CFG_OTHER
+int custom5_other()
+{
+  return 0;
+}
+#endif
index 9b1e68a..ef776f8 100644 (file)
@@ -7,7 +7,14 @@
 
 #include "iface.h"
 
+extern int custom1_debug();
+extern int custom2_debug();
+extern int custom3_debug();
+extern int custom4_debug();
+extern int custom5_debug();
+
 int main(int argc, char** argv)
 {
-  return iface_src() + iface_debug();
+  return iface_src() + iface_debug() + custom1_debug() + custom2_debug() +
+    custom3_debug() + custom4_debug() + custom5_debug();
 }
index 3184a19..74f2156 100644 (file)
@@ -7,7 +7,14 @@
 
 #include "iface.h"
 
+extern int custom1_other();
+extern int custom2_other();
+extern int custom3_other();
+extern int custom4_other();
+extern int custom5_other();
+
 int main(int argc, char** argv)
 {
-  return iface_src() + iface_other();
+  return iface_src() + iface_other() + custom1_other() + custom2_other() +
+    custom3_other() + custom4_other() + custom5_other();
 }
index 4d7062b..6cc2d09 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(Trilinos)
 
 include(ExternalProject)
index 6ae2732..0d36323 100644 (file)
@@ -1,6 +1,6 @@
 # The VTK external project for CMake
 # ---------------------------------------------------------------------------
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(VTK)
 include(ExternalProject)
 
index 00125e3..8b42296 100644 (file)
@@ -5,6 +5,10 @@ project(Toolkit CXX)
 # Validate that we can use CUDAToolkit to find cuda include paths
 find_package(CUDAToolkit REQUIRED)
 
+if(NOT DEFINED CUDAToolkit_VERSION)
+  message(FATAL_ERROR "expected CUDAToolkit variable CUDAToolkit_VERSION not found")
+endif()
+
 message(STATUS "CUDAToolkit_VERSION: ${CUDAToolkit_VERSION}")
 message(STATUS "CUDAToolkit_VERSION_MAJOR: ${CUDAToolkit_VERSION_MAJOR}")
 message(STATUS "CUDAToolkit_VERSION_MINOR: ${CUDAToolkit_VERSION_MINOR}")
index 033f197..fdb7a6e 100644 (file)
@@ -11,6 +11,7 @@ add_cuda_test_macro(CudaOnly.ExportPTX CudaOnlyExportPTX)
 add_cuda_test_macro(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit)
 add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98)
 add_cuda_test_macro(CudaOnly.Toolkit CudaOnlyToolkit)
+add_cuda_test_macro(CudaOnly.ToolkitBeforeLang CudaOnlyToolkitBeforeLang)
 add_cuda_test_macro(CudaOnly.WithDefs CudaOnlyWithDefs)
 add_cuda_test_macro(CudaOnly.CircularLinkLine CudaOnlyCircularLinkLine)
 add_cuda_test_macro(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols)
index 5e8a8e4..38765ec 100644 (file)
@@ -8,6 +8,7 @@ if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
   target_compile_options(CudaOnlyCompileFlags PRIVATE
     -gencode arch=compute_50,code=compute_50
   )
+  set_property(TARGET CudaOnlyCompileFlags PROPERTY CUDA_ARCHITECTURES)
 else()
   set_property(TARGET CudaOnlyCompileFlags PROPERTY CUDA_ARCHITECTURES 50-real)
 endif()
index ee5f54d..e7e7bc4 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.8)
+cmake_minimum_required(VERSION 3.19)
 project (ExportPTX CUDA)
 
 #Goal for this example:
@@ -6,6 +6,10 @@ project (ExportPTX CUDA)
 # How to reference PTX files for custom commands
 # How to install PTX files
 
+# PTX can be compiled only for a single virtual architecture at a time
+list(SUBLIST CMAKE_CUDA_ARCHITECTURES 0 1 CMAKE_CUDA_ARCHITECTURES)
+string(APPEND CMAKE_CUDA_ARCHITECTURES "-virtual")
+
 add_library(CudaPTX OBJECT kernelA.cu kernelB.cu)
 set_property(TARGET CudaPTX PROPERTY CUDA_PTX_COMPILATION ON)
 
index bb06ba8..1486c1a 100644 (file)
@@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.15)
 project(CudaOnlyToolkit CUDA)
 find_package(CUDAToolkit REQUIRED)
 
+if(NOT DEFINED CUDAToolkit_VERSION)
+  message(FATAL_ERROR "expected CUDAToolkit variable CUDAToolkit_VERSION not found")
+endif()
+
 message(STATUS "CUDAToolkit_VERSION: ${CUDAToolkit_VERSION}")
 message(STATUS "CUDAToolkit_VERSION_MAJOR: ${CUDAToolkit_VERSION_MAJOR}")
 message(STATUS "CUDAToolkit_VERSION_MINOR: ${CUDAToolkit_VERSION_MINOR}")
diff --git a/Tests/CudaOnly/ToolkitBeforeLang/CMakeLists.txt b/Tests/CudaOnly/ToolkitBeforeLang/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8dff6cc
--- /dev/null
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 3.15)
+project(CudaOnlyToolkitBeforeLang CXX)
+
+# Validate that CUDAToolkit gets the correct version
+# when called before CUDA the language is enabled
+find_package(CUDAToolkit REQUIRED)
+enable_language(CUDA)
+
+if(NOT DEFINED CUDAToolkit_VERSION)
+  message(FATAL_ERROR "expected CUDAToolkit variable CUDAToolkit_VERSION not found")
+endif()
+
+set(cuda_libs cudart cuda_driver)
+
+# Verify that all the CUDA:: targets and variables exist
+foreach (cuda_lib IN LISTS cuda_libs)
+  if(NOT CUDA_${cuda_lib}_LIBRARY)
+    message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+  endif()
+  if(NOT TARGET CUDA::${cuda_lib})
+    message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+  endif()
+endforeach()
+
+add_executable(CudaOnlyToolkitBeforeLang main.cu)
+target_link_libraries(CudaOnlyToolkitBeforeLang PRIVATE CUDA::toolkit)
diff --git a/Tests/CudaOnly/ToolkitBeforeLang/main.cu b/Tests/CudaOnly/ToolkitBeforeLang/main.cu
new file mode 100644 (file)
index 0000000..0f3ccdc
--- /dev/null
@@ -0,0 +1,8 @@
+// Only thing we care about is that these headers are found
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+
+int main(int argc, char** argv)
+{
+  return 0;
+}
index c1a7a57..80545c4 100644 (file)
@@ -582,3 +582,7 @@ set_target_properties(mac_fw PROPERTIES
   )
 add_custom_command(OUTPUT mac_fw.txt COMMAND ${CMAKE_COMMAND} -E touch mac_fw.txt DEPENDS mac_fw)
 add_custom_target(drive_mac_fw ALL DEPENDS mac_fw.txt)
+
+# Test empty COMMANDs are ommited
+add_executable(empty_command empty_command.cxx)
+add_custom_command(TARGET empty_command POST_BUILD COMMAND $<0:date>)
similarity index 96%
rename from Tests/Server/empty.cpp
rename to Tests/CustomCommand/empty_command.cxx
index 766b775..f8b643a 100644 (file)
@@ -1,4 +1,3 @@
-
 int main()
 {
   return 0;
index 832d9dc..272eff7 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(EmptyDepends)
 
 include(CTest)
index 1088461..813cf06 100644 (file)
@@ -1,5 +1,5 @@
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 find_package(testLibRequired 2.5 REQUIRED)
 
index 29cdcc9..59e3bcc 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(ExternalProjectTest NONE)
 if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
   cmake_policy(SET CMP0114 NEW)
@@ -161,7 +161,7 @@ if(do_cvs_tests)
   #
   set(proj TutorialStep1-CVS-20090626)
   ExternalProject_Add(${proj}
-    CVS_REPOSITORY "${local_cvs_repo}"
+    CVS_REPOSITORY ":local:${local_cvs_repo}"
     CVS_MODULE "TutorialStep1"
     CVS_TAG "-D2009-06-26 16:50:00 UTC"
     UPDATE_COMMAND ""
@@ -176,7 +176,7 @@ if(do_cvs_tests)
   #
   set(proj TutorialStep1-CVS-testtag1)
   ExternalProject_Add(${proj}
-    CVS_REPOSITORY "${local_cvs_repo}"
+    CVS_REPOSITORY ":local:${local_cvs_repo}"
     CVS_MODULE "TutorialStep1"
     CVS_TAG -rtesttag1
     UPDATE_COMMAND ""
@@ -191,7 +191,7 @@ if(do_cvs_tests)
   #
   set(proj TutorialStep1-CVS-HEAD)
   ExternalProject_Add(${proj}
-    CVS_REPOSITORY "${local_cvs_repo}"
+    CVS_REPOSITORY ":local:${local_cvs_repo}"
     CVS_MODULE "TutorialStep1"
     CMAKE_GENERATOR "${CMAKE_GENERATOR}"
     CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
@@ -298,15 +298,9 @@ set(do_git_tests 0)
 if(GIT_EXECUTABLE)
   set(do_git_tests 1)
 
-  execute_process(
-    COMMAND "${GIT_EXECUTABLE}" --version
-    OUTPUT_VARIABLE ov
-    OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
-  string(REGEX REPLACE "^git version (.+)$" "\\1" git_version "${ov}")
-  message(STATUS "git_version='${git_version}'")
+  message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
 
-  if(git_version VERSION_LESS 1.6.5)
+  if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5)
     message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
     set(do_git_tests 0)
   endif()
@@ -335,7 +329,7 @@ if(do_git_tests)
   set(proj TutorialStep1-GIT-byhash)
   ExternalProject_Add(${proj}
     GIT_REPOSITORY "${local_git_repo}"
-    GIT_TAG d1970730310fe8bc07e73f15dc570071f9f9654a
+    GIT_TAG 57418671a0a0e371e7bac532337152595fbe0df5 # generated by gitrepo.bash
     UPDATE_COMMAND ""
     CMAKE_GENERATOR "${CMAKE_GENERATOR}"
     CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
@@ -670,23 +664,23 @@ endif()
 
 if(do_git_tests)
   add_test(TutorialStep1-GIT-byhash
-    "${binary_base}/TutorialStep1-GIT-byhash/Tutorial" 100)
+    ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-byhash/example.cmake")
 
   add_test(TutorialStep1-GIT-bytag
-    "${binary_base}/TutorialStep1-GIT-bytag/Tutorial" 99)
+    ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-bytag/example.cmake")
 
   add_test(TutorialStep1-GIT-bytag-withsubmodules
-    "${binary_base}/TutorialStep1-GIT-bytag-withsubmodules/Tutorial" 99)
+    ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-bytag-withsubmodules/example.cmake")
 
   add_test(TutorialStep1-GIT-shallow-master
-    "${binary_base}/TutorialStep1-GIT-shallow-master/Tutorial" 98)
+    ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-shallow-master/example.cmake")
 
   add_test(TutorialStep1-GIT-master
-    "${binary_base}/TutorialStep1-GIT-master/Tutorial" 98)
+    ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-master/example.cmake")
 
   if(NOT git_version VERSION_LESS 1.7.7)
     add_test(TutorialStep1-GIT-config
-      "${binary_base}/TutorialStep1-GIT-config/Tutorial" 98)
+      ${CMAKE_COMMAND} -P "${binary_base}/TutorialStep1-GIT-config/example.cmake")
   endif()
 endif()
 
index 4c12895..c3f2614 100644 (file)
@@ -1,5 +1,5 @@
 # This is the canonical simplest ExternalProject example CMakeLists.txt file:
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(ExternalProjectExample NONE)
 include(ExternalProject)
 
index b0f3f18..0e63651 100644 (file)
Binary files a/Tests/ExternalProject/gitrepo-sub-rec.tgz and b/Tests/ExternalProject/gitrepo-sub-rec.tgz differ
index c0b5360..ab34fff 100644 (file)
Binary files a/Tests/ExternalProject/gitrepo-sub.tgz and b/Tests/ExternalProject/gitrepo-sub.tgz differ
diff --git a/Tests/ExternalProject/gitrepo.bash b/Tests/ExternalProject/gitrepo.bash
new file mode 100755 (executable)
index 0000000..c341f28
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+
+readonly tmpdir="$(mktemp -d)"
+trap "rm -rf '$tmpdir'" EXIT
+
+readonly outdir="${BASH_SOURCE%/*}"
+readonly defaultBranch='master'
+
+export GIT_AUTHOR_NAME='testauthor'
+export GIT_AUTHOR_EMAIL='testauthor@cmake.org'
+export GIT_COMMITTER_NAME='testauthor'
+export GIT_COMMITTER_EMAIL='testauthor@cmake.org'
+
+(
+cd "$tmpdir"
+
+git --bare init -b "$defaultBranch" gitrepo.git
+rm -f gitrepo.git/hooks/*.sample
+
+mkdir gitrepo
+cd gitrepo
+git init -b "$defaultBranch"
+echo 'cmake_minimum_required(VERSION 3.19)
+project(Example NONE)
+add_custom_target(example ALL
+  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/example.cmake.in example.cmake
+)' >CMakeLists.txt
+echo 'message(STATUS example)' >example.cmake.in
+git add CMakeLists.txt example.cmake.in
+git commit -m "Initial import into repo."
+git push ../gitrepo.git "$defaultBranch"
+cd ../gitrepo.git
+git gc --prune
+cd ..
+ln -s gitrepo.git GIT
+
+git --bare init -b "$defaultBranch" gitrepo-sub.git
+rm -f gitrepo-sub.git/hooks/*.sample
+
+mkdir gitrepo-sub
+cd gitrepo-sub
+git init -b "$defaultBranch"
+echo 'cmake_minimum_required(VERSION 3.19)
+project(ExampleWithSub NONE)
+file(STRINGS "${CMAKE_SOURCE_DIR}/.git/config" git_config_strings
+     REGEX "^\\[submodule")
+foreach(submodule m1 m2)
+  option(WITH_${submodule} "Enable ${submodule}" OFF)
+  set(${submodule}_INITED FALSE)
+  set(${submodule}_UPDATED FALSE)
+  foreach(s ${git_config_strings})
+    if("${s}" MATCHES "${submodule}")
+      set(${submodule}_INITED TRUE)
+    endif()
+  endforeach()
+  if(EXISTS "${CMAKE_SOURCE_DIR}/m/${submodule}/CMakeLists.txt")
+    set(${submodule}_UPDATED TRUE)
+  endif()
+  if(WITH_${submodule})
+    if(NOT ${submodule}_INITED)
+      message(FATAL_ERROR "${submodule} not inited")
+    elseif(NOT ${submodule}_UPDATED)
+      message(FATAL_ERROR "${submodule} not updated")
+    endif()
+  else()
+    if(${submodule}_INITED)
+      message(FATAL_ERROR "${submodule} inited")
+    elseif(${submodule}_UPDATED)
+      message(FATAL_ERROR "${submodule} updated")
+    endif()
+  endif()
+endforeach()' >CMakeLists.txt
+git add CMakeLists.txt
+git submodule add -- ../GIT m/m1
+git submodule add -- ../GIT m/m2
+git submodule add -- ../GIT m/m3
+git commit -m "Initial import into repo."
+git push ../gitrepo-sub.git "$defaultBranch"
+cd ../gitrepo-sub.git
+git gc --prune
+cd ..
+ln -s gitrepo-sub.git GIT-with-submodules
+
+git --bare init -b "$defaultBranch" gitrepo-sub-rec.git
+rm -f gitrepo-sub-rec.git/hooks/*.sample
+
+mkdir gitrepo-sub-rec
+cd gitrepo-sub-rec
+git init -b "$defaultBranch"
+echo 'cmake_minimum_required(VERSION 3.19)
+project(ExampleWithRecSub NONE)
+set(top_submodule_dir "${CMAKE_SOURCE_DIR}/submodule")
+if(NOT EXISTS "${top_submodule_dir}/CMakeLists.txt")
+  message(FATAL_ERROR "Top submodule not updated")
+endif()
+option(WITH_RECURSIVE "Submodules are updated recursively" ON)
+foreach(submodule m1 m2 m3)
+  set(${submodule}_UPDATED FALSE)
+  if(EXISTS "${top_submodule_dir}/m/${submodule}/CMakeLists.txt")
+    set(${submodule}_UPDATED TRUE)
+  endif()
+  if(WITH_RECURSIVE)
+    if(NOT ${submodule}_UPDATED)
+      message(FATAL_ERROR "${submodule} not updated")
+    endif()
+  else()
+    if(${submodule}_UPDATED)
+      message(FATAL_ERROR "${submodule} updated")
+    endif()
+  endif()
+endforeach()' >CMakeLists.txt
+git add CMakeLists.txt
+git submodule add -- ../GIT-with-submodules submodule
+git commit -m "Initial import into repo."
+git push ../gitrepo-sub-rec.git "$defaultBranch"
+cd ../gitrepo-sub-rec.git
+git gc --prune
+cd ..
+)
+
+tar cvzf "$outdir/gitrepo.tgz" -C "$tmpdir" gitrepo.git
+tar cvzf "$outdir/gitrepo-sub.tgz" -C "$tmpdir" gitrepo-sub.git
+tar cvzf "$outdir/gitrepo-sub-rec.tgz" -C "$tmpdir" gitrepo-sub-rec.git
+
+git_tag=$(cd "$tmpdir/gitrepo.git" ; git rev-parse HEAD)
+sed -i "/generated by gitrepo.bash/ s/ [0-9a-f]\\+ / $git_tag /" "$outdir/CMakeLists.txt"
index 0a84bda..8d2d144 100644 (file)
Binary files a/Tests/ExternalProject/gitrepo.tgz and b/Tests/ExternalProject/gitrepo.tgz differ
index 789e4fb..9a0241c 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(ExternalProjectLocalTest NONE)
 if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
   cmake_policy(SET CMP0114 NEW)
index 563a6cf..6f8a7b1 100644 (file)
@@ -1,7 +1,12 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(ExternalProjectUpdateTest NONE)
 if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
   cmake_policy(SET CMP0114 NEW)
+else()
+  # This test is very noisy with warnings about this policy if we don't
+  # explicitly set it. Projects shouldn't do this, but for test code this
+  # is reasonable.
+  cmake_policy(SET CMP0114 OLD)
 endif()
 cmake_policy(GET CMP0114 cmp0114)
 
@@ -51,15 +56,9 @@ set(do_git_tests 0)
 if(GIT_EXECUTABLE)
   set(do_git_tests 1)
 
-  execute_process(
-    COMMAND "${GIT_EXECUTABLE}" --version
-    OUTPUT_VARIABLE ov
-    OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
-  string(REGEX REPLACE "^git version (.+)$" "\\1" git_version "${ov}")
-  message(STATUS "git_version='${git_version}'")
+  message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
 
-  if(git_version VERSION_LESS 1.6.5)
+  if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5)
     message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
     set(do_git_tests 0)
   endif()
index ddc513f..394df87 100644 (file)
@@ -167,15 +167,9 @@ set(do_git_tests 0)
 if(GIT_EXECUTABLE)
   set(do_git_tests 1)
 
-  execute_process(
-    COMMAND "${GIT_EXECUTABLE}" --version
-    OUTPUT_VARIABLE ov
-    OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
-  string(REGEX REPLACE "^git version (.+)$" "\\1" git_version "${ov}")
-  message(STATUS "git_version='${git_version}'")
+  message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
 
-  if(git_version VERSION_LESS 1.6.5)
+  if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5)
     message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
     set(do_git_tests 0)
   endif()
@@ -185,17 +179,16 @@ endif()
 file(REMOVE_RECURSE ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals)
 
 if(do_git_tests)
-  check_a_tag(origin/master 5842b503ba4113976d9bb28d57b5aee1ad2736b7 1 REBASE)
+  check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
   check_a_tag(tag1          d1970730310fe8bc07e73f15dc570071f9f9654a 1 REBASE)
-  # With the Git UPDATE_COMMAND performance patch, this will not required a
+  # With the Git UPDATE_COMMAND performance patch, this will not require a
   # 'git fetch'
   check_a_tag(tag1          d1970730310fe8bc07e73f15dc570071f9f9654a 0 REBASE)
   check_a_tag(tag2          5842b503ba4113976d9bb28d57b5aee1ad2736b7 1 REBASE)
-  check_a_tag(d19707303     d1970730310fe8bc07e73f15dc570071f9f9654a 1 REBASE)
   check_a_tag(d19707303     d1970730310fe8bc07e73f15dc570071f9f9654a 0 REBASE)
-  check_a_tag(origin/master 5842b503ba4113976d9bb28d57b5aee1ad2736b7 1 REBASE)
+  check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
   # This is a remote symbolic ref, so it will always trigger a 'git fetch'
-  check_a_tag(origin/master 5842b503ba4113976d9bb28d57b5aee1ad2736b7 1 REBASE)
+  check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
 
   foreach(strategy IN ITEMS CHECKOUT REBASE_CHECKOUT)
     # Move local master back, then apply a change that will cause a conflict
@@ -229,7 +222,19 @@ if(do_git_tests)
       message(FATAL_ERROR "Could not commit conflicting change.")
     endif()
     # This should discard our commit but leave behind an annotated tag
-    check_a_tag(origin/master 5842b503ba4113976d9bb28d57b5aee1ad2736b7 1 ${strategy})
+    check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 ${strategy})
   endforeach()
 
+  # This file matches a .gitignore rule that the last commit defines. We can't
+  # directly check that updates don't stash ignored contents because the stash
+  # and pop are both done within the update step. We don't have an opportunity
+  # to check things in between, but we can at least check that the update step
+  # doesn't choke on it.
+  set(ignoredFile ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT/ignored_item)
+  file(TOUCH ${ignoredFile})
+  check_a_tag(origin/master b5752a26ae448410926b35c275af3c192a53722e 1 REBASE)
+  if(NOT EXISTS ${ignoredFile})
+    message(FATAL_ERROR "Ignored file is missing")
+  endif()
+
 endif()
index 87090ab..4dab56b 100644 (file)
Binary files a/Tests/ExternalProjectUpdate/gitrepo.tgz and b/Tests/ExternalProjectUpdate/gitrepo.tgz differ
index be37957..0392d88 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(atk C)
 
index e8320b5..ec838de 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(atkmm CXX)
 
index 97a7369..3652ad6 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(cairo C)
 
index 47a156e..cde0f42 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(cairomm CXX)
 
index f485236..35ef337 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gdk C)
 
index 004e82e..ea1b05d 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gdk_pixbuf C)
 
index a54fc4f..72fc6f4 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gdkmm CXX)
 
index db9cdd0..4835afa 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gio C)
 
index 46cfef5..b639979 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(giomm CXX)
 
index 1aa73ff..536fc67 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(glib C)
 
index af8ddcf..25d5518 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(glibmm CXX)
 
index 9717da8..2bfb81e 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gmodule C)
 
index c51fd4d..11520f8 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gobject C)
 
index a90294d..5ecfd9b 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gthread C)
 
index 11603ae..2c67619 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gtk C)
 
index eb0b7aa..3375a55 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(gtkmm CXX)
 
index af382a4..bd6b13a 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(pango C)
 
index 8f61379..157b9c2 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(pangocairo C)
 
index 0f84c7f..76966e7 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(pangoft2 C)
 
index 3650c50..0bb49e2 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(pangomm CXX)
 
index 0db16b1..7051d35 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(pangoxft C)
 
index f830b81..9c1fff7 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(sigc++ CXX)
 
diff --git a/Tests/FindIntl/CMakeLists.txt b/Tests/FindIntl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0906ede
--- /dev/null
@@ -0,0 +1,10 @@
+add_test(NAME FindIntl.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindIntl/Test"
+  "${CMake_BINARY_DIR}/Tests/FindIntl/Test"
+  ${build_generator_args}
+  --build-project TestFindIntl
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/FindIntl/Test/CMakeLists.txt b/Tests/FindIntl/Test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5140406
--- /dev/null
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.10)
+project(TestFindIntl CXX)
+include(CTest)
+
+find_package(Intl REQUIRED)
+
+add_executable(test_intl_tgt main.cxx)
+target_link_libraries(test_intl_tgt Intl::Intl)
+add_test(NAME test_intl_tgt COMMAND test_intl_tgt)
+
+add_executable(test_intl_var main.cxx)
+target_include_directories(test_intl_var PRIVATE ${Intl_INCLUDE_DIRS})
+target_link_libraries(test_intl_var PRIVATE ${Intl_LIBRARIES})
+add_test(NAME test_intl_var COMMAND test_intl_var)
diff --git a/Tests/FindIntl/Test/main.cxx b/Tests/FindIntl/Test/main.cxx
new file mode 100644 (file)
index 0000000..d90c095
--- /dev/null
@@ -0,0 +1,11 @@
+extern "C" {
+#include <libintl.h>
+}
+
+int main()
+{
+  // Check if we include the directory correctly and have no link errors
+  bindtextdomain("", "");
+  gettext("");
+  return 0;
+}
index 374e147..1bc5c56 100644 (file)
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
 project(TestFindPostgreSQL C)
 include(CTest)
 
-find_package(PostgreSQL REQUIRED)
+find_package(PostgreSQL REQUIRED COMPONENTS Server)
 
 add_definitions(-DCMAKE_EXPECTED_POSTGRESQL_VERSION="${PostgreSQL_VERSION_STRING}")
 
index 44484c3..520ba9e 100644 (file)
@@ -451,6 +451,18 @@ if(CMake_TEST_FindPython)
       --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
       )
   endif()
+
+  if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    add_test(NAME FindPython.UnversionedNames COMMAND
+      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/FindPython/UnversionedNames"
+      "${CMake_BINARY_DIR}/Tests/FindPython/UnversionedNames"
+      ${build_generator_args}
+      --build-project UnversionedNames
+      --build-options ${build_options}
+    )
+  endif()
 endif()
 
 if(CMake_TEST_FindPython_NumPy)
diff --git a/Tests/FindPython/UnversionedNames/CMakeLists.txt b/Tests/FindPython/UnversionedNames/CMakeLists.txt
new file mode 100644 (file)
index 0000000..597bd4e
--- /dev/null
@@ -0,0 +1,66 @@
+cmake_minimum_required(VERSION 3.19...3.20)
+
+project(UnversionedNames LANGUAGES NONE)
+
+# check if it is possible to find python with a generic name
+find_program(UNVERSIONED_Python3 NAMES python3)
+
+if (NOT UNVERSIONED_Python3)
+  # no generic name available
+  # test cannot be done
+  return()
+endif()
+
+# search with default configuration
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (Python3_EXECUTABLE STREQUAL UNVERSIONED_Python3)
+  # default configuration pick-up the generic name
+  # test cannot be completed
+  return()
+endif()
+
+unset(Python3_EXECUTABLE)
+# Force now to search first for  generic name
+set(Python3_FIND_UNVERSIONED_NAMES FIRST)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (NOT Python3_EXECUTABLE STREQUAL UNVERSIONED_Python3)
+  message(SEND_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE} instead of ${UNVERSIONED_Python3}")
+endif()
+
+# To check value 'NEVER", creates  directory holding a symlink to the generic name
+file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/bin")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+file(CREATE_LINK "${UNVERSIONED_Python3}" "${CMAKE_CURRENT_BINARY_DIR}/bin/python3" SYMBOLIC)
+
+unset(Python3_EXECUTABLE)
+set(Python3_FIND_UNVERSIONED_NAMES FIRST)
+set(Python3_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+# First search: generic name must be found
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (NOT Python3_EXECUTABLE STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+  message(FATAL_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE} instead of ${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+endif()
+
+unset(Python3_EXECUTABLE)
+set(Python3_FIND_UNVERSIONED_NAMES LAST)
+
+# Second search: generic name must be found
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (NOT Python3_EXECUTABLE STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+  message(FATAL_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE} instead of ${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+endif()
+
+unset(Python3_EXECUTABLE)
+set(Python3_FIND_UNVERSIONED_NAMES NEVER)
+
+# Third search: generic name must NOT be found
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+
+if (Python3_EXECUTABLE STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/bin/python3")
+  message(FATAL_ERROR "Found unexpected interpreter ${Python3_EXECUTABLE}")
+endif()
index 929fa4d..1868892 100644 (file)
@@ -120,7 +120,7 @@ endfunction()
 # if the id's match or the compilers are compatible, then
 # call the test_fortran_c_interface_module function
 if("${CMAKE_Fortran_COMPILER_ID}:${CMAKE_C_COMPILER_ID}" MATCHES
-    "(Intel:MSVC|Absoft:GNU)"
+    "(Intel(LLVM)?:MSVC|Absoft:GNU)"
     OR ("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "${CMAKE_C_COMPILER_ID}" ))
   test_fortran_c_interface_module()
 else()
index efd9b68..1a4d5a4 100644 (file)
@@ -1,6 +1,6 @@
 #include "foo.h"
-extern F_test_mod_sub(void);
-extern F_mysub(void);
+extern void F_test_mod_sub(void);
+extern void F_mysub(void);
 int myc(void)
 {
   F_mysub();
index 79c670d..83c2729 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(FortranC C Fortran)
 
 # Skip this test for compilers not known to be compatible.
index 637f581..b5b5e56 100644 (file)
@@ -111,7 +111,7 @@ endif()
 
 # Test that with Intel Fortran we always compile with preprocessor
 # defines even if splitting the preprocessing and compilation steps.
-if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
+if(CMAKE_Fortran_COMPILER_ID MATCHES "Intel")
   add_executable(IntelIfDef IntelIfDef.f)
   set_property(TARGET IntelIfDef PROPERTY Fortran_FORMAT FIXED)
   target_compile_definitions(IntelIfDef PRIVATE SOME_DEF)
@@ -146,13 +146,13 @@ set_property(SOURCE no_preprocess_source_lower.f PROPERTY Fortran_PREPROCESS OFF
 # Test that we can explicitly not preprocess a target or source.
 # This will not work on certain compilers due to either missing a
 # "don't preprocess" flag, or due to choice of file extension.
-if(test_pp_flags AND NOT CMAKE_Fortran_COMPILER_ID MATCHES "(Flang|NAG|PGI|SunPro|XL)")
+if(test_pp_flags AND NOT CMAKE_Fortran_COMPILER_ID MATCHES "(Flang|NAG|PGI|NVHPC|SunPro|XL)")
   add_library(no_preprocess_target STATIC no_preprocess_target_upper.F)
   target_compile_options(no_preprocess_target PRIVATE -DINTEGER=nonsense)
   add_library(no_preprocess_source STATIC no_preprocess_source_upper.F)
   target_compile_options(no_preprocess_source PRIVATE -DINTEGER=nonsense)
   if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "Cray"
-      AND NOT "${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" STREQUAL "Intel;MSVC")
+      AND NOT "${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" MATCHES "Intel(LLVM)?;MSVC")
     target_sources(no_preprocess_target PRIVATE no_preprocess_target_fpp.fpp)
     target_sources(no_preprocess_source PRIVATE no_preprocess_source_fpp.fpp)
   endif()
diff --git a/Tests/Fuzzing/README.rst b/Tests/Fuzzing/README.rst
new file mode 100644 (file)
index 0000000..a869f9c
--- /dev/null
@@ -0,0 +1,8 @@
+The fuzzers in this directory are run continuously through OSS-fuzz.
+All fuzzers are implemented by way of the `libFuzzer engine`_.
+
+The link to the OSS-fuzz integration can be found here: (pending)
+All email addresses in the `project.yaml` file on OSS-fuzz will have access
+to detailed bug reports and will be notified via email if/when bugs are found.
+
+.. _`libFuzzer Engine`: https://llvm.org/docs/LibFuzzer.html
diff --git a/Tests/Fuzzing/xml_parser_fuzzer.cc b/Tests/Fuzzing/xml_parser_fuzzer.cc
new file mode 100644 (file)
index 0000000..1faa918
--- /dev/null
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cmXMLParser.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+  char test_file[] = "libfuzzer.xml";
+
+  FILE* fp = fopen(test_file, "wb");
+  if (!fp)
+    return 0;
+  fwrite(data, size, 1, fp);
+  fclose(fp);
+
+  cmXMLParser parser;
+  if (!parser.ParseFile(test_file)) {
+    return 1;
+  }
+
+  remove(test_file);
+  return 0;
+}
index 1f5b664..d4c19c7 100644 (file)
@@ -67,7 +67,11 @@ else()
 endif()
 
 # Test escaping of special characters in include directory paths.
-set(special_chars "~@%&{}()!'")
+set(special_chars "~@&{}()!'")
+if(NOT CMAKE_GENERATOR MATCHES "(Unix|MinGW|MSYS) Makefiles")
+  # when compiler is used for dependencies, special characters for make are not escaped
+  string(APPEND special_chars "%")
+endif()
 if(NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
   # Watcom seems to have no way to encode these characters.
   string(APPEND special_chars "#=[]")
index ec0a604..a302c7c 100644 (file)
@@ -1,5 +1,5 @@
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(InterfaceLibrary)
 
index 2023d25..f3cc89d 100644 (file)
@@ -11,7 +11,7 @@ include (UseJava)
 # JNI support
 find_package(JNI)
 
-add_jar(B1 D.java GENERATE_NATIVE_HEADERS D1-native)
+add_jar(B1 D.java GENERATE_NATIVE_HEADERS D1-native DESTINATION INSTALL include)
 add_jar(E1 E.java GENERATE_NATIVE_HEADERS E1-native)
 
 add_jar(hello4 HelloWorld3.java)
@@ -19,6 +19,13 @@ add_jar(hello4 HelloWorld3.java)
 add_library(D SHARED D.cpp E.cpp)
 target_link_libraries (D PRIVATE D1-native E1-native)
 
+install(TARGETS D1-native EXPORT native)
+install(DIRECTORY "$<TARGET_PROPERTY:D1-native,NATIVE_HEADERS_DIRECTORY>/" DESTINATION include)
+install(EXPORT native DESTINATION "${CMAKE_INSTALL_PREFIX}" NAMESPACE D1::)
+
 
 add_test (NAME Java.NativeHeaders
           COMMAND "${Java_JAVA_EXECUTABLE}" -Djava.library.path=$<TARGET_FILE_DIR:D> -classpath hello4.jar HelloWorld3)
+
+add_test (NAME Java.ImportNativeHeaders
+          COMMAND "${CMAKE_COMMAND}" "-DNATIVE_HEADERS_IMPORT_DIR=${CMAKE_INSTALL_PREFIX}" -S "${CMAKE_CURRENT_SOURCE_DIR}/Import" -B "${CMAKE_CURRENT_BINARY_DIR}/Import")
diff --git a/Tests/JavaNativeHeaders/Import/CMakeLists.txt b/Tests/JavaNativeHeaders/Import/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5486da9
--- /dev/null
@@ -0,0 +1,19 @@
+project(ImportJavaNativeHeaders LANGUAGES NONE)
+
+cmake_minimum_required (VERSION 3.19...3.20)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+include(${NATIVE_HEADERS_IMPORT_DIR}/native.cmake)
+
+if(NOT TARGET D1::D1-native)
+  message(FATAL_ERROR "Target 'D1::D1-native' not found.")
+endif()
+
+get_property(incs TARGET D1::D1-native PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
+if (NOT incs MATCHES "${NATIVE_HEADERS_IMPORT_DIR}/include")
+  message(FATAL_ERROR "Target 'D1::D1-native', property 'INTERFACE_INCLUDE_DIRECTORIES' badly defined: ${incs}.")
+endif()
+
+if (NOT EXISTS "${NATIVE_HEADERS_IMPORT_DIR}/include/D.h")
+  message(FATAL_ERROR "file '${NATIVE_HEADERS_IMPORT_DIR}/include/D.h' not found.")
+endif()
index c7a2700..d9a8ac8 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(LinkDirectory C)
 
 # Put the subproject source tree in our build tree so it can refer to
index c877913..e222929 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(LinkDirectoryExternal C)
 
 
index 4607035..31ff9b5 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(LinkFlags C)
 
 string(TOUPPER "${TEST_CONFIG}" TEST_CONFIG_UPPER)
index 62ff749..d17b955 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(mfc_driver)
 
 include(CTest)
index 3632e03..a600c63 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(mfc1)
 
 macro(replace_flags var these those)
index 8e5d746..768d2a6 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(try_compile_mfc)
 
 set(files
index 27838a4..41bd6f5 100644 (file)
@@ -6,8 +6,9 @@ foreach(t MultiThreaded SingleThreaded)
   foreach(dbg "" Debug)
     foreach(dll "" DLL)
       set(var "CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_${t}${dbg}${dll}")
-      if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
-        # ifort does not actually define these, so inject them
+      if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel"
+        OR CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
+        # ifort and ifx do not actually define these, so inject them
         string(REPLACE "-threads" "-threads;-D_MT" "${var}" "${${var}}")
         string(REPLACE "-dbglibs" "-dbglibs;-D_DEBUG" "${var}" "${${var}}")
       elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Flang")
index bf937e6..c9d3f2c 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(MacRuntimePath_A)
 
 # a shared library
index 4317af6..85598c4 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(MacRuntimePath_B)
 
 include(${MacRuntimePath_B_BINARY_DIR}/../Root/lib/exp.cmake)
index a7206c8..b4f0033 100644 (file)
@@ -1,3 +1,3 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(MissingSourceFile C)
 add_executable(MissingSourceFile DoesNotExist/MissingSourceFile.c)
index cffef5a..0cf74bf 100644 (file)
@@ -52,7 +52,7 @@ endmacro()
 # detailed features tables, not just meta-features
 
 if (CMAKE_C_COMPILE_FEATURES)
-  if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+  if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
     set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
     list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
   endif()
@@ -95,7 +95,7 @@ if (C_expected_features)
 endif()
 
 if (CMAKE_CXX_COMPILE_FEATURES)
-  if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+  if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
     set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
     list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
   endif()
index fca5f41..74f34e4 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(ObjectLibrary C)
 
 add_subdirectory(A)
index 22c92a7..fb0ebc0 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(ExportLanguages CXX)
 add_library(ExportLanguagesA OBJECT a.cxx)
 add_library(ExportLanguagesB STATIC a.c $<TARGET_OBJECTS:ExportLanguagesA>)
index 44194ca..5aa2459 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 cmake_policy(SET CMP0054 NEW)
 project(PDBDirectoryAndName C)
 
@@ -9,8 +9,9 @@ endif()
 
 # Intel 11.1 does not support /Fd but Intel 14.0 does.
 # TODO: Did a version in between these add it?
-if(CMAKE_C_COMPILER_ID STREQUAL Intel AND
-   CMAKE_C_COMPILER_VERSION VERSION_LESS 14.0)
+if((CMAKE_C_COMPILER_ID STREQUAL Intel AND
+    CMAKE_C_COMPILER_VERSION VERSION_LESS 14.0) OR
+   CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
   set(NO_COMPILE_PDB 1)
 endif()
 
index 5626dbc..f00122d 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(PluginTest)
 
index e79f3b7..ff779d3 100644 (file)
@@ -1,5 +1,5 @@
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(PositionIndependentTargets)
 
index bce1b3f..bf2af64 100644 (file)
@@ -147,8 +147,13 @@ endif()
 #  - NMake is okay with just \\\"
 #  - The XL compiler does not re-escape \\\" when launching an
 #    internal tool to do preprocessing .
+#  - The IntelLLVM C and C++ compiler drivers do not re-escape the \\\" when
+#    launching the underlying compiler. FIXME: this bug is expected to be fixed
+#    in a future release.
 if((PP_NMAKE OR PP_UMAKE) AND
-    NOT CMAKE_C_COMPILER_ID STREQUAL "XL")
+    NOT CMAKE_C_COMPILER_ID STREQUAL "XL" AND
+    NOT CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM" AND
+    NOT CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
   string(APPEND STRING_EXTRA "\\\"")
 endif()
 
index 2ca11e4..3ddc345 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(Qt4Targets)
 
index d9fc2b0..17855ff 100644 (file)
@@ -2,6 +2,15 @@ cmake_minimum_required(VERSION 3.11)
 project(AutogenOriginDependsOff)
 include("../AutogenCoreTest.cmake")
 
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+# XXX(xcode-per-cfg-src): Enable multi-config code path for Xcode
+# when the Xcode generator supports per-config sources.
+if(_isMultiConfig AND NOT CMAKE_GENERATOR STREQUAL "Xcode")
+  set(mocs_compilation_cpp "mocs_compilation_$<CONFIG>.cpp")
+else()
+  set(mocs_compilation_cpp "mocs_compilation.cpp")
+endif()
+
 set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
 set(CBD ${CMAKE_CURRENT_BINARY_DIR})
 include_directories(${CSD})
@@ -19,7 +28,7 @@ add_custom_command (
 add_custom_target ( a_mc
     COMMAND ${CMAKE_COMMAND} -E sleep 2
     COMMAND ${CMAKE_COMMAND}
-        "-DMCF=${CBD}/a_qt_autogen/mocs_compilation.cpp"
+        "-DMCF=${CBD}/a_qt_autogen/${mocs_compilation_cpp}"
         "-DCF_IN=${CSD}/a_mc.hpp.in"
         "-DCF_OUT=${CBD}/a_mc.hpp"
         -P ${CSD}/configure_content.cmake
@@ -51,7 +60,7 @@ add_custom_command (
     DEPENDS b_qt_autogen
     COMMAND ${CMAKE_COMMAND} -E sleep 2
     COMMAND ${CMAKE_COMMAND}
-        "-DMCF=${CBD}/b_qt_autogen/mocs_compilation.cpp"
+        "-DMCF=${CBD}/b_qt_autogen/${mocs_compilation_cpp}"
         "-DCF_IN=${CSD}/b_mc.cpp.in"
         "-DCF_OUT=${CBD}/b_mc.cpp"
         -P ${CSD}/configure_content.cmake
index 81fd8db..e95c626 100644 (file)
@@ -13,10 +13,10 @@ include("../AutogenCoreTest.cmake")
 set(GAT_SDIR "${CMAKE_CURRENT_SOURCE_DIR}/GAT")
 set(GAT_BDIR "${CMAKE_CURRENT_BINARY_DIR}/GAT")
 # Files
-set(MCA "sda/sda_autogen/mocs_compilation.cpp")
-set(MCB "sdb/sdb_autogen/mocs_compilation.cpp")
-set(MCC "sdc/sdc_autogen/mocs_compilation.cpp")
-set(MCG "gat_autogen/mocs_compilation.cpp")
+set(MCA "sda/sda_autogen/mocs_compilation*.cpp")
+set(MCB "sdb/sdb_autogen/mocs_compilation*.cpp")
+set(MCC "sdc/sdc_autogen/mocs_compilation*.cpp")
+set(MCG "gat_autogen/mocs_compilation*.cpp")
 
 set(DRA "sda/sda_autogen/*qrc_data.cpp")
 set(DRB "sdb/sdb_autogen/*qrc_data.cpp")
index e109154..f4fde58 100644 (file)
@@ -11,6 +11,18 @@ add_executable(mocOnly
   IncA.cpp
   IncB.cpp
 )
+# XXX(xcode-per-cfg-src): Drop the NO_PER_CONFIG_SOURCES exclusion
+# when the Xcode generator supports per-config sources.
+if(NOT NO_PER_CONFIG_SOURCES)
+  target_sources(mocOnly PRIVATE
+    "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/CfgDebug.cpp>"
+    "$<$<NOT:$<CONFIG:Debug>>:${CMAKE_CURRENT_SOURCE_DIR}/CfgOther.cpp>"
+    )
+  target_compile_definitions(mocOnly PRIVATE
+    "$<$<CONFIG:Debug>:HAVE_CFG_DEBUG>"
+    "$<$<NOT:$<CONFIG:Debug>>:HAVE_CFG_OTHER>"
+    )
+endif()
 set_property(TARGET mocOnly PROPERTY AUTOMOC ON)
 target_link_libraries(mocOnly ${QT_LIBRARIES})
 # Add compile definitions with unusual characters
diff --git a/Tests/QtAutogen/MocOnly/CfgDebug.cpp b/Tests/QtAutogen/MocOnly/CfgDebug.cpp
new file mode 100644 (file)
index 0000000..07ca3fb
--- /dev/null
@@ -0,0 +1,5 @@
+#include "CfgDebug.hpp"
+
+CfgDebug::CfgDebug()
+{
+}
diff --git a/Tests/QtAutogen/MocOnly/CfgDebug.hpp b/Tests/QtAutogen/MocOnly/CfgDebug.hpp
new file mode 100644 (file)
index 0000000..3cd90a4
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef CFGDEBUG_HPP
+#define CFGDEBUG_HPP
+
+#include <QObject>
+
+/* clang-format off */
+class CfgDebug : public QObject
+{
+  Q_OBJECT
+public:
+  CfgDebug();
+};
+/* clang-format on */
+
+#endif
diff --git a/Tests/QtAutogen/MocOnly/CfgOther.cpp b/Tests/QtAutogen/MocOnly/CfgOther.cpp
new file mode 100644 (file)
index 0000000..0ccd433
--- /dev/null
@@ -0,0 +1,5 @@
+#include "CfgOther.hpp"
+
+CfgOther::CfgOther()
+{
+}
diff --git a/Tests/QtAutogen/MocOnly/CfgOther.hpp b/Tests/QtAutogen/MocOnly/CfgOther.hpp
new file mode 100644 (file)
index 0000000..7cacd52
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef CFGOTHER_HPP
+#define CFGOTHER_HPP
+
+#include <QObject>
+
+/* clang-format off */
+class CfgOther : public QObject
+{
+  Q_OBJECT
+public:
+  CfgOther();
+};
+/* clang-format on */
+
+#endif
index ec8da21..6c0f6f2 100644 (file)
@@ -5,6 +5,14 @@
 #include "StyleA.hpp"
 #include "StyleB.hpp"
 
+#ifdef HAVE_CFG_DEBUG
+#  include "CfgDebug.hpp"
+#endif
+
+#ifdef HAVE_CFG_OTHER
+#  include "CfgOther.hpp"
+#endif
+
 int main(int argv, char** args)
 {
   StyleA styleA;
index 9b32e59..c53e857 100644 (file)
@@ -47,19 +47,38 @@ macro(require_change_not)
 endmacro()
 
 
-# Initial build
+# Configure the test project
 configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
-try_compile(MOC_RERUN
-  "${mocBasicBinDir}"
-  "${mocBasicSrcDir}"
-  MocBasic
-  CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
-              "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
-              "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+configure_file("${mocBasicSrcDir}/myobject3a.h.in" "${mocBasicBinDir}/myobject3.h" @ONLY)
+if(CMAKE_GENERATOR_INSTANCE)
+    set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}")
+else()
+    set(_D_CMAKE_GENERATOR_INSTANCE "")
+endif()
+execute_process(
+  COMMAND "${CMAKE_COMMAND}" -B "${mocBasicBinDir}" -S "${mocBasicSrcDir}"
+          -G "${CMAKE_GENERATOR}"
+          -A "${CMAKE_GENERATOR_PLATFORM}"
+          -T "${CMAKE_GENERATOR_TOOLSET}"
+          ${_D_CMAKE_GENERATOR_INSTANCE}
+          "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+          "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+          "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+  RESULT_VARIABLE exit_code
   OUTPUT_VARIABLE output
 )
-if (NOT MOC_RERUN)
-  message(FATAL_ERROR "Initial build of mocBasic failed. Output: ${output}")
+if(NOT exit_code EQUAL 0)
+  message(FATAL_ERROR "Initial configuration of mocBasic failed. Output: ${output}")
+endif()
+
+# Initial build
+execute_process(
+    COMMAND "${CMAKE_COMMAND}" --build "${mocBasicBinDir}"
+    RESULT_VARIABLE exit_code
+    OUTPUT_VARIABLE output
+)
+if(NOT exit_code EQUAL 0)
+    message(FATAL_ERROR "Initial build of mocBasic failed. Output: ${output}")
 endif()
 
 # Get name of the output binary
@@ -100,3 +119,43 @@ message(STATUS "Changing nothing for no MOC re-run")
 rebuild(3)
 acquire_timestamp(After)
 require_change_not()
+
+
+# - Ensure that the timestamp will change
+# - Remove Q_OBJECT from header
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Remove Q_OBJECT from header file for a MOC re-run")
+configure_file("${mocBasicSrcDir}/test1c.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
+sleep()
+rebuild(4)
+acquire_timestamp(After)
+require_change()
+
+
+# - Ensure that the timestamp will change
+# - Add Q_OBJECT to header again
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Add Q_OBJECT to test1.h for a MOC re-run")
+configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY)
+sleep()
+rebuild(5)
+acquire_timestamp(After)
+require_change()
+
+
+# - Ensure that the timestamp will change
+# - Add Q_OBJECT to MyObject3
+# - Rebuild
+acquire_timestamp(Before)
+sleep()
+message(STATUS "Add Q_OBJECT to myobject3.h file for a MOC re-run")
+set(CLASS_CONTENT "Q_OBJECT")
+configure_file("${mocBasicSrcDir}/myobject3a.h.in" "${mocBasicBinDir}/myobject3.h" @ONLY)
+sleep()
+rebuild(6)
+acquire_timestamp(After)
+require_change()
index 6a9f550..42f2f57 100644 (file)
@@ -13,10 +13,15 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
 
 add_executable(mocBasic
   ${CMAKE_CURRENT_BINARY_DIR}/test1.h
+  ${CMAKE_CURRENT_BINARY_DIR}/myobject3.h
   ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
+  plainobject.cpp
   res1.qrc
 )
-target_include_directories(mocBasic PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+target_include_directories(mocBasic PRIVATE
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}
+)
 target_link_libraries(mocBasic ${QT_QTCORE_TARGET})
 # Write target name to text file
 add_custom_command(TARGET mocBasic POST_BUILD COMMAND
index 9d7ea37..5accfd6 100644 (file)
@@ -1,4 +1,5 @@
 #include "test1.h"
+#include "plainobject.h"
 
 extern int qInitResources_res1();
 
@@ -16,6 +17,7 @@ int main()
 
   Test1 test1;
   Test2 test2;
+  PlainObject plainObject;
 
   return 0;
 }
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in
new file mode 100644 (file)
index 0000000..d62c314
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef MYOBJECT3_H
+#define MYOBJECT3_H
+
+#include <qobject.h>
+
+class MyObject3 : public QObject
+{
+    @CLASS_CONTENT@
+public:
+    MyObject3() {}
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp
new file mode 100644 (file)
index 0000000..0ca785e
--- /dev/null
@@ -0,0 +1,12 @@
+#include "plainobject.h"
+
+#include "myobject3.h"
+
+PlainObject::PlainObject()
+{
+}
+
+void PlainObject::doSomething()
+{
+  MyObject3 obj3;
+}
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h
new file mode 100644 (file)
index 0000000..8037858
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef PLAINOBJECT_H
+#define PLAINOBJECT_H
+
+// Class that is plain C++, no Qt involved.
+class PlainObject
+{
+public:
+  PlainObject();
+  void doSomething();
+};
+
+#endif
diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in
new file mode 100644 (file)
index 0000000..d0b9868
--- /dev/null
@@ -0,0 +1,6 @@
+#include <QObject>
+class Test1
+{
+public:
+  void onTst1() {}
+};
index 0e27188..1024996 100644 (file)
@@ -1,12 +1,19 @@
 # Autogen build options
 set(Autogen_BUILD_OPTIONS "-DQT_TEST_VERSION=${QT_TEST_VERSION}")
-if(NOT _isMultiConfig)   # Set in Tests/CMakeLists.txt
+if(_isMultiConfig)   # Set in Tests/CMakeLists.txt
+  list(APPEND Autogen_CTEST_OPTIONS --build-config $<CONFIGURATION>)
+else()
   list(APPEND Autogen_BUILD_OPTIONS "-DCMAKE_BUILD_TYPE=$<CONFIGURATION>")
 endif()
 list(APPEND Autogen_BUILD_OPTIONS
     "-DCMAKE_AUTOGEN_VERBOSE=1"
     "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
 )
+# XXX(xcode-per-cfg-src): Drop the NO_PER_CONFIG_SOURCES exclusion
+# when the Xcode generator supports per-config sources.
+if(CMAKE_GENERATOR STREQUAL "Xcode")
+  list(APPEND Autogen_BUILD_OPTIONS -DNO_PER_CONFIG_SOURCES=1)
+endif()
 
 # A macro to add a QtAutogen test
 macro(ADD_AUTOGEN_TEST NAME)
@@ -30,6 +37,7 @@ macro(ADD_AUTOGEN_TEST NAME)
     "${_BuildDir}"
     ${build_generator_args}
     --build-project ${NAME}
+    ${Autogen_CTEST_OPTIONS}
     --build-exe-dir "${_BuildDir}"
     --force-new-ctest-process
     --build-options ${build_options} ${Autogen_BUILD_OPTIONS}
index b26e471..655f12b 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 
 project(QtAutomocNoQt)
 
diff --git a/Tests/RunCMake/ABI/C-stdout.txt b/Tests/RunCMake/ABI/C-stdout.txt
new file mode 100644 (file)
index 0000000..5b67b84
--- /dev/null
@@ -0,0 +1 @@
+-- Check if the system is big endian
diff --git a/Tests/RunCMake/ABI/C.cmake b/Tests/RunCMake/ABI/C.cmake
new file mode 100644 (file)
index 0000000..92f5da4
--- /dev/null
@@ -0,0 +1,22 @@
+enable_language(C)
+if(NOT CMAKE_C_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+  if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+    return()
+  endif()
+  message(FATAL_ERROR "CMAKE_C_BYTE_ORDER has unexpected value '${CMAKE_C_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+  message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
+
+# Test legacy check.
+set(byte_order "${CMAKE_C_BYTE_ORDER}")
+unset(CMAKE_C_BYTE_ORDER)
+include(TestBigEndian)
+test_big_endian(IS_BIG)
+if(IS_BIG AND NOT byte_order STREQUAL "BIG_ENDIAN")
+  message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/CMakeLists.txt b/Tests/RunCMake/ABI/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ab1a20c
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/ABI/CUDA.cmake b/Tests/RunCMake/ABI/CUDA.cmake
new file mode 100644 (file)
index 0000000..8ede3a9
--- /dev/null
@@ -0,0 +1,13 @@
+enable_language(CUDA)
+if(NOT CMAKE_CUDA_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+  if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+    return()
+  endif()
+  message(FATAL_ERROR "CMAKE_CUDA_BYTE_ORDER has unexpected value '${CMAKE_CUDA_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_CUDA_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+  message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/CXX-stdout.txt b/Tests/RunCMake/ABI/CXX-stdout.txt
new file mode 100644 (file)
index 0000000..5b67b84
--- /dev/null
@@ -0,0 +1 @@
+-- Check if the system is big endian
diff --git a/Tests/RunCMake/ABI/CXX.cmake b/Tests/RunCMake/ABI/CXX.cmake
new file mode 100644 (file)
index 0000000..2310002
--- /dev/null
@@ -0,0 +1,22 @@
+enable_language(CXX)
+if(NOT CMAKE_CXX_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+  if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+    return()
+  endif()
+  message(FATAL_ERROR "CMAKE_CXX_BYTE_ORDER has unexpected value '${CMAKE_CXX_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_CXX_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+  message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
+
+# Test legacy check.
+set(byte_order "${CMAKE_CXX_BYTE_ORDER}")
+unset(CMAKE_CXX_BYTE_ORDER)
+include(TestBigEndian)
+test_big_endian(IS_BIG)
+if(IS_BIG AND NOT byte_order STREQUAL "BIG_ENDIAN")
+  message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/OBJC.cmake b/Tests/RunCMake/ABI/OBJC.cmake
new file mode 100644 (file)
index 0000000..ab67459
--- /dev/null
@@ -0,0 +1,13 @@
+enable_language(OBJC)
+if(NOT CMAKE_OBJC_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+  if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+    return()
+  endif()
+  message(FATAL_ERROR "CMAKE_OBJC_BYTE_ORDER has unexpected value '${CMAKE_OBJC_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_OBJC_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+  message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/OBJCXX.cmake b/Tests/RunCMake/ABI/OBJCXX.cmake
new file mode 100644 (file)
index 0000000..41a719e
--- /dev/null
@@ -0,0 +1,13 @@
+enable_language(OBJCXX)
+if(NOT CMAKE_OBJCXX_BYTE_ORDER MATCHES "^(BIG_ENDIAN|LITTLE_ENDIAN)$")
+  if(CMAKE_OSX_ARCHITECTURES MATCHES ";ppc|ppc;")
+    return()
+  endif()
+  message(FATAL_ERROR "CMAKE_OBJCXX_BYTE_ORDER has unexpected value '${CMAKE_OBJCXX_BYTE_ORDER}'")
+endif()
+
+include(TestBigEndian)
+test_big_endian(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN AND NOT CMAKE_OBJCXX_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+  message(FATAL_ERROR "test_big_endian result does not match ABI result")
+endif()
diff --git a/Tests/RunCMake/ABI/RunCMakeTest.cmake b/Tests/RunCMake/ABI/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..d9eabb7
--- /dev/null
@@ -0,0 +1,15 @@
+include(RunCMake)
+
+run_cmake(C)
+run_cmake(CXX)
+
+if(APPLE)
+  run_cmake(OBJC)
+  run_cmake(OBJCXX)
+endif()
+
+if(CMake_TEST_CUDA)
+  run_cmake(CUDA)
+endif()
+
+run_cmake(TestBigEndian-NoLang)
diff --git a/Tests/RunCMake/ABI/TestBigEndian-NoLang-stderr.txt b/Tests/RunCMake/ABI/TestBigEndian-NoLang-stderr.txt
new file mode 100644 (file)
index 0000000..d0aa899
--- /dev/null
@@ -0,0 +1,8 @@
+^CMake Error at [^
+]*/Modules/TestBigEndian.cmake:[0-9]+ \(message\):
+  TEST_BIG_ENDIAN needs either C or CXX language enabled
+Call Stack \(most recent call first\):
+  [^
+]*/Modules/TestBigEndian.cmake:[0-9]+ \(__TEST_BIG_ENDIAN_LEGACY_IMPL\)
+  TestBigEndian-NoLang.cmake:[0-9]+ \(test_big_endian\)
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/ABI/TestBigEndian-NoLang.cmake b/Tests/RunCMake/ABI/TestBigEndian-NoLang.cmake
new file mode 100644 (file)
index 0000000..8c10201
--- /dev/null
@@ -0,0 +1,2 @@
+include(TestBigEndian)
+test_big_endian(var)
index c4b1a00..aa0cf4d 100644 (file)
@@ -103,6 +103,13 @@ foreach(ndk IN LISTS TEST_ANDROID_NDK)
     set(ndk_arg)
   endif()
 
+  set(RunCMake_TEST_OPTIONS
+    -DCMAKE_SYSTEM_NAME=Android
+    -DCMAKE_FIND_ROOT_PATH=/tmp
+    ${ndk_arg}
+    )
+  run_cmake(ndk-search-order)
+
   # Test failure cases.
   message(STATUS "ndk='${ndk}'")
   if(RunCMake_GENERATOR MATCHES "Visual Studio")
index 32412aa..7c80a04 100644 (file)
@@ -5,10 +5,21 @@ if(NOT ANDROID)
   message(SEND_ERROR "CMake variable 'ANDROID' is not set to a true value.")
 endif()
 
-foreach(f
-    "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ar${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
+set(files
+  "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ar${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
+  )
+if(NOT CMAKE_ANDROID_NDK_VERSION VERSION_GREATER_EQUAL 22)
+  list(APPEND files
     "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ld${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
     )
+endif()
+if(NOT CMAKE_ANDROID_NDK_VERSION VERSION_GREATER_EQUAL 19)
+  list(APPEND files
+    "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}"
+    "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}g++${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
+    )
+endif()
+foreach(f IN LISTS files)
   if(NOT EXISTS "${f}")
     message(SEND_ERROR "Expected file does not exist:\n \"${f}\"")
   endif()
diff --git a/Tests/RunCMake/Android/ndk-search-order.cmake b/Tests/RunCMake/Android/ndk-search-order.cmake
new file mode 100644 (file)
index 0000000..498d775
--- /dev/null
@@ -0,0 +1,17 @@
+if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+  return()
+endif()
+
+find_library(LIBDL dl)
+if(NOT LIBDL)
+  message(FATAL_ERROR "libdl not found.")
+endif()
+
+if(LIBDL MATCHES ".a$")
+  message(FATAL_ERROR "found libdl.a")
+endif()
+
+find_program(CLANG clang)
+if(NOT CLANG)
+  message(FATAL_ERROR "clang not found")
+endif()
diff --git a/Tests/RunCMake/ArtifactOutputDirs/ArtifactOutputDirs.cmake b/Tests/RunCMake/ArtifactOutputDirs/ArtifactOutputDirs.cmake
new file mode 100644 (file)
index 0000000..d0accd7
--- /dev/null
@@ -0,0 +1,27 @@
+enable_language(C)
+
+if(CMAKE_IMPORT_LIBRARY_SUFFIX)
+  set(expect_dll 1)
+else()
+  set(expect_dll 0)
+endif()
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/$<IF:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>,rtlib,rtbin>")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/$<IF:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>,sharedlib,others>")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/$<IF:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>,staticlib,others>")
+
+add_executable(exe_tgt main.c)
+add_library(shared_tgt SHARED lib.c)
+add_library(static_tgt STATIC lib.c)
+
+add_custom_target(checkDirs ALL
+  COMMAND ${CMAKE_COMMAND}
+    -Dartifact_path=${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>
+    -Dexe_name=$<TARGET_FILE_NAME:exe_tgt>
+    -Dshared_name=$<TARGET_FILE_NAME:shared_tgt>
+    -Dstatic_name=$<TARGET_FILE_NAME:static_tgt>
+    -Dexpect_dll=${expect_dll}
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
+  )
+
+add_dependencies(checkDirs exe_tgt shared_tgt static_tgt)
diff --git a/Tests/RunCMake/ArtifactOutputDirs/CMakeLists.txt b/Tests/RunCMake/ArtifactOutputDirs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ab1a20c
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/ArtifactOutputDirs/RunCMakeTest.cmake b/Tests/RunCMake/ArtifactOutputDirs/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..1bf8438
--- /dev/null
@@ -0,0 +1,19 @@
+include(RunCMake)
+
+function(run_cmake_and_verify_after_build case)
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${case}-build")
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
+  else()
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+  endif()
+  run_cmake(${case})
+  run_cmake_command("${case}-build" ${CMAKE_COMMAND} --build .)
+  unset(RunCMake_TEST_NO_CLEAN)
+  unset(RunCMake_TEST_BINARY_DIR)
+endfunction()
+
+run_cmake_and_verify_after_build(ArtifactOutputDirs)
diff --git a/Tests/RunCMake/ArtifactOutputDirs/check.cmake b/Tests/RunCMake/ArtifactOutputDirs/check.cmake
new file mode 100644 (file)
index 0000000..ca37eba
--- /dev/null
@@ -0,0 +1,21 @@
+set(expected ${artifact_path}/rtbin/${exe_name})
+if(NOT EXISTS "${expected}")
+  message(SEND_ERROR "executable artifact not created in the expected path:\n  ${expected}")
+endif()
+
+set(expected ${artifact_path}/staticlib/${static_name})
+if(NOT EXISTS "${expected}")
+  message(SEND_ERROR "static artifact not created in the expected path:\n  ${expected}")
+endif()
+
+if(expect_dll)
+  set(expected ${artifact_path}/rtlib/${shared_name})
+  if(NOT EXISTS "${expected}")
+    message(SEND_ERROR "dll artifact not created in the expected path:\n  ${expected}")
+  endif()
+else()
+  set(expected ${artifact_path}/sharedlib/${shared_name})
+  if(NOT EXISTS "${expected}")
+    message(SEND_ERROR "shared artifact not created in the expected path:\n  ${expected}")
+  endif()
+endif()
index 74b3ff8..99f238b 100644 (file)
@@ -1,3 +1,3 @@
 cmake_minimum_required(VERSION 3.3)
 project(${RunCMake_TEST} NONE)
-include(${RunCMake_TEST}.cmake)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.cmake
new file mode 100644 (file)
index 0000000..8a9e600
--- /dev/null
@@ -0,0 +1,46 @@
+enable_language(C)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+  \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+  \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.h\"
+  )
+set(check_exes
+  \"$<TARGET_FILE:main>\"
+  )
+
+if (check_step EQUAL 2)
+  include(\"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Makefile.cmake\")
+  if (NOT CMAKE_DEPEND_INFO_FILES)
+    set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
+  else()
+    include(\"${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_DEPEND_INFO_FILES}\")
+    if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)
+      set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPENDS_DEPENDENCY_FILES not found.\")
+    else()
+      list(GET CMAKE_DEPENDS_DEPENDENCY_FILES 1 OBJECT_FILE)
+      list(GET CMAKE_DEPENDS_DEPENDENCY_FILES 3 DEP_FILE)
+      if (NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+        set(RunCMake_TEST_FAILED \"File \${DEP_FILE} not found.\")
+      else()
+        set (TARGET_DEP_FILE \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+        cmake_path(REPLACE_FILENAME TARGET_DEP_FILE \"compiler_depend.make\")
+        file(READ \"\${TARGET_DEP_FILE}\" DEPENDS_CONTENT)
+        if (WIN32)
+          string (REPLACE \"\\\\\" \"/\" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+          string (TOLOWER \"\${DEPENDS_CONTENT}\" DEPENDS_CONTENT)
+          string (TOLOWER \"\${OBJECT_FILE}\" OBJECT_FILE)
+        else()
+          string(REPLACE \"\\\\ \" \" \" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+        endif()
+        if(NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c\"
+            OR NOT DEPENDS_CONTENT MATCHES \"main.h\")
+          set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated.\")
+        endif()
+      endif()
+    endif()
+  endif()
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.step1.cmake
new file mode 100644 (file)
index 0000000..1da2593
--- /dev/null
@@ -0,0 +1,9 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h" [[
+#define COUNT 1
+]])
+
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c" [[
+#include "main.h"
+
+int main(void) { return COUNT; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/CompilerDependencies.step2.cmake
new file mode 100644 (file)
index 0000000..e983665
--- /dev/null
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h" [[
+#define COUNT 2
+]])
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt
new file mode 100644 (file)
index 0000000..cddea3c
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at CustomCommandDependencies-BadArgs.cmake:[0-9]+ \(add_custom_command\):
+  add_custom_command IMPLICIT_DEPENDS and DEPFILE can not both be specified.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake
new file mode 100644 (file)
index 0000000..91ee338
--- /dev/null
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_custom_command(OUTPUT main.c
+  DEPFILE main.c.d
+  IMPLICIT_DEPENDS C main.c.in
+  COMMAND "${CMAKE_COMMAND}" -DINFILE=main.c.in -DOUTFILE=main.c -DDEPFILE=main.c.d
+  -P "${CMAKE_CURRENT_SOURCE_DIR}/GenerateDepFile.cmake"
+  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_custom_target(mainc ALL DEPENDS main.c)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake
new file mode 100644 (file)
index 0000000..28bbf11
--- /dev/null
@@ -0,0 +1,73 @@
+enable_language(C)
+
+add_custom_command(OUTPUT main.c
+  DEPFILE main.c.d
+  COMMAND "${CMAKE_COMMAND}" -DINFILE=main.c.in -DOUTFILE=main.c -DDEPFILE=main.c.d
+  -P "${CMAKE_CURRENT_SOURCE_DIR}/GenerateDepFile.cmake"
+  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_custom_target(mainc ALL DEPENDS main.c)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+cmake_minimum_required(VERSION 3.19)
+set(check_pairs
+  \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c.in\"
+  \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+  )
+set(check_exes
+  \"$<TARGET_FILE:main>\"
+  )
+
+if (check_step EQUAL 2)
+  include(\"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Makefile.cmake\")
+  if (NOT CMAKE_DEPEND_INFO_FILES)
+    set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
+  else()
+    foreach(DEPEND_INFO_FILE IN LISTS CMAKE_DEPEND_INFO_FILES)
+      include(\"${CMAKE_CURRENT_BINARY_DIR}/\${DEPEND_INFO_FILE}\")
+      if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)
+        set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPENDS_DEPENDENCY_FILES not found.\")
+      else()
+        list(LENGTH CMAKE_DEPENDS_DEPENDENCY_FILES DEPENDENCY_FILES_SIZE)
+          math(EXPR STOP_INDEX \"\${DEPENDENCY_FILES_SIZE} - 1\")
+        foreach(INDEX RANGE 0 \${STOP_INDEX} 4)
+          math(EXPR OBJECT_INDEX \"\${INDEX} + 1\")
+          math(EXPR FORMAT_INDEX \"\${INDEX} + 2\")
+          math(EXPR DEP_INDEX \"\${INDEX} + 3\")
+          list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${OBJECT_INDEX} OBJECT_FILE)
+          list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${FORMAT_INDEX} DEP_FORMAT)
+          list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${DEP_INDEX} DEP_FILE)
+          if (NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+            set(RunCMake_TEST_FAILED \"File \${DEP_FILE} not found.\")
+          else()
+            cmake_path(APPEND TARGET_DEP_FILE \"${CMAKE_CURRENT_BINARY_DIR}\" \"\${DEPEND_INFO_FILE}\")
+            cmake_path(REPLACE_FILENAME TARGET_DEP_FILE \"compiler_depend.make\")
+            file(READ \"\${TARGET_DEP_FILE}\" DEPENDS_CONTENT)
+            if (WIN32)
+              string (REPLACE \"\\\\\" \"/\" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+              string (TOLOWER \"\${DEPENDS_CONTENT}\" DEPENDS_CONTENT)
+              string (TOLOWER \"\${OBJECT_FILE}\" OBJECT_FILE)
+            else()
+              string(REPLACE \"\\\\ \" \" \" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+            endif()
+            if(DEPEND_INFO_FILE MATCHES \"main\\\\.dir\")
+              if (DEP_FORMAT STREQUAL \"gcc\" AND NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c\")
+                set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+              endif()
+              if (DEP_FORMAT STREQUAL \"custom\" AND NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c.in\")
+                set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+              endif()
+            else()
+              if (NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c.in\")
+                set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+              endif()
+            endif()
+          endif()
+        endforeach()
+      endif()
+    endforeach()
+  endif()
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake
new file mode 100644 (file)
index 0000000..87576eb
--- /dev/null
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c.in" [[
+int main(void) { return 1; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake
new file mode 100644 (file)
index 0000000..69b21b8
--- /dev/null
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c.in" [[
+int main(void) { return 2; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
new file mode 100644 (file)
index 0000000..01eac91
--- /dev/null
@@ -0,0 +1,61 @@
+cmake_policy(SET CMP0116 NEW)
+enable_language(C)
+
+add_custom_command(
+  OUTPUT topcc.c
+  DEPFILE topcc.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/topcc.c -DINFILE=topccdep.txt -DDEPFILE=topcc.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+  )
+add_custom_target(topcc ALL DEPENDS topcc.c)
+
+add_custom_command(
+  OUTPUT topexe.c
+  DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/topexe.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=topexe.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/topexedep.txt" -DDEPFILE=topexe.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+  )
+add_executable(topexe "${CMAKE_CURRENT_BINARY_DIR}/topexe.c")
+
+add_custom_command(
+  OUTPUT toplib.c
+  DEPFILE toplib.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=toplib.c -DINFILE=toplibdep.txt -DDEPFILE=toplib.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+  )
+add_library(toplib STATIC toplib.c)
+
+add_subdirectory(DepfileSubdir)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+function(check_exists file)
+  if(NOT EXISTS \"\${file}\")
+    string(APPEND RunCMake_TEST_FAILED \"\${file} does not exist\\n\")
+  endif()
+  set(RunCMake_TEST_FAILED \"\${RunCMake_TEST_FAILED}\" PARENT_SCOPE)
+endfunction()
+
+function(check_not_exists file)
+  if(EXISTS \"\${file}\")
+    string(APPEND RunCMake_TEST_FAILED \"\${file} exists\\n\")
+  endif()
+  set(RunCMake_TEST_FAILED \"\${RunCMake_TEST_FAILED}\" PARENT_SCOPE)
+endfunction()
+
+set(check_pairs
+  \"${CMAKE_BINARY_DIR}/topcc.c|${CMAKE_BINARY_DIR}/topccdep.txt\"
+  \"$<TARGET_FILE:topexe>|${CMAKE_BINARY_DIR}/topexedep.txt\"
+  \"$<TARGET_FILE:toplib>|${CMAKE_BINARY_DIR}/toplibdep.txt\"
+  \"${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c|${CMAKE_BINARY_DIR}/DepfileSubdir/subccdep.txt\"
+  \"$<TARGET_FILE:subexe>|${CMAKE_BINARY_DIR}/DepfileSubdir/subexedep.txt\"
+  \"$<TARGET_FILE:sublib>|${CMAKE_BINARY_DIR}/DepfileSubdir/sublibdep.txt\"
+  )
+
+if(check_step EQUAL 3)
+  list(APPEND check_pairs
+    \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/topcc.c\"
+    \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:topexe>\"
+    \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:toplib>\"
+    \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c\"
+    \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:subexe>\"
+    \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:sublib>\"
+    )
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake
new file mode 100644 (file)
index 0000000..0dfe78e
--- /dev/null
@@ -0,0 +1,10 @@
+file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir")
+file(REMOVE "${RunCMake_TEST_BINARY_DIR}/../sublib.c")
+file(REMOVE "${RunCMake_TEST_BINARY_DIR}/step3.timestamp")
+
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake
new file mode 100644 (file)
index 0000000..c711514
--- /dev/null
@@ -0,0 +1,6 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake
new file mode 100644 (file)
index 0000000..c55ccc1
--- /dev/null
@@ -0,0 +1 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/step3.timestamp")
diff --git a/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt b/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f131751
--- /dev/null
@@ -0,0 +1,22 @@
+cmake_policy(SET CMP0116 NEW)
+
+add_custom_command(
+  OUTPUT subcc.c
+  DEPFILE subcc.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/subcc.c -DINFILE=subccdep.txt -DDEPFILE=subcc.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+  )
+add_custom_target(subcc ALL DEPENDS subcc.c)
+
+add_custom_command(
+  OUTPUT subexe.c
+  DEPFILE subexe.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=subexe.c -DINFILE=subexedep.txt -DDEPFILE=subexe.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+  )
+add_executable(subexe subexe.c)
+
+add_custom_command(
+  OUTPUT ${CMAKE_BINARY_DIR}/../sublib.c
+  DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/sublib.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_BINARY_DIR}/../sublib.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/sublibdep.txt" -DDEPFILE=sublib.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+  )
+add_library(sublib STATIC "${CMAKE_BINARY_DIR}/../sublib.c")
diff --git a/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake b/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake
new file mode 100644 (file)
index 0000000..f7d0f13
--- /dev/null
@@ -0,0 +1,6 @@
+file(READ "${INFILE}" INCONTENT)
+file(WRITE "${OUTFILE}" "${INCONTENT}")
+
+string(REPLACE [[ ]] [[\ ]] OUTFILE "${OUTFILE}")
+string(REPLACE [[ ]] [[\ ]] INFILE "${INFILE}")
+file(WRITE "${DEPFILE}" "${OUTFILE}: ${INFILE}\n")
diff --git a/Tests/RunCMake/BuildDepends/MakeDependencies.cmake b/Tests/RunCMake/BuildDepends/MakeDependencies.cmake
new file mode 100644 (file)
index 0000000..33e8c7e
--- /dev/null
@@ -0,0 +1,13 @@
+enable_language(C)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+set(check_pairs
+  \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+  \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.h\"
+  )
+set(check_exes
+  \"$<TARGET_FILE:main>\"
+  )
+")
diff --git a/Tests/RunCMake/BuildDepends/MakeDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/MakeDependencies.step1.cmake
new file mode 100644 (file)
index 0000000..c74f033
--- /dev/null
@@ -0,0 +1,18 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/main.c")
+foreach(i RANGE 1 20000)
+  file(WRITE "${RunCMake_TEST_BINARY_DIR}/temp_header_file_${i}.h"
+    "#define HEADER_${i} ${i}\n"
+    )
+  file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
+    "#include \"temp_header_file_${i}.h\"\n"
+    )
+endforeach()
+file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
+  "#include \"main.h\"\n"
+  )
+file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
+  "int main(void) { return COUNT; }\n"
+  )
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h"
+  "#define COUNT 1\n"
+  )
diff --git a/Tests/RunCMake/BuildDepends/MakeDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/MakeDependencies.step2.cmake
new file mode 100644 (file)
index 0000000..c826d3c
--- /dev/null
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h"
+  "#define COUNT 2\n"
+  )
index 6c6d548..6232634 100644 (file)
@@ -30,8 +30,17 @@ function(run_BuildDepends CASE)
   include(${RunCMake_SOURCE_DIR}/${CASE}.step2.cmake OPTIONAL)
   set(check_step 2)
   run_cmake_command(${CASE}-build2 ${CMAKE_COMMAND} --build . --config Debug)
+  if(run_BuildDepends_skip_step_3)
+    return()
+  endif()
+  execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay}) # handle 1s resolution
+  include(${RunCMake_SOURCE_DIR}/${CASE}.step3.cmake OPTIONAL)
+  set(check_step 3)
+  run_cmake_command(${CASE}-build3 ${CMAKE_COMMAND} --build . --config Debug)
 endfunction()
 
+set(run_BuildDepends_skip_step_3 1)
+
 run_BuildDepends(C-Exe)
 if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
   if(RunCMake_GENERATOR MATCHES "Visual Studio 10" OR
@@ -130,3 +139,28 @@ if(CMake_TEST_BuildDepends_GNU_AS)
   set(ENV{ASM} "${CMake_TEST_BuildDepends_GNU_AS}")
   run_BuildDepends(GNU-AS)
 endif()
+
+if ((RunCMake_GENERATOR STREQUAL "Unix Makefiles"
+      AND (CMAKE_C_COMPILER_ID STREQUAL "GNU"
+        OR CMAKE_C_COMPILER_ID STREQUAL "Clang"
+        OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
+    OR (RunCMake_GENERATOR STREQUAL "NMake Makefiles"
+      AND MSVC_VERSION GREATER 1300
+      AND CMAKE_C_COMPILER_ID STREQUAL "MSVC"))
+  run_BuildDepends(CompilerDependencies)
+  run_BuildDepends(CustomCommandDependencies)
+endif()
+
+if (RunCMake_GENERATOR MATCHES "Makefiles")
+  run_cmake(CustomCommandDependencies-BadArgs)
+endif()
+
+if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+  unset(run_BuildDepends_skip_step_3)
+  run_BuildDepends(CustomCommandDepfile)
+  set(run_BuildDepends_skip_step_3 1)
+endif()
+
+if(RunCMake_GENERATOR MATCHES "Make")
+  run_BuildDepends(MakeDependencies)
+endif()
diff --git a/Tests/RunCMake/BuildDepends/WriteDepfile.cmake b/Tests/RunCMake/BuildDepends/WriteDepfile.cmake
new file mode 100644 (file)
index 0000000..c958cde
--- /dev/null
@@ -0,0 +1,8 @@
+file(WRITE "${OUTFILE}" [[int main(void)
+{
+  return 0;
+}
+]])
+string(REPLACE [[ ]] [[\ ]] OUTFILE "${OUTFILE}")
+string(REPLACE [[ ]] [[\ ]] INFILE "${INFILE}")
+file(WRITE "${DEPFILE}" "${OUTFILE}: ${INFILE}\n")
index 415eecc..6988447 100644 (file)
@@ -1,3 +1,5 @@
+set(ENV{CUDAARCHS})
+
 cmake_policy(SET CMP0104 OLD)
 include(CMP0104-Common.cmake)
 
index 7ad774e..8a4d7e4 100644 (file)
@@ -1,4 +1,4 @@
-CMake Error at .*/Modules/Documentation.cmake:15 \(message\):
+CMake Error at .*/Modules/Documentation.cmake:[0-9]+ \(message\):
   Documentation.cmake is VTK-specific code and should not be used in non-VTK
   projects.  This logic in this module is best shipped with the project using
   it rather than with CMake.  This is now an error according to policy
index d0d48d0..af6bb05 100644 (file)
@@ -8,7 +8,7 @@ Call Stack \(most recent call first\):
   CMakeLists.txt:7 \(include\)
 This warning is for project developers.  Use -Wno-dev to suppress it.
 
-CMake Warning \(dev\) at .*/Modules/Documentation.cmake:27 \(message\):
+CMake Warning \(dev\) at .*/Modules/Documentation.cmake:[0-9]+ \(message\):
   Policy CMP0106 is not set: The Documentation module is removed.  Run "cmake
   --help-policy CMP0106" for policy details.  Use the cmake_policy command to
   set the policy and suppress this warning.
@@ -22,7 +22,7 @@ Call Stack \(most recent call first\):
   CMakeLists.txt:7 \(include\)
 This warning is for project developers.  Use -Wno-dev to suppress it.
 
-CMake Warning \(dev\) at .*/Modules/Documentation.cmake:27 \(message\):
+CMake Warning \(dev\) at .*/Modules/Documentation.cmake:[0-9]+ \(message\):
   Policy CMP0106 is not set: The Documentation module is removed.  Run "cmake
   --help-policy CMP0106" for policy details.  Use the cmake_policy command to
   set the policy and suppress this warning.
diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt
new file mode 100644 (file)
index 0000000..b63c53d
--- /dev/null
@@ -0,0 +1,17 @@
+^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Cannot find source file:
+
+    main
+Call Stack \(most recent call first\):
+  CMP0115-NEW\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+  CMP0115-NEW\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake b/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake
new file mode 100644 (file)
index 0000000..ddf5071
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0115.cmake)
diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt
new file mode 100644 (file)
index 0000000..8b90311
--- /dev/null
@@ -0,0 +1,22 @@
+^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Cannot find source file:
+
+    noexist
+
+  Tried extensions [^
+]*
+  [^
+]*
+Call Stack \(most recent call first\):
+  CMP0115-OLD\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+  CMP0115-OLD\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake b/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake
new file mode 100644 (file)
index 0000000..ddf5071
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0115.cmake)
diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt
new file mode 100644 (file)
index 0000000..7b100b6
--- /dev/null
@@ -0,0 +1,36 @@
+^CMake Warning \(dev\) at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Policy CMP0115 is not set: Source file extensions must be explicit\.  Run
+  "cmake --help-policy CMP0115" for policy details\.  Use the cmake_policy
+  command to set the policy and suppress this warning\.
+
+  File:
+
+    [^
+]*/Tests/RunCMake/CMP0115/main\.c
+Call Stack \(most recent call first\):
+  CMP0115-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  Cannot find source file:
+
+    noexist
+
+  Tried extensions [^
+]*
+  [^
+]*
+Call Stack \(most recent call first\):
+  CMP0115-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+  No SOURCES given to target: exe
+Call Stack \(most recent call first\):
+  CMP0115-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake b/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake
new file mode 100644 (file)
index 0000000..ddf5071
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0115.cmake)
diff --git a/Tests/RunCMake/CMP0115/CMP0115.cmake b/Tests/RunCMake/CMP0115/CMP0115.cmake
new file mode 100644 (file)
index 0000000..be910a4
--- /dev/null
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_executable(exe main noexist)
diff --git a/Tests/RunCMake/CMP0115/CMakeLists.txt b/Tests/RunCMake/CMP0115/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b646c4a
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.18)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0115/RunCMakeTest.cmake b/Tests/RunCMake/CMP0115/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..58182ac
--- /dev/null
@@ -0,0 +1,12 @@
+include(RunCMake)
+
+function(run_cmp0115 status)
+  if(NOT status STREQUAL "WARN")
+    set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0115=${status})
+  endif()
+  run_cmake(CMP0115-${status})
+endfunction()
+
+run_cmp0115(OLD)
+run_cmp0115(WARN)
+run_cmp0115(NEW)
similarity index 51%
rename from Tests/Server/buildsystem1/subdir/empty.cpp
rename to Tests/RunCMake/CMP0115/main.c
index 7f39d71..8488f4e 100644 (file)
@@ -1,5 +1,4 @@
-
-int foo()
+int main(void)
 {
   return 0;
 }
diff --git a/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt
new file mode 100644 (file)
index 0000000..10e83a9
--- /dev/null
@@ -0,0 +1,17 @@
+^CMake Warning \(dev\) at CMP0116-Mixed\.cmake:1 \(add_custom_command\):
+  Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+  add_custom_command\(\)\.  Run "cmake --help-policy CMP0116" 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\.(
+
+CMake Warning \(dev\) at CMP0116-Mixed\.cmake:1 \(add_custom_command\):
+  Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+  add_custom_command\(\)\.  Run "cmake --help-policy CMP0116" 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/CMP0116/CMP0116-Mixed.cmake b/Tests/RunCMake/CMP0116/CMP0116-Mixed.cmake
new file mode 100644 (file)
index 0000000..6cbbc09
--- /dev/null
@@ -0,0 +1,18 @@
+add_custom_command(
+  OUTPUT warn.txt
+  COMMAND ${CMAKE_COMMAND} -E touch warn.txt
+  DEPFILE warn.d
+  )
+cmake_policy(SET CMP0116 OLD)
+add_custom_command(
+  OUTPUT old.txt
+  COMMAND ${CMAKE_COMMAND} -E touch old.txt
+  DEPFILE old.d
+  )
+cmake_policy(SET CMP0116 NEW)
+add_custom_command(
+  OUTPUT new.txt
+  COMMAND ${CMAKE_COMMAND} -E touch new.txt
+  DEPFILE new.d
+  )
+add_custom_target(cc ALL DEPENDS warn.txt old.txt new.txt)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake
new file mode 100644 (file)
index 0000000..f92fac6
--- /dev/null
@@ -0,0 +1,3 @@
+set(depdir)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake
new file mode 100644 (file)
index 0000000..f92fac6
--- /dev/null
@@ -0,0 +1,3 @@
+set(depdir)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake
new file mode 100644 (file)
index 0000000..665f485
--- /dev/null
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake
new file mode 100644 (file)
index 0000000..665f485
--- /dev/null
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt
new file mode 100644 (file)
index 0000000..843ff1c
--- /dev/null
@@ -0,0 +1,7 @@
+^(CMake Warning \(dev\) at Subdirectory/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+  add_custom_command\(\)\.  Run "cmake --help-policy CMP0116" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
+*)+$
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake
new file mode 100644 (file)
index 0000000..665f485
--- /dev/null
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt
new file mode 100644 (file)
index 0000000..e29af91
--- /dev/null
@@ -0,0 +1,16 @@
+^(CMake Warning \(dev\) at Common\.cmake:[0-9]+ \(add_custom_command\):
+  Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+  add_custom_command\(\)\.  Run "cmake --help-policy CMP0116" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+Call Stack \(most recent call first\):
+  CMP0116-WARN-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+(CMake Warning \(dev\) at Subdirectory/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
+  add_custom_command\(\)\.  Run "cmake --help-policy CMP0116" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
+*)+$
diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake
new file mode 100644 (file)
index 0000000..665f485
--- /dev/null
@@ -0,0 +1,3 @@
+set(depdir Subdirectory/)
+
+include(Common.cmake)
diff --git a/Tests/RunCMake/CMP0116/CMakeLists.txt b/Tests/RunCMake/CMP0116/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b646c4a
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.18)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0116/Common.cmake b/Tests/RunCMake/CMP0116/Common.cmake
new file mode 100644 (file)
index 0000000..472b162
--- /dev/null
@@ -0,0 +1,8 @@
+add_custom_command(
+  OUTPUT top.txt
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=top.txt -DINFILE=topdep.txt -DDEPFILE=top.txt.d -DSTAMPFILE=topstamp.txt -DDEPDIR= -P ${CMAKE_SOURCE_DIR}/WriteDepfile.cmake
+  DEPFILE top.txt.d
+  )
+add_custom_target(top ALL DEPENDS top.txt)
+
+add_subdirectory(Subdirectory)
diff --git a/Tests/RunCMake/CMP0116/RunCMakeTest.cmake b/Tests/RunCMake/CMP0116/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..ce3e86a
--- /dev/null
@@ -0,0 +1,52 @@
+include(RunCMake)
+
+function(run_cmp0116 status warn)
+  if(warn)
+    set(name CMP0116-${status}-WARN)
+  else()
+    set(name CMP0116-${status}-NOWARN)
+  endif()
+  set(RunCMake_TEST_OPTIONS
+    -DCMAKE_POLICY_WARNING_CMP0116:BOOL=${warn}
+    )
+  if(NOT status STREQUAL "WARN")
+    list(APPEND RunCMake_TEST_OPTIONS
+      -DCMAKE_POLICY_DEFAULT_CMP0116:STRING=${status}
+      )
+  endif()
+
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
+  run_cmake(${name})
+  unset(RunCMake_TEST_OPTIONS)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake-check-file check.cmake)
+
+  file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topdep.txt")
+  file(TOUCH "${RunCMake_TEST_BINARY_DIR}/Subdirectory/subdep.txt")
+  set(cmp0116_step 1)
+  run_cmake_command(${name}-build1 ${CMAKE_COMMAND} --build . --config Debug)
+  file(REMOVE "${RunCMake_TEST_BINARY_DIR}/topstamp.txt")
+  file(REMOVE "${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt")
+  execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.25)
+
+  file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topdep.txt")
+  file(TOUCH "${RunCMake_TEST_BINARY_DIR}/Subdirectory/subdep.txt")
+  set(cmp0116_step 2)
+  run_cmake_command(${name}-build2 ${CMAKE_COMMAND} --build . --config Debug)
+  file(REMOVE "${RunCMake_TEST_BINARY_DIR}/topstamp.txt")
+  file(REMOVE "${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt")
+  execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.25)
+
+  set(cmp0116_step 3)
+  run_cmake_command(${name}-build3 ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+
+run_cmp0116(WARN OFF)
+run_cmp0116(OLD OFF)
+run_cmp0116(NEW OFF)
+run_cmp0116(WARN ON)
+run_cmp0116(OLD ON)
+run_cmp0116(NEW ON)
+
+set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_WARNING_CMP0116:BOOL=TRUE)
+run_cmake(CMP0116-Mixed)
diff --git a/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt b/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f0f60b2
--- /dev/null
@@ -0,0 +1,6 @@
+add_custom_command(
+  OUTPUT sub.txt
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=sub.txt -DINFILE=subdep.txt -DDEPFILE=sub.txt.d -DSTAMPFILE=substamp.txt -DDEPDIR=${depdir} -P ${CMAKE_SOURCE_DIR}/WriteDepfile.cmake
+  DEPFILE ${depdir}sub.txt.d
+  )
+add_custom_target(sub ALL DEPENDS sub.txt)
diff --git a/Tests/RunCMake/CMP0116/WriteDepfile.cmake b/Tests/RunCMake/CMP0116/WriteDepfile.cmake
new file mode 100644 (file)
index 0000000..1a74d2a
--- /dev/null
@@ -0,0 +1,3 @@
+file(TOUCH "${OUTFILE}")
+file(TOUCH "${STAMPFILE}")
+file(WRITE "${DEPFILE}" "${DEPDIR}${OUTFILE}: ${DEPDIR}${INFILE}\n")
diff --git a/Tests/RunCMake/CMP0116/check.cmake b/Tests/RunCMake/CMP0116/check.cmake
new file mode 100644 (file)
index 0000000..1b16748
--- /dev/null
@@ -0,0 +1,18 @@
+function(check_exists file)
+  if(NOT EXISTS "${file}")
+    string(APPEND RunCMake_TEST_FAILED "${file} does not exist\n")
+  endif()
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+function(check_not_exists file)
+  if(EXISTS "${file}")
+    string(APPEND RunCMake_TEST_FAILED "${file} exists\n")
+  endif()
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+if(cmp0116_step EQUAL 3)
+  check_not_exists("${RunCMake_TEST_BINARY_DIR}/topstamp.txt")
+  check_not_exists("${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt")
+endif()
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Helper.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Helper.cmake
new file mode 100644 (file)
index 0000000..b237b7f
--- /dev/null
@@ -0,0 +1,14 @@
+macro(get_and_print_GENERATED_property filename)
+  get_property(prop SOURCE      "${CMAKE_CURRENT_BINARY_DIR}/${filename}" PROPERTY GENERATED)
+  message(NOTICE "${filename}: # 1a # GENERATED = `${prop}`")
+  get_source_file_property(prop "${CMAKE_CURRENT_BINARY_DIR}/${filename}" GENERATED)
+  message(NOTICE "${filename}: # 1b # GENERATED = `${prop}`")
+  get_property(prop SOURCE      "${filename}"                             PROPERTY GENERATED)
+  message(NOTICE "${filename}: # 2a # GENERATED = `${prop}`")
+  get_source_file_property(prop "${filename}"                             GENERATED)
+  message(NOTICE "${filename}: # 2b # GENERATED = `${prop}`")
+  get_property(prop SOURCE      "${CMAKE_CURRENT_SOURCE_DIR}/${filename}" PROPERTY GENERATED)
+  message(NOTICE "${filename}: # 3a # GENERATED = `${prop}`")
+  get_source_file_property(prop "${CMAKE_CURRENT_SOURCE_DIR}/${filename}" GENERATED)
+  message(NOTICE "${filename}: # 3b # GENERATED = `${prop}`")
+endmacro()
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test1.cmake
new file mode 100644 (file)
index 0000000..2b66515
--- /dev/null
@@ -0,0 +1,9 @@
+add_custom_target(custom)
+target_sources(custom PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+)
+
+get_property(prop SOURCE
+  "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+  PROPERTY GENERATED)
+message(NOTICE "prop: `${prop}`")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test10.cmake
new file mode 100644 (file)
index 0000000..d060207
--- /dev/null
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test10)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test11.cmake
new file mode 100644 (file)
index 0000000..00b204e
--- /dev/null
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test11)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test12.cmake
new file mode 100644 (file)
index 0000000..1182d17
--- /dev/null
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(TARGET custom0 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(TARGET custom1 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(TARGET custom2 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(TARGET custom3 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test12)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test13.cmake
new file mode 100644 (file)
index 0000000..12f4ac1
--- /dev/null
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_command(TARGET custom0 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_command(TARGET custom1 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_command(TARGET custom2 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_command(TARGET custom3 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test13)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test14.cmake
new file mode 100644 (file)
index 0000000..30e3edc
--- /dev/null
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_target(custom0_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_target(custom1_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test14)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test15.cmake
new file mode 100644 (file)
index 0000000..fb05248
--- /dev/null
@@ -0,0 +1,65 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+# The sources of custom0 will not be modified by set_property!
+add_custom_target(custom0)
+target_sources(custom0 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+# The sources of custom[1-6] will (tried to) be modified by set_property!
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+add_custom_target(custom0_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source0.txt"
+)
+add_custom_target(custom1_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+
+add_subdirectory(subdir-Common-Test15)
+
+get_and_print_GENERATED_property("Generated_source0.txt")
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test2.cmake
new file mode 100644 (file)
index 0000000..1180b6b
--- /dev/null
@@ -0,0 +1,12 @@
+add_custom_target(custom)
+target_sources(custom PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+)
+
+set_property(SOURCE
+  "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+  PROPERTY GENERATED "1")
+get_property(prop SOURCE
+  "${CMAKE_CURRENT_BINARY_DIR}/GeneratedMain.txt"
+  PROPERTY GENERATED)
+message(NOTICE "prop: `${prop}`")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test3.cmake
new file mode 100644 (file)
index 0000000..27516b7
--- /dev/null
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "Generated_with_relative_path1.txt"
+  "Generated_with_relative_path2.txt"
+  "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test3b.cmake
new file mode 100644 (file)
index 0000000..3e03a1f
--- /dev/null
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+  PROPERTY GENERATED "1")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "Generated_with_relative_path1.txt"
+  "Generated_with_relative_path2.txt"
+  "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test4.cmake
new file mode 100644 (file)
index 0000000..953e26a
--- /dev/null
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "Generated_with_relative_path1.txt"
+  "Generated_with_relative_path2.txt"
+  "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test4b.cmake
new file mode 100644 (file)
index 0000000..025caa8
--- /dev/null
@@ -0,0 +1,66 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "Generated_with_full_path2.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_path3.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_relative_path1.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_relative_path3.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "Generated_with_full_source_path2.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+  PROPERTY GENERATED "0")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "Generated_with_relative_path1.txt"
+  "Generated_with_relative_path2.txt"
+  "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test5.cmake
new file mode 100644 (file)
index 0000000..5349bff
--- /dev/null
@@ -0,0 +1,78 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "Generated_with_relative_path1.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "Generated_with_relative_path2.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "Generated_with_relative_path3.txt"
+)
+add_custom_target(custom7)
+target_sources(custom7 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path1.txt"
+)
+add_custom_target(custom8)
+target_sources(custom8 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+)
+add_custom_target(custom9)
+target_sources(custom9 PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path3.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path1.txt"
+  PROPERTY GENERATED "tRue")
+get_and_print_GENERATED_property("Generated_with_full_path1.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path2.txt"
+  PROPERTY GENERATED "SomeVar-NOTFOUND")
+get_and_print_GENERATED_property("Generated_with_full_path2.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_path3.txt"
+  PROPERTY GENERATED "Junk-value")
+get_and_print_GENERATED_property("Generated_with_full_path3.txt")
+
+
+set_property(SOURCE "Generated_with_relative_path1.txt"
+  PROPERTY GENERATED "tRue")
+get_and_print_GENERATED_property("Generated_with_relative_path1.txt")
+
+set_property(SOURCE "Generated_with_relative_path2.txt"
+  PROPERTY GENERATED "SomeVar-NOTFOUND")
+get_and_print_GENERATED_property("Generated_with_relative_path2.txt")
+
+set_property(SOURCE "Generated_with_relative_path3.txt"
+  PROPERTY GENERATED "Junk-value")
+get_and_print_GENERATED_property("Generated_with_relative_path3.txt")
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_with_full_source_path1.txt"
+  PROPERTY GENERATED "tRue")
+get_and_print_GENERATED_property("Generated_with_full_source_path1.txt")
+
+set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Generated_with_full_source_path2.txt"
+  PROPERTY GENERATED "SomeVar-NOTFOUND")
+get_and_print_GENERATED_property("Generated_with_full_source_path2.txt")
+
+set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/"Generated_with_full_source_path3.txt"
+  PROPERTY GENERATED "Junk-value")
+get_and_print_GENERATED_property("Generated_with_full_source_path3.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test6.cmake
new file mode 100644 (file)
index 0000000..a6f28aa
--- /dev/null
@@ -0,0 +1,44 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  PROPERTY GENERATED "1")
+
+add_subdirectory(subdir-Common-Test6)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test7.cmake
new file mode 100644 (file)
index 0000000..eed49b8
--- /dev/null
@@ -0,0 +1,44 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  PROPERTY GENERATED "1")
+
+add_subdirectory(subdir-Common-Test7)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test8.cmake
new file mode 100644 (file)
index 0000000..5cc6e99
--- /dev/null
@@ -0,0 +1,50 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+
+add_subdirectory(subdir-Common-Test8)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-Common-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-Common-Test9.cmake
new file mode 100644 (file)
index 0000000..b7d36ef
--- /dev/null
@@ -0,0 +1,50 @@
+include(${CMAKE_CURRENT_LIST_DIR}/CMP0118-Common-Helper.cmake)
+
+
+add_custom_target(custom1)
+target_sources(custom1 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+)
+add_custom_target(custom2)
+target_sources(custom2 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+)
+add_custom_target(custom3)
+target_sources(custom3 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+)
+add_custom_target(custom4)
+target_sources(custom4 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+)
+add_custom_target(custom5)
+target_sources(custom5 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+)
+add_custom_target(custom6)
+target_sources(custom6 PRIVATE
+  "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+)
+
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source1.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source2.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source3.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+
+add_subdirectory(subdir-Common-Test9)
+
+get_and_print_GENERATED_property("Generated_source1.txt")
+get_and_print_GENERATED_property("Generated_source2.txt")
+get_and_print_GENERATED_property("Generated_source3.txt")
+get_and_print_GENERATED_property("Generated_source4.txt")
+get_and_print_GENERATED_property("Generated_source5.txt")
+get_and_print_GENERATED_property("Generated_source6.txt")
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-stderr.txt
new file mode 100644 (file)
index 0000000..ec777f7
--- /dev/null
@@ -0,0 +1,10 @@
+^prop: `0`
+CMake Error at CMP0118-Common-Test1\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test1-build/GeneratedMain\.txt
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test1\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test1.cmake
new file mode 100644 (file)
index 0000000..bbbee43
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test1.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10-stderr.txt
new file mode 100644 (file)
index 0000000..2bd1cba
--- /dev/null
@@ -0,0 +1,42 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test10.cmake
new file mode 100644 (file)
index 0000000..15a7178
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test10.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11-stderr.txt
new file mode 100644 (file)
index 0000000..05b2353
--- /dev/null
@@ -0,0 +1,55 @@
+^(CMake Warning \(dev\) at subdir-Common-Test11/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_subdirectory\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test11.cmake
new file mode 100644 (file)
index 0000000..cb87a86
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test11.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12-stderr.txt
new file mode 100644 (file)
index 0000000..e6c429c
--- /dev/null
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test12.cmake
new file mode 100644 (file)
index 0000000..61bf977
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test12.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13-stderr.txt
new file mode 100644 (file)
index 0000000..7802538
--- /dev/null
@@ -0,0 +1,64 @@
+^CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+(CMake Warning \(dev\) at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test13\.cmake:[0-9]+ \(add_subdirectory\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test13\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test13.cmake
new file mode 100644 (file)
index 0000000..569e4c6
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test13.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14-stderr.txt
new file mode 100644 (file)
index 0000000..2bd1cba
--- /dev/null
@@ -0,0 +1,42 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test14.cmake
new file mode 100644 (file)
index 0000000..e7d8d77
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test14.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15-stderr.txt
new file mode 100644 (file)
index 0000000..3166f45
--- /dev/null
@@ -0,0 +1,55 @@
+^(CMake Warning \(dev\) at subdir-Common-Test15/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_subdirectory\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test15.cmake
new file mode 100644 (file)
index 0000000..93513ae
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test15.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2-stderr.txt
new file mode 100644 (file)
index 0000000..403ce5a
--- /dev/null
@@ -0,0 +1 @@
+^prop: `1`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test2.cmake
new file mode 100644 (file)
index 0000000..ee8233d
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test2.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3-stderr.txt
new file mode 100644 (file)
index 0000000..f7d9f6b
--- /dev/null
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3.cmake
new file mode 100644 (file)
index 0000000..b9533fd
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test3.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b-stderr.txt
new file mode 100644 (file)
index 0000000..a876390
--- /dev/null
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test3b.cmake
new file mode 100644 (file)
index 0000000..79631e7
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test3b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4-stderr.txt
new file mode 100644 (file)
index 0000000..b750ae7
--- /dev/null
@@ -0,0 +1,167 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4.cmake
new file mode 100644 (file)
index 0000000..8a7d35a
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test4.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b-stderr.txt
new file mode 100644 (file)
index 0000000..580f04f
--- /dev/null
@@ -0,0 +1,167 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test4b-build/Generated_with_full_path1\.txt|CMP0118-NEW-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test4b.cmake
new file mode 100644 (file)
index 0000000..c03a39d
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test4b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5-stderr.txt
new file mode 100644 (file)
index 0000000..e268a7a
--- /dev/null
@@ -0,0 +1,174 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is set to NEW and the following non-boolean value given for
+  property 'GENERATED' is therefore not allowed:
+
+  Junk-value
+
+  Replace it with a boolean value!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is set to NEW and the following non-boolean value given for
+  property 'GENERATED' is therefore not allowed:
+
+  Junk-value
+
+  Replace it with a boolean value!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is set to NEW and the following non-boolean value given for
+  property 'GENERATED' is therefore not allowed:
+
+  Junk-value
+
+  Replace it with a boolean value!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-NEW-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test5.cmake
new file mode 100644 (file)
index 0000000..691f94a
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test5.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6-stderr.txt
new file mode 100644 (file)
index 0000000..0c84cfe
--- /dev/null
@@ -0,0 +1,36 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test6.cmake
new file mode 100644 (file)
index 0000000..09b87a5
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test6.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-stderr.txt
new file mode 100644 (file)
index 0000000..08eb682
--- /dev/null
@@ -0,0 +1,74 @@
+^(CMake Warning \(dev\) at subdir-Common-Test7/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_subdirectory\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test7-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test7.cmake
new file mode 100644 (file)
index 0000000..ceb8beb
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test7.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8-stderr.txt
new file mode 100644 (file)
index 0000000..f723875
--- /dev/null
@@ -0,0 +1,36 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test8.cmake
new file mode 100644 (file)
index 0000000..6878b94
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test8.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-stderr.txt
new file mode 100644 (file)
index 0000000..b7c496c
--- /dev/null
@@ -0,0 +1,74 @@
+^(CMake Warning \(dev\) at subdir-Common-Test9/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+(CMake Warning \(dev\) at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_subdirectory\):
+  Unsetting the 'GENERATED' property is not allowed under CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-NEW-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-NEW-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-NEW-Test9.cmake
new file mode 100644 (file)
index 0000000..00b05fd
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(CMP0118-Common-Test9.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt
new file mode 100644 (file)
index 0000000..58144c8
--- /dev/null
@@ -0,0 +1,10 @@
+^prop: `0`
+CMake Error at CMP0118-Common-Test1\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-build/GeneratedMain\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test1\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1.cmake
new file mode 100644 (file)
index 0000000..c18dd25
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test1.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt
new file mode 100644 (file)
index 0000000..1f1bc90
--- /dev/null
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test10\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test10\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10.cmake
new file mode 100644 (file)
index 0000000..b96973f
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test10.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt
new file mode 100644 (file)
index 0000000..5c15f12
--- /dev/null
@@ -0,0 +1,67 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11.cmake
new file mode 100644 (file)
index 0000000..d6ad7d2
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test11.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt
new file mode 100644 (file)
index 0000000..e6c429c
--- /dev/null
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12.cmake
new file mode 100644 (file)
index 0000000..b87b03a
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test12.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt
new file mode 100644 (file)
index 0000000..75dbf23
--- /dev/null
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13.cmake
new file mode 100644 (file)
index 0000000..17a135b
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test13.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt
new file mode 100644 (file)
index 0000000..12a913a
--- /dev/null
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test14\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test14\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14.cmake
new file mode 100644 (file)
index 0000000..0702291
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test14.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt
new file mode 100644 (file)
index 0000000..62db7ee
--- /dev/null
@@ -0,0 +1,67 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15.cmake
new file mode 100644 (file)
index 0000000..c330d4e
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test15.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt
new file mode 100644 (file)
index 0000000..403ce5a
--- /dev/null
@@ -0,0 +1 @@
+^prop: `1`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2.cmake
new file mode 100644 (file)
index 0000000..3ea8800
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test2.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt
new file mode 100644 (file)
index 0000000..7f86d38
--- /dev/null
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3.cmake
new file mode 100644 (file)
index 0000000..c8f5a0e
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test3.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt
new file mode 100644 (file)
index 0000000..4104fc0
--- /dev/null
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b.cmake
new file mode 100644 (file)
index 0000000..0b046b4
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test3b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt
new file mode 100644 (file)
index 0000000..7a16d0b
--- /dev/null
@@ -0,0 +1,95 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4.cmake
new file mode 100644 (file)
index 0000000..2f77397
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test4.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt
new file mode 100644 (file)
index 0000000..5a5c4ec
--- /dev/null
@@ -0,0 +1,95 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test4b-build/Generated_with_full_path1\.txt|CMP0118-OLD-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b.cmake
new file mode 100644 (file)
index 0000000..ce6726d
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test4b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt
new file mode 100644 (file)
index 0000000..12fa617
--- /dev/null
@@ -0,0 +1,111 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-OLD-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5.cmake
new file mode 100644 (file)
index 0000000..2de6d89
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test5.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt
new file mode 100644 (file)
index 0000000..7199f04
--- /dev/null
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test6\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test6\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6.cmake
new file mode 100644 (file)
index 0000000..b571052
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test6.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt
new file mode 100644 (file)
index 0000000..233fd8b
--- /dev/null
@@ -0,0 +1,77 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7.cmake
new file mode 100644 (file)
index 0000000..551da23
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test7.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt
new file mode 100644 (file)
index 0000000..4aed2ed
--- /dev/null
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test8\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test8\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8.cmake
new file mode 100644 (file)
index 0000000..2d9e3d3
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test8.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-result.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt
new file mode 100644 (file)
index 0000000..cea8c22
--- /dev/null
@@ -0,0 +1,61 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-OLD-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9.cmake
new file mode 100644 (file)
index 0000000..53f73d9
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(CMP0118-Common-Test9.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-stderr.txt
new file mode 100644 (file)
index 0000000..e2a2cf5
--- /dev/null
@@ -0,0 +1,10 @@
+^prop: `0`
+CMake Error at CMP0118-Common-Test1\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test1-build/GeneratedMain\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test1\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test1.cmake
new file mode 100644 (file)
index 0000000..3c82f8e
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test1.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-stderr.txt
new file mode 100644 (file)
index 0000000..bce7681
--- /dev/null
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test10\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test10-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test10\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test10.cmake
new file mode 100644 (file)
index 0000000..c639c40
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test10.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-stderr.txt
new file mode 100644 (file)
index 0000000..00c47e9
--- /dev/null
@@ -0,0 +1,90 @@
+^((CMake Warning \(dev\) at subdir-Common-Test11/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_subdirectory\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test11\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test11-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test11\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test11.cmake
new file mode 100644 (file)
index 0000000..4c9735d
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test11.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12-stderr.txt
new file mode 100644 (file)
index 0000000..e6c429c
--- /dev/null
@@ -0,0 +1,51 @@
+^CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test12.cmake
new file mode 100644 (file)
index 0000000..79fa00a
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test12.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13-stderr.txt
new file mode 100644 (file)
index 0000000..6d59cb4
--- /dev/null
@@ -0,0 +1,74 @@
+^CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+  TARGET 'custom[4-6]' was not created in this directory\.
++
+((CMake Warning \(dev\) at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test13\.cmake:[0-9]+ \(add_subdirectory\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test13\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test13.cmake
new file mode 100644 (file)
index 0000000..27f71c7
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test13.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-stderr.txt
new file mode 100644 (file)
index 0000000..5b7994c
--- /dev/null
@@ -0,0 +1,51 @@
+^Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test14\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test14-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test14\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test14.cmake
new file mode 100644 (file)
index 0000000..056f0ad
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test14.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-stderr.txt
new file mode 100644 (file)
index 0000000..c975c23
--- /dev/null
@@ -0,0 +1,90 @@
+^((CMake Warning \(dev\) at subdir-Common-Test15/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_subdirectory\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source0\.txt: # 1a # GENERATED = `1`
+Generated_source0\.txt: # 1b # GENERATED = `1`
+Generated_source0\.txt: # 2a # GENERATED = `1`
+Generated_source0\.txt: # 2b # GENERATED = `1`
+Generated_source0\.txt: # 3a # GENERATED = `0`
+Generated_source0\.txt: # 3b # GENERATED = `0`
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test15\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test15-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test15\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test15.cmake
new file mode 100644 (file)
index 0000000..acc8bf6
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test15.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2-stderr.txt
new file mode 100644 (file)
index 0000000..403ce5a
--- /dev/null
@@ -0,0 +1 @@
+^prop: `1`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test2.cmake
new file mode 100644 (file)
index 0000000..5a67974
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test2.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3-stderr.txt
new file mode 100644 (file)
index 0000000..142d8a0
--- /dev/null
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3.cmake
new file mode 100644 (file)
index 0000000..7cdfacb
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test3.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b-stderr.txt
new file mode 100644 (file)
index 0000000..d4ef667
--- /dev/null
@@ -0,0 +1,87 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `1`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test3b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test3b-build/Generated_with_full_path3\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test3b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test3b.cmake
new file mode 100644 (file)
index 0000000..6dfc16a
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test3b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4-stderr.txt
new file mode 100644 (file)
index 0000000..ceeb570
--- /dev/null
@@ -0,0 +1,212 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4.cmake
new file mode 100644 (file)
index 0000000..9d432a4
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test4.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b-stderr.txt
new file mode 100644 (file)
index 0000000..f8484d0
--- /dev/null
@@ -0,0 +1,212 @@
+^CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test4b\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test4b\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test4b-build/Generated_with_full_path1\.txt|CMP0118-WARN-Test4b-build/Generated_with_relative_path1\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test4b\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test4b.cmake
new file mode 100644 (file)
index 0000000..2e2c2bd
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test4b.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5-stderr.txt
new file mode 100644 (file)
index 0000000..0556391
--- /dev/null
@@ -0,0 +1,213 @@
+^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Attempt to set property 'GENERATED' with the following non-boolean value
+  \(which will be interpreted as "0"\):
+
+  Junk-value
+
+  That exact value will not be retrievable\.  A value of "0" will be returned
+  instead\.
+
+  This will be an error under policy CMP0118\.
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_relative_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Attempt to set property 'GENERATED' with the following non-boolean value
+  \(which will be interpreted as "0"\):
+
+  Junk-value
+
+  That exact value will not be retrievable\.  A value of "0" will be returned
+  instead\.
+
+  This will be an error under policy CMP0118\.
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_relative_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_relative_path3\.txt: # 3b # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 1a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 1b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2a # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 2b # GENERATED = `1`
+Generated_with_full_source_path1\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path1\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path2\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path2\.txt: # 3b # GENERATED = `0`
+CMake Warning \(dev\) at CMP0118-Common-Test5\.cmake:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Attempt to set property 'GENERATED' with the following non-boolean value
+  \(which will be interpreted as "0"\):
+
+  Junk-value
+
+  That exact value will not be retrievable\.  A value of "0" will be returned
+  instead\.
+
+  This will be an error under policy CMP0118\.
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+Generated_with_full_source_path3\.txt: # 1a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 1b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 2b # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3a # GENERATED = `0`
+Generated_with_full_source_path3\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test5\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/(Generated_with_full_source_path[1-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_relative_path[2-3]\.txt|CMP0118-WARN-Test5-build/Generated_with_full_path[2-3]\.txt)
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test5\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test5.cmake
new file mode 100644 (file)
index 0000000..87e965e
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test5.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-stderr.txt
new file mode 100644 (file)
index 0000000..7d588a2
--- /dev/null
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test6\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test6-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test6\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test6.cmake
new file mode 100644 (file)
index 0000000..6f1edbc
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test6.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-stderr.txt
new file mode 100644 (file)
index 0000000..8421061
--- /dev/null
@@ -0,0 +1,100 @@
+^((CMake Warning \(dev\) at subdir-Common-Test7/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_subdirectory\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `1`
+Generated_source1\.txt: # 1b # GENERATED = `1`
+Generated_source1\.txt: # 2a # GENERATED = `1`
+Generated_source1\.txt: # 2b # GENERATED = `1`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test7\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test7-build/Generated_source[2-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test7\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test7.cmake
new file mode 100644 (file)
index 0000000..86af20d
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test7.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-stderr.txt
new file mode 100644 (file)
index 0000000..e0f17e6
--- /dev/null
@@ -0,0 +1,45 @@
+^Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `1`
+Generated_source2\.txt: # 1b # GENERATED = `1`
+Generated_source2\.txt: # 2a # GENERATED = `1`
+Generated_source2\.txt: # 2b # GENERATED = `1`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `1`
+Generated_source3\.txt: # 1b # GENERATED = `1`
+Generated_source3\.txt: # 2a # GENERATED = `1`
+Generated_source3\.txt: # 2b # GENERATED = `1`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `1`
+Generated_source5\.txt: # 1b # GENERATED = `1`
+Generated_source5\.txt: # 2a # GENERATED = `1`
+Generated_source5\.txt: # 2b # GENERATED = `1`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `1`
+Generated_source6\.txt: # 1b # GENERATED = `1`
+Generated_source6\.txt: # 2a # GENERATED = `1`
+Generated_source6\.txt: # 2b # GENERATED = `1`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test8\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test8-build/Generated_source4\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test8\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test8.cmake
new file mode 100644 (file)
index 0000000..6a0bb4c
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test8.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-result.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-stderr.txt
new file mode 100644 (file)
index 0000000..80f3edf
--- /dev/null
@@ -0,0 +1,84 @@
+^((CMake Warning \(dev\) at subdir-Common-Test9/CMakeLists\.txt:[0-9]+ \(set_property\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+
+(CMake Warning \(dev\) at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_subdirectory\):
+  Policy CMP0118 is not set: The GENERATED source file property is now
+  visible in all directories\.  Run "cmake --help-policy CMP0118" for policy
+  details\.  Use the cmake_policy command to set the policy and suppress this
+  warning\.
+
+  Unsetting property 'GENERATED' will not be allowed under policy CMP0118!
+
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++)+)+
+Generated_source1\.txt: # 1a # GENERATED = `0`
+Generated_source1\.txt: # 1b # GENERATED = `0`
+Generated_source1\.txt: # 2a # GENERATED = `0`
+Generated_source1\.txt: # 2b # GENERATED = `0`
+Generated_source1\.txt: # 3a # GENERATED = `0`
+Generated_source1\.txt: # 3b # GENERATED = `0`
+Generated_source2\.txt: # 1a # GENERATED = `0`
+Generated_source2\.txt: # 1b # GENERATED = `0`
+Generated_source2\.txt: # 2a # GENERATED = `0`
+Generated_source2\.txt: # 2b # GENERATED = `0`
+Generated_source2\.txt: # 3a # GENERATED = `0`
+Generated_source2\.txt: # 3b # GENERATED = `0`
+Generated_source3\.txt: # 1a # GENERATED = `0`
+Generated_source3\.txt: # 1b # GENERATED = `0`
+Generated_source3\.txt: # 2a # GENERATED = `0`
+Generated_source3\.txt: # 2b # GENERATED = `0`
+Generated_source3\.txt: # 3a # GENERATED = `0`
+Generated_source3\.txt: # 3b # GENERATED = `0`
+Generated_source4\.txt: # 1a # GENERATED = `0`
+Generated_source4\.txt: # 1b # GENERATED = `0`
+Generated_source4\.txt: # 2a # GENERATED = `0`
+Generated_source4\.txt: # 2b # GENERATED = `0`
+Generated_source4\.txt: # 3a # GENERATED = `0`
+Generated_source4\.txt: # 3b # GENERATED = `0`
+Generated_source5\.txt: # 1a # GENERATED = `0`
+Generated_source5\.txt: # 1b # GENERATED = `0`
+Generated_source5\.txt: # 2a # GENERATED = `0`
+Generated_source5\.txt: # 2b # GENERATED = `0`
+Generated_source5\.txt: # 3a # GENERATED = `0`
+Generated_source5\.txt: # 3b # GENERATED = `0`
+Generated_source6\.txt: # 1a # GENERATED = `0`
+Generated_source6\.txt: # 1b # GENERATED = `0`
+Generated_source6\.txt: # 2a # GENERATED = `0`
+Generated_source6\.txt: # 2b # GENERATED = `0`
+Generated_source6\.txt: # 3a # GENERATED = `0`
+Generated_source6\.txt: # 3b # GENERATED = `0`
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Error at CMP0118-Common-Test9\.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+[ \t]*.*Tests/RunCMake/CMP0118/CMP0118-WARN-Test9-build/Generated_source[4-6]\.txt
+Call Stack \(most recent call first\):
+  CMP0118-WARN-Test9\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
++
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9.cmake b/Tests/RunCMake/CMP0118/CMP0118-WARN-Test9.cmake
new file mode 100644 (file)
index 0000000..c48c64e
--- /dev/null
@@ -0,0 +1 @@
+include(CMP0118-Common-Test9.cmake)
diff --git a/Tests/RunCMake/CMP0118/CMakeLists.txt b/Tests/RunCMake/CMP0118/CMakeLists.txt
new file mode 100644 (file)
index 0000000..957fe03
--- /dev/null
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.19)
+cmake_policy(SET CMP0115 NEW)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-Common.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-Common.cmake
new file mode 100644 (file)
index 0000000..6012c79
--- /dev/null
@@ -0,0 +1,2 @@
+add_custom_target(top)
+add_subdirectory(GenInSubdir)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-NEW.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-NEW.cmake
new file mode 100644 (file)
index 0000000..373e73d
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 NEW)
+include(GenInSubdir-Common.cmake)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-OLD-result.txt b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt
new file mode 100644 (file)
index 0000000..d3aa546
--- /dev/null
@@ -0,0 +1,8 @@
+^CMake Error at GenInSubdir-Common.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+    [^
+]*/Tests/RunCMake/CMP0118/GenInSubdir-OLD-build/GenInSubdir/sub.txt
+Call Stack \(most recent call first\):
+  GenInSubdir-OLD.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-OLD.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-OLD.cmake
new file mode 100644 (file)
index 0000000..48be27e
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0118 OLD)
+include(GenInSubdir-Common.cmake)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-WARN-result.txt b/Tests/RunCMake/CMP0118/GenInSubdir-WARN-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-WARN-stderr.txt b/Tests/RunCMake/CMP0118/GenInSubdir-WARN-stderr.txt
new file mode 100644 (file)
index 0000000..5eb8a34
--- /dev/null
@@ -0,0 +1,8 @@
+^CMake Error at GenInSubdir-Common.cmake:[0-9]+ \(add_custom_target\):
+  Cannot find source file:
+
+    [^
+]*/Tests/RunCMake/CMP0118/GenInSubdir-WARN-build/GenInSubdir/sub.txt
+Call Stack \(most recent call first\):
+  GenInSubdir-WARN.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-WARN.cmake b/Tests/RunCMake/CMP0118/GenInSubdir-WARN.cmake
new file mode 100644 (file)
index 0000000..8e7e395
--- /dev/null
@@ -0,0 +1,2 @@
+
+include(GenInSubdir-Common.cmake)
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir/CMakeLists.txt b/Tests/RunCMake/CMP0118/GenInSubdir/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3f1ce8d
--- /dev/null
@@ -0,0 +1,9 @@
+add_custom_command(
+  OUTPUT sub.txt
+  COMMAND ${CMAKE_COMMAND} -E touch sub.txt
+  VERBATIM
+  )
+add_custom_target(gen DEPENDS sub.txt)
+
+add_dependencies(top gen)
+target_sources(top PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/sub.txt)
diff --git a/Tests/RunCMake/CMP0118/RunCMakeTest.cmake b/Tests/RunCMake/CMP0118/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..f7f135e
--- /dev/null
@@ -0,0 +1,59 @@
+include(RunCMake)
+
+run_cmake(GenInSubdir-OLD)
+run_cmake(GenInSubdir-WARN)
+run_cmake(GenInSubdir-NEW)
+
+run_cmake(CMP0118-OLD-Test1)
+run_cmake(CMP0118-OLD-Test2)
+run_cmake(CMP0118-OLD-Test3)
+run_cmake(CMP0118-OLD-Test3b)
+run_cmake(CMP0118-OLD-Test4)
+run_cmake(CMP0118-OLD-Test4b)
+run_cmake(CMP0118-OLD-Test5)
+run_cmake(CMP0118-OLD-Test6)
+run_cmake(CMP0118-OLD-Test7)
+run_cmake(CMP0118-OLD-Test8)
+run_cmake(CMP0118-OLD-Test9)
+run_cmake(CMP0118-OLD-Test10)
+run_cmake(CMP0118-OLD-Test11)
+run_cmake(CMP0118-OLD-Test12)
+run_cmake(CMP0118-OLD-Test13)
+run_cmake(CMP0118-OLD-Test14)
+run_cmake(CMP0118-OLD-Test15)
+
+run_cmake(CMP0118-WARN-Test1)
+run_cmake(CMP0118-WARN-Test2)
+run_cmake(CMP0118-WARN-Test3)
+run_cmake(CMP0118-WARN-Test3b)
+run_cmake(CMP0118-WARN-Test4)
+run_cmake(CMP0118-WARN-Test4b)
+run_cmake(CMP0118-WARN-Test5)
+run_cmake(CMP0118-WARN-Test6)
+run_cmake(CMP0118-WARN-Test7)
+run_cmake(CMP0118-WARN-Test8)
+run_cmake(CMP0118-WARN-Test9)
+run_cmake(CMP0118-WARN-Test10)
+run_cmake(CMP0118-WARN-Test11)
+run_cmake(CMP0118-WARN-Test12)
+run_cmake(CMP0118-WARN-Test13)
+run_cmake(CMP0118-WARN-Test14)
+run_cmake(CMP0118-WARN-Test15)
+
+run_cmake(CMP0118-NEW-Test1)
+run_cmake(CMP0118-NEW-Test2)
+run_cmake(CMP0118-NEW-Test3)
+run_cmake(CMP0118-NEW-Test3b)
+run_cmake(CMP0118-NEW-Test4)
+run_cmake(CMP0118-NEW-Test4b)
+run_cmake(CMP0118-NEW-Test5)
+run_cmake(CMP0118-NEW-Test6)
+run_cmake(CMP0118-NEW-Test7)
+run_cmake(CMP0118-NEW-Test8)
+run_cmake(CMP0118-NEW-Test9)
+run_cmake(CMP0118-NEW-Test10)
+run_cmake(CMP0118-NEW-Test11)
+run_cmake(CMP0118-NEW-Test12)
+run_cmake(CMP0118-NEW-Test13)
+run_cmake(CMP0118-NEW-Test14)
+run_cmake(CMP0118-NEW-Test15)
diff --git a/Tests/RunCMake/CMP0118/source.cpp.in b/Tests/RunCMake/CMP0118/source.cpp.in
new file mode 100644 (file)
index 0000000..678cd7a
--- /dev/null
@@ -0,0 +1,5 @@
+int func();
+int main()
+{
+  return func();
+}
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test10/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test10/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6bc99cb
--- /dev/null
@@ -0,0 +1,33 @@
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test11/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test11/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fbd7e6f
--- /dev/null
@@ -0,0 +1,33 @@
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test12/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test12/CMakeLists.txt
new file mode 100644 (file)
index 0000000..916725c
--- /dev/null
@@ -0,0 +1,33 @@
+add_custom_command(TARGET custom4 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(TARGET custom5 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(TARGET custom6 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test13/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test13/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f2929aa
--- /dev/null
@@ -0,0 +1,33 @@
+add_custom_command(TARGET custom4 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_command(TARGET custom5 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_command(TARGET custom6 PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test14/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test14/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7397db9
--- /dev/null
@@ -0,0 +1,33 @@
+add_custom_target(custom4_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_target(custom5_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_target(custom6_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test15/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test15/CMakeLists.txt
new file mode 100644 (file)
index 0000000..314e427
--- /dev/null
@@ -0,0 +1,33 @@
+add_custom_target(custom4_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+)
+add_custom_target(custom5_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+)
+add_custom_target(custom6_source_generator ALL
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Source.txt.in"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test6/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test6/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fa307d1
--- /dev/null
@@ -0,0 +1,16 @@
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test7/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test7/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6362f78
--- /dev/null
@@ -0,0 +1,16 @@
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test8/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test8/CMakeLists.txt
new file mode 100644 (file)
index 0000000..55debd1
--- /dev/null
@@ -0,0 +1,30 @@
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "1")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "1")
diff --git a/Tests/RunCMake/CMP0118/subdir-Common-Test9/CMakeLists.txt b/Tests/RunCMake/CMP0118/subdir-Common-Test9/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cdb8884
--- /dev/null
@@ -0,0 +1,30 @@
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source4.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source5.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Generated_source6.txt"
+  CONTENT "int func();\nint main(){ return func(); }"
+)
+
+
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source1.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source2.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source3.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source4.txt"
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source5.txt"
+  DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
+  PROPERTY GENERATED "0")
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/../Generated_source6.txt"
+  TARGET_DIRECTORY custom1
+  PROPERTY GENERATED "0")
diff --git a/Tests/RunCMake/CMP0119/AltExtC.zzz b/Tests/RunCMake/CMP0119/AltExtC.zzz
new file mode 100644 (file)
index 0000000..5b240eb
--- /dev/null
@@ -0,0 +1,4 @@
+int main(void) {
+  int class = 0;
+  return class;
+}
diff --git a/Tests/RunCMake/CMP0119/AltExtCXX.zzz b/Tests/RunCMake/CMP0119/AltExtCXX.zzz
new file mode 100644 (file)
index 0000000..3c521ed
--- /dev/null
@@ -0,0 +1,3 @@
+int main() {
+  return static_cast<int>(0);
+}
diff --git a/Tests/RunCMake/CMP0119/CMP0119-Common.cmake b/Tests/RunCMake/CMP0119/CMP0119-Common.cmake
new file mode 100644 (file)
index 0000000..f45895b
--- /dev/null
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(AltExtC AltExtC.zzz)
+set_property(SOURCE AltExtC.zzz PROPERTY LANGUAGE C)
diff --git a/Tests/RunCMake/CMP0119/CMP0119-NEW.cmake b/Tests/RunCMake/CMP0119/CMP0119-NEW.cmake
new file mode 100644 (file)
index 0000000..df0ed48
--- /dev/null
@@ -0,0 +1,6 @@
+cmake_policy(SET CMP0119 NEW)
+include(CMP0119-Common.cmake)
+
+enable_language(CXX)
+add_executable(AltExtCXX AltExtCXX.zzz)
+set_property(SOURCE AltExtCXX.zzz PROPERTY LANGUAGE CXX)
diff --git a/Tests/RunCMake/CMP0119/CMP0119-OLD-build-result.txt b/Tests/RunCMake/CMP0119/CMP0119-OLD-build-result.txt
new file mode 100644 (file)
index 0000000..d197c91
--- /dev/null
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CMP0119/CMP0119-OLD-build-stderr.txt b/Tests/RunCMake/CMP0119/CMP0119-OLD-build-stderr.txt
new file mode 100644 (file)
index 0000000..8d98f9d
--- /dev/null
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CMP0119/CMP0119-OLD.cmake b/Tests/RunCMake/CMP0119/CMP0119-OLD.cmake
new file mode 100644 (file)
index 0000000..9eaa200
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0119 OLD)
+include(CMP0119-Common.cmake)
diff --git a/Tests/RunCMake/CMP0119/CMP0119-WARN-build-result.txt b/Tests/RunCMake/CMP0119/CMP0119-WARN-build-result.txt
new file mode 100644 (file)
index 0000000..d197c91
--- /dev/null
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/CMP0119/CMP0119-WARN-build-stderr.txt b/Tests/RunCMake/CMP0119/CMP0119-WARN-build-stderr.txt
new file mode 100644 (file)
index 0000000..8d98f9d
--- /dev/null
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CMP0119/CMP0119-WARN.cmake b/Tests/RunCMake/CMP0119/CMP0119-WARN.cmake
new file mode 100644 (file)
index 0000000..00281e9
--- /dev/null
@@ -0,0 +1,2 @@
+
+include(CMP0119-Common.cmake)
diff --git a/Tests/RunCMake/CMP0119/CMakeLists.txt b/Tests/RunCMake/CMP0119/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ab1a20c
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0119/RunCMakeTest.cmake b/Tests/RunCMake/CMP0119/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..e547ef5
--- /dev/null
@@ -0,0 +1,17 @@
+include(RunCMake)
+
+function(run_CMP0119 status)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0119-${status}-build)
+  run_cmake(CMP0119-${status})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(CMP0119-${status}-build "${CMAKE_COMMAND}" --build . --config Debug)
+endfunction()
+
+if(NOT RunCMake_GENERATOR MATCHES "Visual Studio|Xcode" AND
+    NOT CMAKE_C_COMPILER_ID MATCHES "(Borland|Embarcadero|Watcom)")
+  run_CMP0119(WARN)
+  run_CMP0119(OLD)
+endif()
+if((CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang|MSVC|Borland|Embarcadero|Intel|TI)"))
+  run_CMP0119(NEW)
+endif()
index 8dcfe84..91fe6ca 100644 (file)
@@ -125,6 +125,12 @@ if(CMake_TEST_CUDA)
 endif()
 add_RunCMake_test(CMP0106)
 add_RunCMake_test(CMP0111)
+add_RunCMake_test(CMP0115)
+if(CMAKE_GENERATOR MATCHES "Ninja")
+  add_RunCMake_test(CMP0116)
+endif()
+add_RunCMake_test(CMP0118)
+add_RunCMake_test(CMP0119 -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
 
 # The test for Policy 65 requires the use of the
 # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
@@ -175,6 +181,10 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE)
     )
 endif()
 
+add_RunCMake_test(ABI -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+set_property(TEST RunCMake.ABI APPEND
+  PROPERTY LABELS "CUDA")
+
 add_RunCMake_test(AndroidTestUtilities)
 if(CMake_TEST_APPLE_SILICON)
   add_RunCMake_test(AppleSilicon)
@@ -187,6 +197,9 @@ if(CMake_TEST_Qt5 AND Qt5Widgets_FOUND)
   set(autogen_with_qt5 TRUE)
 endif ()
 add_RunCMake_test(Autogen -Dwith_qt5=${autogen_with_qt5})
+
+add_RunCMake_test(ArtifactOutputDirs)
+
 if(NOT DEFINED CMake_TEST_BuildDepends_GNU_AS
     AND CMAKE_C_COMPILER_ID STREQUAL "GNU"
     AND CMAKE_GENERATOR MATCHES "^Ninja"
@@ -198,14 +211,16 @@ if(NOT DEFINED CMake_TEST_BuildDepends_GNU_AS
     set(CMake_TEST_BuildDepends_GNU_AS "${_gnu_as}")
   endif()
 endif()
+
 add_RunCMake_test(BuildDepends
+  -DMSVC_VERSION=${MSVC_VERSION}
+  -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
   -DCMake_TEST_BuildDepends_GNU_AS=${CMake_TEST_BuildDepends_GNU_AS}
   )
 if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
   add_RunCMake_test(Byproducts)
 endif()
 add_RunCMake_test(CMakeRoleGlobalProperty)
-add_RunCMake_test(CMakeRelease -DCMake_TEST_JQ=${CMake_TEST_JQ})
 if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
   add_RunCMake_test(CompilerChange)
 endif()
@@ -224,6 +239,9 @@ add_RunCMake_test(FileAPI -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
 add_RunCMake_test(FindBoost)
 add_RunCMake_test(FindLua)
 add_RunCMake_test(FindOpenGL)
+if(CMake_TEST_FindOpenSSL)
+  add_RunCMake_test(FindOpenSSL)
+endif()
 if(CMake_TEST_UseSWIG)
   add_RunCMake_test(FindSWIG)
   add_RunCMake_test(UseSWIG -DCMake_TEST_FindPython=${CMake_TEST_FindPython})
@@ -253,11 +271,12 @@ add_RunCMake_test(Graphviz)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(LinkStatic)
-if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
+if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang)$")
   add_RunCMake_test(MetaCompileFeatures)
 endif()
 if(MSVC)
   add_RunCMake_test(MSVCRuntimeLibrary)
+  add_RunCMake_test(MSVCRuntimeTypeInfo)
   add_RunCMake_test(MSVCWarningFlags)
 endif()
 add_RunCMake_test(ObjectLibrary)
@@ -275,6 +294,7 @@ add_RunCMake_test(ToolchainFile)
 add_RunCMake_test(find_dependency)
 add_RunCMake_test(CompileDefinitions)
 add_RunCMake_test(CompileFeatures)
+add_RunCMake_test(Policy)
 add_RunCMake_test(PolicyScope)
 add_RunCMake_test(WriteBasicConfigVersionFile)
 add_RunCMake_test(WriteCompilerDetectionHeader)
@@ -315,7 +335,7 @@ add_RunCMake_test(export)
 add_RunCMake_test(cmake_language)
 add_RunCMake_test(cmake_minimum_required)
 add_RunCMake_test(cmake_parse_arguments)
-add_RunCMake_test(cmake_path)
+add_RunCMake_test(cmake_path)
 add_RunCMake_test(continue)
 add_executable(color_warning color_warning.c)
 add_executable(fake_build_command fake_build_command.c)
@@ -338,6 +358,9 @@ add_RunCMake_test(ctest_upload)
 add_RunCMake_test(ctest_fixtures)
 add_RunCMake_test(file)
 add_RunCMake_test(file-CHMOD)
+if(HAVE_ELF_H OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
+  add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DHAVE_ELF_H=${HAVE_ELF_H})
+endif()
 add_RunCMake_test(find_file)
 add_RunCMake_test(find_library -DCYGWIN=${CYGWIN})
 add_RunCMake_test(find_package)
@@ -511,6 +534,7 @@ endif()
 
 if(XCODE_VERSION)
   add_RunCMake_test(XcodeProject -DXCODE_VERSION=${XCODE_VERSION})
+  add_RunCMake_test(XcodeProject-Embed)
 
   # This test can take a very long time due to lots of combinations.
   # Use a long default timeout and provide an option to customize it.
@@ -571,7 +595,8 @@ if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin)"
 endif()
 
 
-add_RunCMake_test(CommandLine -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCYGWIN=${CYGWIN} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
+add_executable(pseudo_llvm-rc pseudo_llvm-rc.c)
+add_RunCMake_test(CommandLine -DLLVM_RC=$<TARGET_FILE:pseudo_llvm-rc> -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCYGWIN=${CYGWIN} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
 add_RunCMake_test(CommandLineTar)
 
 if(CMAKE_PLATFORM_NO_VERSIONED_SONAME OR (NOT CMAKE_SHARED_LIBRARY_SONAME_FLAG AND NOT CMAKE_SHARED_LIBRARY_SONAME_C_FLAG))
@@ -780,6 +805,12 @@ add_RunCMake_test(PrecompileHeaders -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
 
 add_RunCMake_test("UnityBuild")
 add_RunCMake_test(CMakePresets -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
+add_RunCMake_test(CMakePresetsBuild -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
+add_RunCMake_test(CMakePresetsTest -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
+
+if(${CMAKE_GENERATOR} MATCHES "Make|Ninja")
+  add_RunCMake_test(TransformDepfile)
+endif()
 
 if(WIN32)
   add_RunCMake_test(Win32GenEx)
index e65c1a9..c6f943c 100644 (file)
     {
       "name": "Good Spaces",
       "generator": "@RunCMake_GENERATOR@",
-      "binaryDir": "${sourceDir}/build"
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "GOOD_SPACES": {
+          "type": "STRING",
+          "value": "1"
+        }
+      }
     },
     {
       "name": "GoodWindowsBackslash",
diff --git a/Tests/RunCMake/CMakePresets/GoodSpaces-stdout.txt b/Tests/RunCMake/CMakePresets/GoodSpaces-stdout.txt
new file mode 100644 (file)
index 0000000..d106c45
--- /dev/null
@@ -0,0 +1,3 @@
+Preset CMake variables:
+
+  GOOD_SPACES:STRING="1"
diff --git a/Tests/RunCMake/CMakePresets/GoodSpacesEq-stdout.txt b/Tests/RunCMake/CMakePresets/GoodSpacesEq-stdout.txt
new file mode 100644 (file)
index 0000000..d106c45
--- /dev/null
@@ -0,0 +1,3 @@
+Preset CMake variables:
+
+  GOOD_SPACES:STRING="1"
diff --git a/Tests/RunCMake/CMakePresets/GoodSpacesEq.cmake b/Tests/RunCMake/CMakePresets/GoodSpacesEq.cmake
new file mode 100644 (file)
index 0000000..e69de29
index 1758f33..60d6adb 100644 (file)
@@ -1,5 +1,5 @@
 ^Not searching for unused variables given on the command line\.
-Available presets:
+Available configure presets:
 
   "zzzzzz"   - Sleepy
   "aaaaaaaa" - Screaming
index 1758f33..60d6adb 100644 (file)
@@ -1,5 +1,5 @@
 ^Not searching for unused variables given on the command line\.
-Available presets:
+Available configure presets:
 
   "zzzzzz"   - Sleepy
   "aaaaaaaa" - Screaming
index 1758f33..60d6adb 100644 (file)
@@ -1,5 +1,5 @@
 ^Not searching for unused variables given on the command line\.
-Available presets:
+Available configure presets:
 
   "zzzzzz"   - Sleepy
   "aaaaaaaa" - Screaming
index 1758f33..60d6adb 100644 (file)
@@ -1,5 +1,5 @@
 ^Not searching for unused variables given on the command line\.
-Available presets:
+Available configure presets:
 
   "zzzzzz"   - Sleepy
   "aaaaaaaa" - Screaming
index aef30d2..a53682d 100644 (file)
@@ -1 +1,2 @@
-^CMake Error: No preset specified for --preset$
+^CMake Error: No preset specified for --preset
+CMake Error: Run 'cmake --help' for all supported options.$
diff --git a/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-result.txt b/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-stderr.txt b/Tests/RunCMake/CMakePresets/NoPresetArgumentEq-stderr.txt
new file mode 100644 (file)
index 0000000..a53682d
--- /dev/null
@@ -0,0 +1,2 @@
+^CMake Error: No preset specified for --preset
+CMake Error: Run 'cmake --help' for all supported options.$
index 1f399fe..dfc56ee 100644 (file)
@@ -9,21 +9,7 @@ endif()
 
 set(RunCMake-check-file check.cmake)
 
-function(validate_schema file expected_result)
-  execute_process(
-    COMMAND "${PYTHON_EXECUTABLE}" "${RunCMake_SOURCE_DIR}/validate_schema.py" "${file}"
-    RESULT_VARIABLE _result
-    OUTPUT_VARIABLE _output
-    ERROR_VARIABLE _error
-    )
-  if(NOT _result STREQUAL expected_result)
-    string(REPLACE "\n" "\n" _output_p "${_output}")
-    string(REPLACE "\n" "\n" _error_p "${_error}")
-    string(APPEND RunCMake_TEST_FAILED "Expected result of validating ${file}: ${expected_result}\nActual result: ${_result}\nOutput:\n${_output_p}\nError:\n${_error_p}")
-  endif()
-
-  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
-endfunction()
+include("${RunCMake_SOURCE_DIR}/validate_schema.cmake")
 
 function(run_cmake_presets name)
   set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
@@ -158,7 +144,8 @@ run_cmake_presets(GoodBinaryUp)
 set(CMakePresets_SOURCE_ARG "../GoodBinaryRelative")
 run_cmake_presets(GoodBinaryRelative)
 unset(CMakePresets_SOURCE_ARG)
-run_cmake_presets(GoodSpaces "--preset=Good Spaces")
+run_cmake_presets(GoodSpaces "--preset" "Good Spaces")
+run_cmake_presets(GoodSpacesEq "--preset=Good Spaces")
 if(WIN32)
   run_cmake_presets(GoodWindowsBackslash)
 endif()
@@ -221,7 +208,8 @@ endif()
 
 # Test bad command line arguments
 run_cmake_presets(NoSuchPreset)
-run_cmake_presets(NoPresetArgument --preset=)
+run_cmake_presets(NoPresetArgument --preset)
+run_cmake_presets(NoPresetArgumentEq --preset= -DA=B)
 run_cmake_presets(UseHiddenPreset)
 
 # Test CMakeUserPresets.json
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.cmake b/Tests/RunCMake/CMakePresets/validate_schema.cmake
new file mode 100644 (file)
index 0000000..68b638f
--- /dev/null
@@ -0,0 +1,19 @@
+function(validate_schema file expected_result)
+  if (NOT CMakePresets_VALIDATE_SCRIPT_PATH)
+    set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/validate_schema.py")
+  endif()
+
+  execute_process(
+    COMMAND "${PYTHON_EXECUTABLE}" "${CMakePresets_VALIDATE_SCRIPT_PATH}" "${file}"
+    RESULT_VARIABLE _result
+    OUTPUT_VARIABLE _output
+    ERROR_VARIABLE _error
+    )
+  if(NOT _result STREQUAL expected_result)
+    string(REPLACE "\n" "\n  " _output_p "${_output}")
+    string(REPLACE "\n" "\n  " _error_p "${_error}")
+    string(APPEND RunCMake_TEST_FAILED "Expected result of validating ${file}: ${expected_result}\nActual result: ${_result}\nOutput:\n  ${_output_p}\nError:\n  ${_error_p}\n")
+  endif()
+
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CMakePresetsBuild/CMakeLists.txt.in b/Tests/RunCMake/CMakePresetsBuild/CMakeLists.txt.in
new file mode 100644 (file)
index 0000000..129184a
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project("@CASE_NAME@" NONE)
+include("@CASE_SOURCE_DIR@/@CASE_NAME@.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-build-other-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-build-other-check.cmake
new file mode 100644 (file)
index 0000000..b2699db
--- /dev/null
@@ -0,0 +1,5 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_environment_variable("TEST_ENV_" "other")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-macros-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-macros-check.cmake
new file mode 100644 (file)
index 0000000..7801c3d
--- /dev/null
@@ -0,0 +1,14 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+if(RunCMake_GENERATOR STREQUAL "NMake Makefiles JOM")
+  # JOM removes the '$' and content following it.
+else()
+  test_environment_variable("TEST_DOLLAR" "x\\$x")
+endif()
+test_environment_variable("TEST_GENERATOR" "${RunCMake_GENERATOR}")
+test_environment_variable("TEST_PRESET_NAME" "xmacrosx")
+test_environment_variable("TEST_SOURCE_DIR_" "x[^\n]*[/\\\\]Tests[/\\\\]RunCMake[/\\\\]CMakePresetsBuild[/\\\\]Goodx")
+test_environment_variable("TEST_SOURCE_DIR_NAME" "xGoodx")
+test_environment_variable("TEST_SOURCE_PARENT_DIR" "x[^\n]*[/\\\\]Tests[/\\\\]RunCMake[/\\\\]CMakePresetsBuildx")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-noEnvironment-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-noEnvironment-check.cmake
new file mode 100644 (file)
index 0000000..94a54ca
--- /dev/null
@@ -0,0 +1,6 @@
+string(FIND "${actual_stdout}" "TEST_ENV_" TEST_ENV_POS)
+if (NOT TEST_ENV_POS EQUAL -1)
+  message(FATAL_ERROR "Found TEST_ENV_ in environment")
+endif()
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good-build-withEnvironment-check.cmake b/Tests/RunCMake/CMakePresetsBuild/Good-build-withEnvironment-check.cmake
new file mode 100644 (file)
index 0000000..9c6b5c2
--- /dev/null
@@ -0,0 +1,8 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_environment_variable("TEST_ENV_" "Environment variable")
+test_environment_variable("TEST_ENV_OVERRIDE_" "Overridden")
+test_environment_variable("TEST_ENV_OVERRIDE_REF" "xOverriddenx")
+test_environment_variable("TEST_ENV_REF" "xEnvironment variablex")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good.cmake b/Tests/RunCMake/CMakePresetsBuild/Good.cmake
new file mode 100644 (file)
index 0000000..491d367
--- /dev/null
@@ -0,0 +1,3 @@
+add_custom_target(good ALL)
+add_custom_command(TARGET good PRE_BUILD
+    COMMAND ${CMAKE_COMMAND} -E environment)
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good.json.in b/Tests/RunCMake/CMakePresetsBuild/Good.json.in
new file mode 100644 (file)
index 0000000..fd43c4e
--- /dev/null
@@ -0,0 +1,78 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}",
+            "environment": {
+                "TEST_ENV_": "Environment variable",
+                "TEST_ENV_OVERRIDE_": "Environment variable",
+                "TEST_ENV_OVERRIDE_REF": "x$env{TEST_ENV_OVERRIDE_}x"
+            }
+        },
+        {
+            "name": "other",
+            "inherits": "default",
+            "environment": {
+                "TEST_ENV_": "other"
+            }
+        }
+    ],
+    "buildPresets": [
+        {
+            "name": "build-default",
+            "hidden": true,
+            "inherits": [],
+            "configurePreset": "default",
+            "vendor": {},
+            "displayName": "",
+            "description": "",
+            "inheritConfigureEnvironment": true,
+            "environment": {},
+            "jobs": 0,
+            "targets": [],
+            "configuration": "",
+            "verbose": true,
+            "nativeToolOptions": []
+        },
+        {
+            "name": "build-other",
+            "configurePreset": "other"
+        },
+        {
+            "name": "withEnvironment",
+            "inherits": "build-default",
+            "environment": {
+                "TEST_ENV_OVERRIDE_": "Overridden",
+                "TEST_ENV_REF": "x$env{TEST_ENV_}x",
+                "TEST_ENV_OVERRIDE_REF": "x$env{TEST_ENV_OVERRIDE_}x"
+            }
+        },
+        {
+            "name": "noEnvironment",
+            "inherits": "build-default",
+            "inheritConfigureEnvironment": false
+        },
+        {
+            "name": "macros",
+            "inherits": "build-default",
+            "inheritConfigureEnvironment": false,
+            "environment": {
+                "TEST_SOURCE_DIR_": "x${sourceDir}x",
+                "TEST_SOURCE_PARENT_DIR": "x${sourceParentDir}x",
+                "TEST_SOURCE_DIR_NAME": "x${sourceDirName}x",
+                "TEST_PRESET_NAME": "x${presetName}x",
+                "TEST_GENERATOR": "x${generator}x",
+                "TEST_DOLLAR": "x${dollar}x"
+            }
+        },
+        {
+            "name": "vendorObject",
+            "configurePreset": "default",
+            "vendor": {
+                "example.com": "value"
+            }
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-badConfigurePreset-stderr.txt
new file mode 100644 (file)
index 0000000..7c3255d
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: No such configure preset in [^
+]*/Tests/RunCMake/CMakePresetsBuild/Invalid: "dne"
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-result.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-hidden-stderr.txt
new file mode 100644 (file)
index 0000000..f10c7b8
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Cannot use hidden build preset in [^
+]*/Tests/RunCMake/CMakePresetsBuild/Invalid: "hidden"
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-result.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Invalid-build-vendorMacro-stderr.txt
new file mode 100644 (file)
index 0000000..a3b951f
--- /dev/null
@@ -0,0 +1 @@
+CMake Error: Could not evaluate build preset "vendorMacro": Invalid macro expansion
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid.cmake b/Tests/RunCMake/CMakePresetsBuild/Invalid.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsBuild/Invalid.json.in b/Tests/RunCMake/CMakePresetsBuild/Invalid.json.in
new file mode 100644 (file)
index 0000000..c22fdec
--- /dev/null
@@ -0,0 +1,23 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "buildPresets": [
+        {
+            "name": "hidden",
+            "hidden": true
+        },
+        {
+            "name": "vendorMacro",
+            "configurePreset": "default",
+            "environment": {
+                "TEST": "$vendor{bad.TEST}"
+            }
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-build-badConfigurePreset-stderr.txt
new file mode 100644 (file)
index 0000000..303632e
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-result.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset-configure-default-stderr.txt
new file mode 100644 (file)
index 0000000..303632e
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsBuild/InvalidConfigurePreset.json.in
new file mode 100644 (file)
index 0000000..c0429d5
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "buildPresets": [
+        {
+            "name": "badConfigurePreset",
+            "configurePreset": "dne"
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt b/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt
new file mode 100644 (file)
index 0000000..4d30707
--- /dev/null
@@ -0,0 +1,5 @@
+Available build presets:
+
+  "build-default" - build-default displayName
+  "empty"
+  "display"       - display displayName
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets.cmake b/Tests/RunCMake/CMakePresetsBuild/ListPresets.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in b/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in
new file mode 100644 (file)
index 0000000..3f5e02c
--- /dev/null
@@ -0,0 +1,31 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "buildPresets": [
+        {
+            "name": "build-default",
+            "configurePreset": "default",
+            "displayName": "build-default displayName",
+            "description": "build-default description"
+        },
+        {
+            "name": "empty",
+            "inherits": "build-default"
+        },
+        {
+            "name": "display",
+            "inherits": "build-default",
+            "displayName": "display displayName"
+        },
+        {
+            "name": "hidden",
+            "hidden": true
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset-build-noConfigurePreset-stderr.txt
new file mode 100644 (file)
index 0000000..fcb37bc
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset: Invalid preset
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsBuild/NoConfigurePreset.json.in
new file mode 100644 (file)
index 0000000..81b2cde
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "buildPresets": [
+        {
+            "name": "noConfigurePreset"
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-result.txt b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported-build-x-stderr.txt
new file mode 100644 (file)
index 0000000..d6ae62d
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported: File version must be 2 or higher for build and test preset support.
diff --git a/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported.json.in b/Tests/RunCMake/CMakePresetsBuild/PresetsUnsupported.json.in
new file mode 100644 (file)
index 0000000..0028239
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "version": 1,
+    "configurePresets": [
+    ],
+    "buildPresets": [
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..2559b12
--- /dev/null
@@ -0,0 +1,76 @@
+include(RunCMake)
+
+# Presets do not support legacy VS generator name architecture suffix.
+if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ")
+  set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
+endif()
+
+function(run_cmake_build_presets name CMakePresetsBuild_CONFIGURE_PRESETS CMakePresetsBuild_BUILD_PRESETS)
+  set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build")
+  set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+
+  set(RunCMake_TEST_NO_CLEAN TRUE)
+
+  file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  set(CASE_NAME "${name}")
+  set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
+  configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in" "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY)
+
+  if(NOT CMakePresetsBuild_FILE)
+    set(CMakePresetsBuild_FILE "${RunCMake_SOURCE_DIR}/${name}.json.in")
+  endif()
+  if(EXISTS "${CMakePresetsBuild_FILE}")
+    configure_file("${CMakePresetsBuild_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY)
+  endif()
+
+  if(NOT CMakeUserPresets_FILE)
+    set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/${name}User.json.in")
+  endif()
+  if(EXISTS "${CMakeUserPresets_FILE}")
+    configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
+  endif()
+
+  if (NOT CMakePresetsBuild_BUILD_ONLY)
+    foreach(CONFIGURE_PRESET ${CMakePresetsBuild_CONFIGURE_PRESETS})
+      run_cmake_command("${name}-configure-${CONFIGURE_PRESET}"
+        "${CMAKE_COMMAND}" "--preset" "${CONFIGURE_PRESET}")
+    endforeach()
+  endif()
+
+  set(eq 0)
+  foreach(BUILD_PRESET ${CMakePresetsBuild_BUILD_PRESETS})
+    if (EXISTS "${RunCMake_SOURCE_DIR}/${name}-build-${BUILD_PRESET}-check.cmake")
+      set(RunCMake-check-file "${name}-build-${BUILD_PRESET}-check.cmake")
+    else()
+      set(RunCMake-check-file "check.cmake")
+    endif()
+
+    if(eq)
+      run_cmake_command(${name}-build-${BUILD_PRESET}
+        ${CMAKE_COMMAND} "--build" "--preset=${BUILD_PRESET}" ${ARGN})
+      set(eq 0)
+    else()
+      run_cmake_command(${name}-build-${BUILD_PRESET}
+        ${CMAKE_COMMAND} "--build" "--preset" "${BUILD_PRESET}" ${ARGN})
+      set(eq 1)
+    endif()
+  endforeach()
+endfunction()
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+
+run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject")
+run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset")
+
+set(CMakePresetsBuild_BUILD_ONLY 1)
+run_cmake_build_presets(ListPresets "x" "x" "--list-presets")
+run_cmake_build_presets(NoConfigurePreset "x" "noConfigurePreset")
+run_cmake_build_presets(Invalid "x" "hidden;vendorMacro")
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_build_presets(PresetsUnsupported "x" "x")
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+set(CMakePresetsBuild_BUILD_ONLY 0)
diff --git a/Tests/RunCMake/CMakePresetsBuild/TestVariable.cmake b/Tests/RunCMake/CMakePresetsBuild/TestVariable.cmake
new file mode 100644 (file)
index 0000000..3113dcc
--- /dev/null
@@ -0,0 +1,14 @@
+function(test_environment_variable name expected_value)
+  string(REGEX MATCH "${name}=([^\n]*)" REGEX_RESULT "${actual_stdout}")
+  if(NOT REGEX_RESULT)
+    string(APPEND RunCMake_TEST_FAILED "Environment variable '${name}' is not defined.\n")
+  else()
+    set(actual_value "${CMAKE_MATCH_1}")
+    if(NOT "${actual_value}" MATCHES "${expected_value}")
+      string(REPLACE "\n" "\n  " _actual "${expected_value}")
+      string(REPLACE "\n" "\n  " _expect "${actual_value}")
+      string(APPEND RunCMake_TEST_FAILED "Expected value of environment variable '${name}':\n  ${_expect}\nActual value:\n  ${_actual}\n")
+    endif()
+  endif()
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CMakePresetsBuild/check.cmake b/Tests/RunCMake/CMakePresetsBuild/check.cmake
new file mode 100644 (file)
index 0000000..e79c4f1
--- /dev/null
@@ -0,0 +1,3 @@
+set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsTest/CMakeLists.txt.in b/Tests/RunCMake/CMakePresetsTest/CMakeLists.txt.in
new file mode 100644 (file)
index 0000000..129184a
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project("@CASE_NAME@" NONE)
+include("@CASE_SOURCE_DIR@/@CASE_NAME@.cmake")
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-indexFile.txt b/Tests/RunCMake/CMakePresetsTest/Good-indexFile.txt
new file mode 100644 (file)
index 0000000..4ac2314
--- /dev/null
@@ -0,0 +1 @@
+2,,2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-config-debug-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-config-debug-stdout.txt
new file mode 100644 (file)
index 0000000..c281c81
--- /dev/null
@@ -0,0 +1,5 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+    Start 6: debug-only
+.*
+100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-config-release-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-config-release-stdout.txt
new file mode 100644 (file)
index 0000000..66bfd22
--- /dev/null
@@ -0,0 +1,5 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+    Start 6: release-only
+.*
+100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-exclude-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-exclude-stdout.txt
new file mode 100644 (file)
index 0000000..5e990de
--- /dev/null
@@ -0,0 +1,7 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+    Start 3: testc
+.*
+    Start 4: testd
+.*
+100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-index-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-index-stdout.txt
new file mode 100644 (file)
index 0000000..2df6fcb
--- /dev/null
@@ -0,0 +1,7 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+    Start 1: testa
+.*
+    Start 3: testc
+.*
+100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-indexFile-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-indexFile-stdout.txt
new file mode 100644 (file)
index 0000000..1366876
--- /dev/null
@@ -0,0 +1,7 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+    Start 2: testb
+.*
+    Start 4: testd
+.*
+100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-noEnvironment-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-noEnvironment-stdout.txt
new file mode 100644 (file)
index 0000000..8b4845e
--- /dev/null
@@ -0,0 +1,8 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+.*
+    Start 5: test-env
+.*
+5: TEST_ENV_REF=xx
+.*
+100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-showOnly-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-showOnly-stdout.txt
new file mode 100644 (file)
index 0000000..67ddd4f
--- /dev/null
@@ -0,0 +1,8 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+  Test #1: testa
+  Test #2: testb
+  Test #3: testc
+  Test #4: testd
+
+Total Tests: 4
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-withEnvironment-check.cmake b/Tests/RunCMake/CMakePresetsTest/Good-withEnvironment-check.cmake
new file mode 100644 (file)
index 0000000..0c19556
--- /dev/null
@@ -0,0 +1,8 @@
+include("${RunCMake_SOURCE_DIR}/../CMakePresetsBuild/TestVariable.cmake")
+
+test_environment_variable("TEST_ENV" "Environment variable")
+test_environment_variable("TEST_ENV_OVERRIDE" "Override")
+test_environment_variable("TEST_ENV_OVERRIDE_REF" "xOverridex")
+test_environment_variable("TEST_ENV_REF" "xEnvironment variablex")
+
+include("${RunCMake_SOURCE_DIR}/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsTest/Good.cmake b/Tests/RunCMake/CMakePresetsTest/Good.cmake
new file mode 100644 (file)
index 0000000..0a6cf57
--- /dev/null
@@ -0,0 +1,27 @@
+enable_testing()
+add_test(testa ${CMAKE_COMMAND} -E echo testa)
+add_test(testb ${CMAKE_COMMAND} -E echo testb)
+add_test(testc ${CMAKE_COMMAND} -E echo testc)
+add_test(testd ${CMAKE_COMMAND} -E echo testd)
+
+set_tests_properties(testa testb testc testd
+                     PROPERTIES LABELS "echo")
+set_property(TEST testa testb
+             APPEND PROPERTY LABELS ab)
+set_property(TEST testb testc
+             APPEND PROPERTY LABELS bc)
+set_property(TEST testc testd
+             APPEND PROPERTY LABELS cd)
+
+add_test(test-env ${CMAKE_COMMAND} -E environment | sort)
+set_tests_properties(test-env PROPERTIES LABELS "env")
+
+add_test(NAME debug-only
+         COMMAND ${CMAKE_COMMAND} -E echo debug-only
+         CONFIGURATIONS Debug)
+add_test(NAME release-only
+         COMMAND ${CMAKE_COMMAND} -E echo release-only
+         CONFIGURATIONS Release)
+
+set_tests_properties(debug-only release-only
+                     PROPERTIES LABELS "config")
diff --git a/Tests/RunCMake/CMakePresetsTest/Good.json.in b/Tests/RunCMake/CMakePresetsTest/Good.json.in
new file mode 100644 (file)
index 0000000..57be5a5
--- /dev/null
@@ -0,0 +1,175 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}",
+            "environment": {
+                "TEST_ENV": "Environment variable",
+                "TEST_ENV_OVERRIDE": "Overridden environment variable"
+            }
+        }
+    ],
+    "buildPresets": [
+        {
+            "name": "build-default-debug",
+            "configurePreset": "default",
+            "configuration": "Debug"
+        },
+        {
+            "name": "build-default-release",
+            "inherits": "build-default-debug",
+            "configuration": "Release"
+        }
+    ],
+    "testPresets": [
+        {
+            "name": "minimal",
+            "configurePreset": "default"
+        },
+        {
+            "name": "defaults",
+            "hidden": false,
+            "inherits": [],
+            "vendor": {},
+            "displayName": "",
+            "description": "",
+            "environment": {},
+            "configurePreset": "default",
+            "inheritConfigureEnvironment": true,
+            "configuration": "",
+            "overwriteConfigurationFile": [],
+            "output": {
+                "shortProgress": false,
+                "verbosity": "default",
+                "debug": false,
+                "outputOnFailure": false,
+                "quiet": false,
+                "outputLogFile": "",
+                "labelSummary": true,
+                "subprojectSummary": true
+            },
+            "filter": {
+                "include": {
+                    "name": "",
+                    "label": "",
+                    "useUnion": false,
+                    "index": ""
+                },
+                "exclude": {
+                    "name": "",
+                    "label": "",
+                    "fixtures": {
+                        "any": "",
+                        "setup": "",
+                        "cleanup": ""
+                    }
+                }
+            },
+            "execution": {
+                "stopOnFailure": false,
+                "enableFailover": false,
+                "jobs": 0,
+                "resourceSpecFile": "",
+                "showOnly": "human",
+                "repeat": {
+                    "mode": "until-pass",
+                    "count": 1
+                },
+                "interactiveDebugging": false,
+                "scheduleRandom": false,
+                "noTestsAction": "default"
+            }
+        },
+        {
+            "name": "noEnvironment",
+            "configurePreset": "default",
+            "inheritConfigureEnvironment": false,
+            "environment": {
+                "TEST_ENV_REF": "x$env{TEST_ENV}x"
+            },
+            "filter": {
+                "include": {
+                    "name": "test-env"
+                }
+            },
+            "output": {
+                "verbosity": "verbose"
+            }
+        },
+        {
+            "name": "withEnvironment",
+            "inherits": "noEnvironment",
+            "inheritConfigureEnvironment": true,
+            "environment": {
+                "TEST_ENV_OVERRIDE": "Override",
+                "TEST_ENV_OVERRIDE_REF": "x$env{TEST_ENV_OVERRIDE}x",
+                "TEST_ENV_REF": "x$env{TEST_ENV}x"
+            }
+        },
+        {
+            "name": "config-debug",
+            "inherits": "minimal",
+            "configuration": "Debug",
+            "filter": {
+                "include": {
+                    "label": "config"
+                }
+            }
+        },
+        {
+            "name": "config-release",
+            "inherits": "minimal",
+            "configuration": "Release",
+            "filter": {
+                "include": {
+                    "label": "config"
+                }
+            }
+        },
+        {
+            "name": "exclude",
+            "inherits": "minimal",
+            "filter": {
+                "exclude": {
+                    "name": "test-env",
+                    "label": "(ab|config)"
+                }
+            }
+        },
+        {
+            "name": "index",
+            "inherits": "minimal",
+            "filter": {
+                "include": {
+                    "index": {
+                        "end": 4,
+                        "stride": 2
+                    }
+                }
+            }
+        },
+        {
+            "name": "indexFile",
+            "inherits": "minimal",
+            "filter": {
+                "include": {
+                    "index": "${sourceDir}/Good-indexFile.txt"
+                }
+            }
+        },
+        {
+            "name": "showOnly",
+            "inherits": "minimal",
+            "filter": {
+                "include": {
+                    "label": "echo"
+                }
+            },
+            "execution": {
+                "showOnly": "human"
+            }
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-badConfigurePreset-stderr.txt
new file mode 100644 (file)
index 0000000..9cf9987
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: No such configure preset in [^
+]*/Tests/RunCMake/CMakePresetsTest/Invalid: "dne"
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-result.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-stderr.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-hidden-stderr.txt
new file mode 100644 (file)
index 0000000..41b1b4e
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Cannot use hidden test preset in [^
+]*/Tests/RunCMake/CMakePresetsTest/Invalid: "hidden"
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-result.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-stderr.txt b/Tests/RunCMake/CMakePresetsTest/Invalid-test-vendorMacro-stderr.txt
new file mode 100644 (file)
index 0000000..ed5bb98
--- /dev/null
@@ -0,0 +1 @@
+CMake Error: Could not evaluate test preset "vendorMacro": Invalid macro expansion
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid.cmake b/Tests/RunCMake/CMakePresetsTest/Invalid.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsTest/Invalid.json.in b/Tests/RunCMake/CMakePresetsTest/Invalid.json.in
new file mode 100644 (file)
index 0000000..cfcf4b7
--- /dev/null
@@ -0,0 +1,23 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "testPresets": [
+        {
+            "name": "hidden",
+            "hidden": true
+        },
+        {
+            "name": "vendorMacro",
+            "configurePreset": "default",
+            "environment": {
+                "TEST": "$vendor{bad.TEST}"
+            }
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-result.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-stderr.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-configure-default-stderr.txt
new file mode 100644 (file)
index 0000000..3d7cdd0
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset-test-badConfigurePreset-stderr.txt
new file mode 100644 (file)
index 0000000..3d7cdd0
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset: Invalid "configurePreset" field
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsTest/InvalidConfigurePreset.json.in
new file mode 100644 (file)
index 0000000..e305c42
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "testPresets": [
+        {
+            "name": "badConfigurePreset",
+            "configurePreset": "dne"
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt b/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt
new file mode 100644 (file)
index 0000000..46ffbcf
--- /dev/null
@@ -0,0 +1,12 @@
+Available test presets:
+
+  "minimal"
+  "defaults"
+  "noEnvironment"
+  "withEnvironment"
+  "config-debug"
+  "config-release"
+  "exclude"
+  "index"
+  "indexFile"
+  "showOnly"
diff --git a/Tests/RunCMake/CMakePresetsTest/ListPresets.cmake b/Tests/RunCMake/CMakePresetsTest/ListPresets.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-result.txt b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset-test-noConfigurePreset-stderr.txt
new file mode 100644 (file)
index 0000000..b167f68
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset: Invalid preset
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.cmake b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.json.in b/Tests/RunCMake/CMakePresetsTest/NoConfigurePreset.json.in
new file mode 100644 (file)
index 0000000..4591cc8
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "testPresets": [
+        {
+            "name": "noConfigurePreset"
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-result.txt b/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-result.txt
new file mode 100644 (file)
index 0000000..45a4fb7
--- /dev/null
@@ -0,0 +1 @@
+8
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-stderr.txt b/Tests/RunCMake/CMakePresetsTest/NoTestsAction-test-noTestsAction-stderr.txt
new file mode 100644 (file)
index 0000000..eafba1c
--- /dev/null
@@ -0,0 +1 @@
+No tests were found!!!
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction.cmake b/Tests/RunCMake/CMakePresetsTest/NoTestsAction.cmake
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/CMakePresetsTest/NoTestsAction.json.in b/Tests/RunCMake/CMakePresetsTest/NoTestsAction.json.in
new file mode 100644 (file)
index 0000000..20a50d6
--- /dev/null
@@ -0,0 +1,19 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "testPresets": [
+        {
+            "name": "noTestsAction",
+            "configurePreset": "default",
+            "execution": {
+                "noTestsAction": "error"
+            }
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-result.txt b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported-test-x-stderr.txt
new file mode 100644 (file)
index 0000000..eb0ec1a
--- /dev/null
@@ -0,0 +1,2 @@
+CMake Error: Could not read presets from [^
+]*Tests/RunCMake/CMakePresetsTest/PresetsUnsupported: File version must be 2 or higher for build and test preset support.
diff --git a/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported.json.in b/Tests/RunCMake/CMakePresetsTest/PresetsUnsupported.json.in
new file mode 100644 (file)
index 0000000..ff1b000
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "version": 1,
+    "configurePresets": [
+    ],
+    "testPresets": [
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..c93dff3
--- /dev/null
@@ -0,0 +1,104 @@
+include(RunCMake)
+
+# Presets do not support legacy VS generator name architecture suffix.
+if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ")
+  set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
+endif()
+
+function(run_cmake_test_presets name CMakePresetsTest_CONFIGURE_PRESETS CMakePresetsTest_BUILD_PRESETS CMakePresetsTest_TEST_PRESETS)
+  set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build")
+  set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+
+  set(RunCMake_TEST_NO_CLEAN TRUE)
+
+  file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  set(CASE_NAME "${name}")
+  set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
+  configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in" "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY)
+
+  if(NOT CMakePresetsTest_FILE)
+    set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/${name}.json.in")
+  endif()
+  if(EXISTS "${CMakePresetsTest_FILE}")
+    configure_file("${CMakePresetsTest_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY)
+  endif()
+
+  if(NOT CMakeUserPresets_FILE)
+    set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/${name}User.json.in")
+  endif()
+  if(EXISTS "${CMakeUserPresets_FILE}")
+    configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
+  endif()
+
+  foreach(ASSET ${CMakePresetsTest_ASSETS})
+    configure_file("${RunCMake_SOURCE_DIR}/${ASSET}" "${RunCMake_TEST_SOURCE_DIR}" COPYONLY)
+  endforeach()
+
+  if (NOT CMakePresetsTest_NO_CONFIGURE)
+    foreach(CONFIGURE_PRESET ${CMakePresetsTest_CONFIGURE_PRESETS})
+      run_cmake_command("${name}-configure-${CONFIGURE_PRESET}"
+        "${CMAKE_COMMAND}" "--preset" "${CONFIGURE_PRESET}")
+    endforeach()
+  endif()
+
+  if (NOT CMakePresetsTest_NO_BUILD)
+    foreach(BUILD_PRESET ${CMakePresetsTest_BUILD_PRESETS})
+      run_cmake_command("${name}-build-${BUILD_PRESET}"
+        "${CMAKE_COMMAND}" "--build" "--preset" "${BUILD_PRESET}")
+    endforeach()
+  endif()
+
+  set(eq 0)
+  foreach(TEST_PRESET ${CMakePresetsTest_TEST_PRESETS})
+    if (EXISTS "${RunCMake_SOURCE_DIR}/${name}-test-${TEST_PRESET}-check.cmake")
+      set(RunCMake-check-file "${name}-test-${TEST_PRESET}-check.cmake")
+    else()
+      set(RunCMake-check-file "check.cmake")
+    endif()
+
+    if(eq)
+      run_cmake_command(${name}-test-${TEST_PRESET}
+        ${CMAKE_CTEST_COMMAND} "--preset=${TEST_PRESET}" ${ARGN})
+      set(eq 0)
+    else()
+      run_cmake_command(${name}-test-${TEST_PRESET}
+        ${CMAKE_CTEST_COMMAND} "--preset" "${TEST_PRESET}" ${ARGN})
+      set(eq 1)
+    endif()
+  endforeach()
+endfunction()
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+set(CMakePresetsTest_NO_BUILD 1)
+
+set(CMakePresetsTest_ASSETS "Good-indexFile.txt")
+set(GoodTestPresets
+  "minimal;defaults;noEnvironment;withEnvironment"
+  "config-debug;config-release"
+  "exclude;index;indexFile;showOnly")
+run_cmake_test_presets(Good
+                       "default"
+                       ""
+                       "${GoodTestPresets}")
+unset(CMakePresetsTest_ASSETS)
+
+run_cmake_test_presets(InvalidConfigurePreset "default" "" "badConfigurePreset")
+
+set(CMakePresetsTest_NO_CONFIGURE 1)
+set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/Good.json.in")
+run_cmake_test_presets(ListPresets "" "" "x" "--list-presets")
+unset(CMakePresetsTest_FILE)
+
+run_cmake_test_presets(NoConfigurePreset "" "" "noConfigurePreset")
+run_cmake_test_presets(NoTestsAction "default" "" "noTestsAction")
+run_cmake_test_presets(Invalid "" "" "hidden;vendorMacro")
+
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_test_presets(PresetsUnsupported "" "" "x")
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+set(CMakePresetsTest_NO_CONFIGURE 0)
+
+set(CMakePresetsTest_NO_BUILD 0)
diff --git a/Tests/RunCMake/CMakePresetsTest/check.cmake b/Tests/RunCMake/CMakePresetsTest/check.cmake
new file mode 100644 (file)
index 0000000..e79c4f1
--- /dev/null
@@ -0,0 +1,3 @@
+set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
+include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CMakeRelease/FileTable-stdout.txt b/Tests/RunCMake/CMakeRelease/FileTable-stdout.txt
deleted file mode 100644 (file)
index 011673f..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-^-- query: \.version \| \.major , \.minor , \.patch , \.suffix, \.string
-1
-2
-3
-"rc4"
-"@version@"
--- query: \.files\[\]\.name
-"cmake-@version@-Linux-aarch64\.sh"
-"cmake-@version@-Linux-aarch64\.tar\.gz"
-"cmake-@version@-Linux-x86_64\.sh"
-"cmake-@version@-Linux-x86_64\.tar\.gz"
-"cmake-@version@-macos-universal\.dmg"
-"cmake-@version@-macos-universal\.tar\.gz"
-"cmake-@version@-macos10\.10-universal\.dmg"
-"cmake-@version@-macos10\.10-universal\.tar\.gz"
-"cmake-@version@-win32-x86\.msi"
-"cmake-@version@-win32-x86\.zip"
-"cmake-@version@-win64-x64\.msi"
-"cmake-@version@-win64-x64\.zip"
-"cmake-@version@\.tar\.gz"
-"cmake-@version@\.zip"
--- query: \.files\[\] \| select\(\.os\[\] \| \. == "source"\) \| \.name
-"cmake-@version@\.tar\.gz"
-"cmake-@version@\.zip"
--- query: \.files\[\] \| select\(\(\.os\[\] \| \. == "macOS"\) and \(\.class == "volume"\)\) \| \.name
-"cmake-@version@-macos-universal\.dmg"
--- query: \.files\[\] \| select\(\(\.os\[\] \| \. == "macos10\.10"\) and \(\.class == "archive"\)\) \| \.name
-"cmake-@version@-macos10\.10-universal\.tar\.gz"
--- query: \.files\[\] \| select\(\(\.os\[\] \| \. == "windows"\) and \(\.architecture\[\] \| \. == "i386"\) and \(\.class == "installer"\)\) \| \.name
-"cmake-@version@-win32-x86\.msi"
--- query: \.files\[\] \| select\(\.architecture\[\] \| \. == "x86_64"\) \| \.name
-"cmake-@version@-Linux-x86_64\.sh"
-"cmake-@version@-Linux-x86_64\.tar\.gz"
-"cmake-@version@-macos-universal\.dmg"
-"cmake-@version@-macos-universal\.tar\.gz"
-"cmake-@version@-macos10\.10-universal\.dmg"
-"cmake-@version@-macos10\.10-universal\.tar\.gz"
-"cmake-@version@-win64-x64\.msi"
-"cmake-@version@-win64-x64\.zip"
--- query: \.files\[\] \| select\(\[\.macOSmin\] \| inside\(\["10\.10", "10\.11", "10\.12"\]\)\) \| \.name
-"cmake-@version@-macos10\.10-universal\.dmg"
-"cmake-@version@-macos10\.10-universal\.tar\.gz"
--- query: \.hashFiles\[\] \| select\(\.algorithm\[\] \| \. == "SHA-256"\) \| \.name
-"cmake-@version@-SHA-256\.txt"$
diff --git a/Tests/RunCMake/CMakeRelease/FileTable.cmake b/Tests/RunCMake/CMakeRelease/FileTable.cmake
deleted file mode 100644 (file)
index f46535c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-set(version "@version@")
-set(version_major "1")
-set(version_minor "2")
-set(version_patch "3")
-set(maybe_version_suffix "\"suffix\": \"rc4\",")
-configure_file("${CMAKE_CURRENT_LIST_DIR}/../../../Utilities/Release/files-v1.json.in" "files-v1.json" @ONLY)
-
-foreach(query
-    ".version | .major , .minor , .patch , .suffix, .string"
-    ".files[].name"
-    ".files[] | select(.os[] | . == \"source\") | .name"
-    ".files[] | select((.os[] | . == \"macOS\") and (.class == \"volume\")) | .name"
-    ".files[] | select((.os[] | . == \"macos10.10\") and (.class == \"archive\")) | .name"
-    ".files[] | select((.os[] | . == \"windows\") and (.architecture[] | . == \"i386\") and (.class == \"installer\")) | .name"
-    ".files[] | select(.architecture[] | . == \"x86_64\") | .name"
-    ".files[] | select([.macOSmin] | inside([\"10.10\", \"10.11\", \"10.12\"])) | .name"
-    ".hashFiles[] | select(.algorithm[] | . == \"SHA-256\") | .name"
-    )
-  message(STATUS "query: ${query}")
-  execute_process(COMMAND ${JQ} "${query}" files-v1.json)
-endforeach()
diff --git a/Tests/RunCMake/CMakeRelease/RunCMakeTest.cmake b/Tests/RunCMake/CMakeRelease/RunCMakeTest.cmake
deleted file mode 100644 (file)
index 9a08ff3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-include(RunCMake)
-
-if(CMake_TEST_JQ)
-  set(JQ "${CMake_TEST_JQ}")
-else()
-  find_program(JQ NAMES jq)
-endif()
-if(JQ)
-  run_cmake_script(FileTable -DJQ=${JQ})
-endif()
index 24f54c6..3ec4c69 100644 (file)
@@ -21,6 +21,12 @@ function(run_cpack_test_common_ TEST_NAME types build SUBTEST_SUFFIX source PACK
      # TODO this should be executed only once per ctest run (not per generator)
     file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
     file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+    # Set permissions to those expected by the test
+    file(CHMOD "${RunCMake_TEST_BINARY_DIR}"
+      PERMISSIONS
+        OWNER_READ OWNER_WRITE OWNER_EXECUTE
+        GROUP_READ GROUP_EXECUTE
+        WORLD_READ WORLD_EXECUTE)
 
     if(EXISTS "${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-Prerequirements.cmake")
       include("${RunCMake_SOURCE_DIR}/tests/${TEST_NAME}/${GENERATOR_TYPE}-Prerequirements.cmake")
index 530bcdf..15bfb60 100644 (file)
@@ -21,8 +21,8 @@ run_cpack_test(LONG_FILENAMES "DEB.LONG_FILENAMES" false "MONOLITHIC")
 run_cpack_test_subtests(MAIN_COMPONENT "invalid;found" "RPM.MAIN_COMPONENT" false "COMPONENT")
 run_cpack_test(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;External" false "MONOLITHIC;COMPONENT")
 run_cpack_test_package_target(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;External" false "MONOLITHIC;COMPONENT")
-run_cpack_test_package_target(THREADED_ALL "TXZ" false "MONOLITHIC;COMPONENT")
-run_cpack_test_package_target(THREADED "TXZ" false "MONOLITHIC;COMPONENT")
+run_cpack_test_package_target(THREADED_ALL "TXZ;DEB" false "MONOLITHIC;COMPONENT")
+run_cpack_test_package_target(THREADED "TXZ;DEB" false "MONOLITHIC;COMPONENT")
 run_cpack_test_subtests(PACKAGE_CHECKSUM "invalid;MD5;SHA1;SHA224;SHA256;SHA384;SHA512" "TGZ" false "MONOLITHIC")
 run_cpack_test(PARTIALLY_RELOCATABLE_WARNING "RPM.PARTIALLY_RELOCATABLE_WARNING" false "COMPONENT")
 run_cpack_test(PER_COMPONENT_FIELDS "RPM.PER_COMPONENT_FIELDS;DEB.PER_COMPONENT_FIELDS" false "COMPONENT")
index 345b37f..0ab545a 100644 (file)
@@ -79,6 +79,11 @@ if(NOT EXPECTED_FILES_COUNT EQUAL 0)
           "which does not match:${msg_expected}\n"
           "${output_error_message}")
       endif()
+    elseif(foundFilescount_ EQUAL 0)
+      message(FATAL_ERROR
+        "Found no files for file No. '${file_no_}'!"
+        " Globbing expression: '${EXPECTED_FILE_${file_no_}}'"
+        "${output_error_message}")
     else()
       message(FATAL_ERROR
         "Found more than one file for file No. '${file_no_}'!"
index cf2e8ac..cf4aa51 100644 (file)
@@ -1,6 +1,6 @@
 set(whitespaces_ "[\t\n\r ]*")
 
-set(EXPECTED_FILES_COUNT "5")
+set(EXPECTED_FILES_COUNT "6")
 set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
 
 if(GENERATOR_TYPE STREQUAL "RPM")
@@ -39,3 +39,6 @@ elseif(GENERATOR_TYPE STREQUAL "DEB")
   set(EXPECTED_FILE_5 "TestDinfo-pkg-libs-dbgsym.ddeb")
   set(EXPECTED_FILE_CONTENT_5 ".*/usr/lib/debug/.build-id/.*\.debug.*")
 endif()
+
+set(EXPECTED_FILE_6 "TestDinfo-pkg*-appheaders.${PKG}")
+set(EXPECTED_FILE_CONTENT_6_LIST "/include;/include/test_lib.hpp")
index 161a36a..9ff1f8a 100644 (file)
@@ -1,7 +1,7 @@
 set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
 
-# PGI compiler doesn't add build id to binaries by default
-if(CMAKE_CXX_COMPILER_ID STREQUAL "PGI")
+# Some compilers do not add build id to binaries by default.
+if(CMAKE_CXX_COMPILER_ID MATCHES "^(IntelLLVM|PGI|NVHPC)$")
   string(APPEND CMAKE_EXE_LINKER_FLAGS "-Wl,--build-id")
   string(APPEND CMAKE_SHARED_LINKER_FLAGS "-Wl,--build-id")
 endif()
@@ -23,6 +23,7 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
 add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
 target_link_libraries(test_prog test_lib)
 
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/test_lib.hpp" DESTINATION include COMPONENT appheaders)
 install(TARGETS test_prog DESTINATION foo COMPONENT applications)
 install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
 install(TARGETS test_lib DESTINATION bas COMPONENT libs)
@@ -40,6 +41,10 @@ set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON)
 set(CPACK_DEBIAN_PACKAGE_NAME "Debuginfo")
 set(CPACK_DEBIAN_LIBS_DEBUGINFO_PACKAGE ON)
 
+# Test that a component with debug info requested but without any debug info produces none
+set(CPACK_RPM_APPHEADERS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_APPHEADERS_DEBUGINFO_PACKAGE ON)
+
 # test debuginfo package rename
 set(CPACK_RPM_DEBUGINFO_FILE_NAME
   "@cpack_component@-DebugInfoPackage.rpm")
diff --git a/Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt b/Tests/RunCMake/CPack/tests/EXTRA/DEB-stderr.txt
new file mode 100644 (file)
index 0000000..37360e8
--- /dev/null
@@ -0,0 +1,6 @@
+CPack Warning: Adding file to tar:
+#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/Linux/DEB/extra-0.1.1-Linux/bas
+#missing file: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/conffiles
+CPack Warning: Adding file to tar:
+#top level directory: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/_CPack_Packages/Linux/DEB/extra-0.1.1-Linux/foo
+#missing file: .*/Tests/RunCMake/DEB.EXTRA/CPack/EXTRA-build/conffiles
diff --git a/Tests/RunCMake/CPack/tests/THREADED/DEB-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/THREADED/DEB-Prerequirements.cmake
new file mode 100644 (file)
index 0000000..7b2692c
--- /dev/null
@@ -0,0 +1 @@
+set(CPACK_DEBIAN_COMPRESSION_TYPE xz)
index 78fc9e9..9e82e8c 100644 (file)
@@ -1,6 +1,6 @@
 install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
 
-set(CPACK_ARCHIVE_THREADS 2)
+set(CPACK_THREADS 2)
 
 if(PACKAGING_TYPE STREQUAL "COMPONENT")
   set(CPACK_COMPONENTS_ALL test)
diff --git a/Tests/RunCMake/CPack/tests/THREADED_ALL/DEB-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/THREADED_ALL/DEB-Prerequirements.cmake
new file mode 100644 (file)
index 0000000..7b2692c
--- /dev/null
@@ -0,0 +1 @@
+set(CPACK_DEBIAN_COMPRESSION_TYPE xz)
index 34051b8..6f37201 100644 (file)
@@ -1,6 +1,6 @@
 install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
 
-set(CPACK_ARCHIVE_THREADS 0)
+set(CPACK_THREADS 0)
 
 if(PACKAGING_TYPE STREQUAL "COMPONENT")
   set(CPACK_COMPONENTS_ALL test)
index ffc8f78..b81f319 100644 (file)
@@ -5,6 +5,7 @@ run_cmake(BeforeProject)
 unset(RunCMake_TEST_OPTIONS)
 
 run_cmake(NotOn)
+run_cmake(Site)
 
 function(run_CMakeCTestArguments)
   run_cmake_with_options(CMakeCTestArguments "-DCMAKE_CTEST_ARGUMENTS=--quiet\\;--output-log\\;output-log.txt")
diff --git a/Tests/RunCMake/CTest/Site.cmake b/Tests/RunCMake/CTest/Site.cmake
new file mode 100644 (file)
index 0000000..2c96f23
--- /dev/null
@@ -0,0 +1,5 @@
+include(CTest)
+get_property(site CACHE SITE PROPERTY VALUE)
+if(NOT "${site}" STREQUAL "${SITE}")
+  message(FATAL_ERROR "SITE is not a cache entry")
+endif()
index 97e2a10..b27da43 100644 (file)
@@ -1,4 +1,6 @@
 ^CMake Error at CTestTestfile.cmake:[0-9]+ \(subdirs\):
   subdirs called with incorrect number of arguments
 +
-Errors while running CTest$
+Errors while running CTest
+Output from these tests are in: .*/Testing/Temporary/LastTest.log
+Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.$
index e05ad79..6cf1476 100644 (file)
@@ -380,3 +380,20 @@ run_MemCheckSan(Leak "simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode
 run_MemCheckSan(Memory "simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode=55")
 run_MemCheckSan(Thread "report_bugs=1:history_size=5:exitcode=55")
 run_MemCheckSan(UndefinedBehavior "simulate_sanitizer=1")
+
+run_cmake_command(test-dir-invalid-arg ${CMAKE_CTEST_COMMAND} --test-dir)
+run_cmake_command(test-dir-non-existing-dir ${CMAKE_CTEST_COMMAND} --test-dir non-existing-dir)
+
+function(run_testDir)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/testDir)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/sub")
+  file(WRITE "${RunCMake_TEST_BINARY_DIR}/sub/CTestTestfile.cmake" "
+  add_test(Test1 \"${CMAKE_COMMAND}\" -E true)
+  add_test(Test2 \"${CMAKE_COMMAND}\" -E true)
+  ")
+  run_cmake_command(testDir ${CMAKE_CTEST_COMMAND} --test-dir "${RunCMake_TEST_BINARY_DIR}/sub")
+endfunction()
+run_testDir()
index 7593783..a993ac6 100644 (file)
@@ -1 +1,3 @@
-^Errors while running CTest$
+^Errors while running CTest
+Output from these tests are in: .*/Testing/Temporary/LastTest.log
+Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.$
diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-result.txt b/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-stderr.txt b/Tests/RunCMake/CTestCommandLine/test-dir-invalid-arg-stderr.txt
new file mode 100644 (file)
index 0000000..15908a7
--- /dev/null
@@ -0,0 +1 @@
+CMake Error: '--test-dir' requires an argument
diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-result.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt
new file mode 100644 (file)
index 0000000..017ccb0
--- /dev/null
@@ -0,0 +1 @@
+Failed to change working directory to ".*/non-existing-dir" : No such file or directory
diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt
new file mode 100644 (file)
index 0000000..ddcd238
--- /dev/null
@@ -0,0 +1 @@
+Internal ctest changing into directory: .*/non-existing-dir
index 960fe94..97833f5 100644 (file)
@@ -47,4 +47,15 @@ CMake Warning \(dev\) at [^
 Call Stack \(most recent call first\):
   CMP0075.cmake:41 \(check_include_files\)
   CMakeLists.txt:[0-9]+ \(include\)
-This warning is for project developers.  Use -Wno-dev to suppress it.$
+This warning is for project developers.  Use -Wno-dev to suppress it.
++
+CMake Deprecation Warning at CMP0075.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0075 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/ClangTidy/OBJC-Build-stdout.txt b/Tests/RunCMake/ClangTidy/OBJC-Build-stdout.txt
new file mode 100644 (file)
index 0000000..571ec02
--- /dev/null
@@ -0,0 +1 @@
+Tests[/\]RunCMake[/\]ClangTidy[/\]main\.m:0:0: warning: message \[checker\]
diff --git a/Tests/RunCMake/ClangTidy/OBJC-launch-Build-stdout.txt b/Tests/RunCMake/ClangTidy/OBJC-launch-Build-stdout.txt
new file mode 100644 (file)
index 0000000..571ec02
--- /dev/null
@@ -0,0 +1 @@
+Tests[/\]RunCMake[/\]ClangTidy[/\]main\.m:0:0: warning: message \[checker\]
diff --git a/Tests/RunCMake/ClangTidy/OBJC-launch.cmake b/Tests/RunCMake/ClangTidy/OBJC-launch.cmake
new file mode 100644 (file)
index 0000000..43e8521
--- /dev/null
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJC.cmake)
diff --git a/Tests/RunCMake/ClangTidy/OBJC.cmake b/Tests/RunCMake/ClangTidy/OBJC.cmake
new file mode 100644 (file)
index 0000000..43eae30
--- /dev/null
@@ -0,0 +1,3 @@
+enable_language(OBJC)
+set(CMAKE_OBJC_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
+add_executable(main main.m)
diff --git a/Tests/RunCMake/ClangTidy/OBJCXX-Build-stdout.txt b/Tests/RunCMake/ClangTidy/OBJCXX-Build-stdout.txt
new file mode 100644 (file)
index 0000000..cbc7629
--- /dev/null
@@ -0,0 +1 @@
+Tests[/\]RunCMake[/\]ClangTidy[/\]main\.mm:0:0: warning: message \[checker\]
diff --git a/Tests/RunCMake/ClangTidy/OBJCXX-launch-Build-stdout.txt b/Tests/RunCMake/ClangTidy/OBJCXX-launch-Build-stdout.txt
new file mode 100644 (file)
index 0000000..cbc7629
--- /dev/null
@@ -0,0 +1 @@
+Tests[/\]RunCMake[/\]ClangTidy[/\]main\.mm:0:0: warning: message \[checker\]
diff --git a/Tests/RunCMake/ClangTidy/OBJCXX-launch.cmake b/Tests/RunCMake/ClangTidy/OBJCXX-launch.cmake
new file mode 100644 (file)
index 0000000..5a54bff
--- /dev/null
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJCXX.cmake)
diff --git a/Tests/RunCMake/ClangTidy/OBJCXX.cmake b/Tests/RunCMake/ClangTidy/OBJCXX.cmake
new file mode 100644 (file)
index 0000000..ccc5c2c
--- /dev/null
@@ -0,0 +1,3 @@
+enable_language(OBJCXX)
+set(CMAKE_OBJCXX_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
+add_executable(main main.mm)
index 2f41e50..ee41d94 100644 (file)
@@ -16,8 +16,16 @@ endfunction()
 
 run_tidy(C)
 run_tidy(CXX)
+if (APPLE)
+  run_tidy(OBJC)
+  run_tidy(OBJCXX)
+endif()
 if (NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
   run_tidy(C-launch)
   run_tidy(CXX-launch)
+  if (APPLE)
+    run_tidy(OBJC-launch)
+    run_tidy(OBJCXX-launch)
+  endif()
 endif()
 run_tidy(C-bad)
diff --git a/Tests/RunCMake/ClangTidy/main.m b/Tests/RunCMake/ClangTidy/main.m
new file mode 100644 (file)
index 0000000..8488f4e
--- /dev/null
@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}
index e73d760..16f8be8 100644 (file)
@@ -1,3 +1,3 @@
 ^'--parallel' invalid number '12ab' given\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 94fc157..e7b9aaa 100644 (file)
@@ -1,3 +1,3 @@
 ^The <jobs> value is too large\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index e73d760..16f8be8 100644 (file)
@@ -1,3 +1,3 @@
 ^'--parallel' invalid number '12ab' given\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 8ed4fee..d1241f4 100644 (file)
@@ -1,3 +1,3 @@
 ^The <jobs> value requires a positive integer argument\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index c810087..d52b165 100644 (file)
@@ -1,3 +1,3 @@
 ^'-j' invalid number '12ab' given\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 94fc157..e7b9aaa 100644 (file)
@@ -1,3 +1,3 @@
 ^The <jobs> value is too large\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index c810087..d52b165 100644 (file)
@@ -1,3 +1,3 @@
 ^'-j' invalid number '12ab' given\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 8ed4fee..d1241f4 100644 (file)
@@ -1,3 +1,3 @@
 ^The <jobs> value requires a positive integer argument\.
 +
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 40d9bec..2dd9bc4 100644 (file)
@@ -1,2 +1,2 @@
 ^Error: Building 'clean' and other targets together is not supported\.
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 40d9bec..2dd9bc4 100644 (file)
@@ -1,2 +1,2 @@
 ^Error: Building 'clean' and other targets together is not supported\.
-Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 0570d8f..5992dcd 100644 (file)
@@ -1,2 +1,2 @@
 ^CMake Error: -C must be followed by a file name.
-CMake Error: Problem processing arguments. Aborting.$
+CMake Error: Run 'cmake --help' for all supported options.$
index 5e43bca..8503767 100644 (file)
@@ -1,2 +1,2 @@
 ^CMake Error: -D must be followed with VAR=VALUE.
-CMake Error: Problem processing arguments. Aborting.$
+CMake Error: Run 'cmake --help' for all supported options.$
index e24e131..c76c92d 100644 (file)
@@ -1 +1 @@
-^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":true,"version":{.*}}$
+^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$
diff --git a/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt b/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt
deleted file mode 100644 (file)
index 4dcbab9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-^CMake Error: Unknown argument for server mode$
diff --git a/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt b/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt
deleted file mode 100644 (file)
index 7193ba6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-^CMake Error: No pipe given after --pipe=$
diff --git a/Tests/RunCMake/CommandLine/E_server-result.txt b/Tests/RunCMake/CommandLine/E_server-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_server-stderr.txt b/Tests/RunCMake/CommandLine/E_server-stderr.txt
new file mode 100644 (file)
index 0000000..0cd0e56
--- /dev/null
@@ -0,0 +1 @@
+^CMake Error: CMake server mode has been removed in favor of the file-api\.$
diff --git a/Tests/RunCMake/CommandLine/InvalidArg1-result.txt b/Tests/RunCMake/CommandLine/InvalidArg1-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/InvalidArg1-stderr.txt b/Tests/RunCMake/CommandLine/InvalidArg1-stderr.txt
new file mode 100644 (file)
index 0000000..6b825bb
--- /dev/null
@@ -0,0 +1,2 @@
+^CMake Error: Unknown argument -invalid
+CMake Error: Run 'cmake --help' for all supported options.$
diff --git a/Tests/RunCMake/CommandLine/InvalidArg2-result.txt b/Tests/RunCMake/CommandLine/InvalidArg2-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/InvalidArg2-stderr.txt b/Tests/RunCMake/CommandLine/InvalidArg2-stderr.txt
new file mode 100644 (file)
index 0000000..eb1488c
--- /dev/null
@@ -0,0 +1,2 @@
+^CMake Error: Unknown argument --invalid
+CMake Error: Run 'cmake --help' for all supported options.$
index b23c8c2..51754fc 100644 (file)
@@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.1)
 include(RunCMake)
 
 run_cmake_command(NoArgs ${CMAKE_COMMAND})
+run_cmake_command(InvalidArg1 ${CMAKE_COMMAND} -invalid)
+run_cmake_command(InvalidArg2 ${CMAKE_COMMAND} --invalid)
 run_cmake_command(Wizard ${CMAKE_COMMAND} -i)
 run_cmake_command(C-no-arg ${CMAKE_COMMAND} -B DummyBuildDir -C)
 run_cmake_command(C-no-file ${CMAKE_COMMAND} -B DummyBuildDir -C nosuchcachefile.txt)
@@ -25,8 +27,7 @@ run_cmake_command(E_compare_files-ignore-eol-nonexistent ${CMAKE_COMMAND} -E com
 run_cmake_command(E_compare_files-invalid-arguments ${CMAKE_COMMAND} -E compare_files file1.txt file2.txt file3.txt)
 run_cmake_command(E_echo_append ${CMAKE_COMMAND} -E echo_append)
 run_cmake_command(E_rename-no-arg ${CMAKE_COMMAND} -E rename)
-run_cmake_command(E_server-arg ${CMAKE_COMMAND} -E server --extra-arg)
-run_cmake_command(E_server-pipe ${CMAKE_COMMAND} -E server --pipe=)
+run_cmake_command(E_server ${CMAKE_COMMAND} -E server)
 run_cmake_command(E_true ${CMAKE_COMMAND} -E true)
 run_cmake_command(E_true-extraargs ${CMAKE_COMMAND} -E true ignored)
 run_cmake_command(E_false ${CMAKE_COMMAND} -E false)
@@ -202,8 +203,8 @@ function(run_BuildDir)
   run_cmake_command(BuildDir--build--parallel-large ${CMAKE_COMMAND} -E chdir ..
     ${CMAKE_COMMAND} --build BuildDir-build --parallel 4294967293)
 
-  # No default jobs for Xcode and FreeBSD build command
-  if(NOT RunCMake_GENERATOR MATCHES "Xcode" AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+  # No default jobs for FreeBSD build command
+  if(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
     run_cmake_command(BuildDir--build-jobs-no-number ${CMAKE_COMMAND} -E chdir ..
       ${CMAKE_COMMAND} --build BuildDir-build -j)
     run_cmake_command(BuildDir--build-jobs-no-number-trailing--target ${CMAKE_COMMAND} -E chdir ..
@@ -672,6 +673,10 @@ set(RunCMake_TEST_OPTIONS -Wno-error=deprecated)
 run_cmake(Wno-error_deprecated)
 unset(RunCMake_TEST_OPTIONS)
 
+set(RunCMake_TEST_OPTIONS -Werror=deprecated -Wno-error=deprecated)
+run_cmake(Wno-error_deprecated)
+unset(RunCMake_TEST_OPTIONS)
+
 # Dev warnings should be on by default
 run_cmake(Wdev)
 
@@ -790,7 +795,7 @@ function(run_llvm_rc)
         "test.tmp was not deleted")
   endif()
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir")
-  run_cmake_command(llvm_rc_full_run ${CMAKE_COMMAND} -E cmake_llvm_rc ${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir/source_file test.tmp ${CMAKE_COMMAND} -E echo "This is a test" ++ ${CMAKE_COMMAND} -E copy test.tmp SOURCE_DIR/llvmrc.result )
+  run_cmake_command(llvm_rc_full_run ${CMAKE_COMMAND} -E cmake_llvm_rc ${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir/source_file test.tmp ${CMAKE_COMMAND} -E echo "This is a test" ++ ${LLVM_RC} -bad /FO SOURCE_DIR/llvmrc.result test.tmp )
   if(EXISTS ${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir/test.tmp)
       message(SEND_ERROR "${test} - FAILED:\n"
         "test.tmp was not deleted")
index c34ef94..20715cf 100644 (file)
@@ -1,2 +1,2 @@
 ^CMake Error: -U must be followed with VAR.
-CMake Error: Problem processing arguments. Aborting.$
+CMake Error: Run 'cmake --help' for all supported options.$
index 0c0f613..139511b 100644 (file)
@@ -1,2 +1,2 @@
 CMake Error: -W must be followed with \[no-\]<name>.
-CMake Error: Problem processing arguments. Aborting.
+CMake Error: Run 'cmake --help' for all supported options.
index cc643df..5d416fc 100644 (file)
@@ -1,2 +1,2 @@
 CMake Error: No warning name provided.
-CMake Error: Problem processing arguments. Aborting.
+CMake Error: Run 'cmake --help' for all supported options.
index cc643df..5d416fc 100644 (file)
@@ -1,2 +1,2 @@
 CMake Error: No warning name provided.
-CMake Error: Problem processing arguments. Aborting.
+CMake Error: Run 'cmake --help' for all supported options.
index 8d518f6..9b4d26b 100644 (file)
@@ -1 +1 @@
-^Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
+^Usage: cmake --build \[<dir> \| --preset <preset>\] \[options\] \[-- \[native-options\]\]
index 031478b..e0e3054 100644 (file)
@@ -3,8 +3,9 @@ if(EXISTS "${depend_make}")
   file(READ "${depend_make}" depend_make_content)
   string(REGEX REPLACE "\n+$" "" depend_make_content "${depend_make_content}")
   if(NOT depend_make_content MATCHES "
-CMakeFiles/DepTarget.dir/test.c.o: .*/Tests/RunCMake/CommandLine/cmake_depends/test.c
-CMakeFiles/DepTarget.dir/test.c.o: .*/Tests/RunCMake/CommandLine/cmake_depends/test.h$")
+CMakeFiles/DepTarget.dir/test.c.o: \\\\
+ .*/Tests/RunCMake/CommandLine/cmake_depends/test.c \\\\
+ .*/Tests/RunCMake/CommandLine/cmake_depends/test.h$")
     string(REPLACE "\n" "\n  " depend_make_content "  ${depend_make_content}")
     set(RunCMake_TEST_FAILED "depend.make does not have expected content:\n${depend_make_content}")
   endif()
index cb0d541..891e138 100644 (file)
@@ -10,7 +10,8 @@ function(check_files dir)
   set(actual)
   foreach(i IN LISTS glob)
     if(NOT i MATCHES "(\\.manifest$)|(\\.exp$)|(\\.tds$)")
-      list(APPEND actual ${i})
+      get_filename_component(real_path ${i} REALPATH)
+      list(APPEND actual ${real_path})
     endif()
   endforeach()
   list(REMOVE_DUPLICATES actual)
diff --git a/Tests/RunCMake/ExportCompileCommands/Properties.cmake b/Tests/RunCMake/ExportCompileCommands/Properties.cmake
new file mode 100644 (file)
index 0000000..c7a38b7
--- /dev/null
@@ -0,0 +1,22 @@
+enable_language(C)
+
+add_library(Unset STATIC empty.c)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+add_library(SetOn STATIC empty.c)
+set(CMAKE_EXPORT_COMPILE_COMMANDS OFF)
+add_library(SetOff STATIC empty.c)
+
+get_property(_set TARGET Unset PROPERTY EXPORT_COMPILE_COMMANDS)
+if(_set)
+  message(SEND_ERROR "EXPORT_COMPILE_COMMANDS property should be unset for Unset target (got \"${_set}\")")
+endif()
+
+get_property(_on TARGET SetOn PROPERTY EXPORT_COMPILE_COMMANDS)
+if(NOT _on STREQUAL "ON")
+  message(SEND_ERROR "EXPORT_COMPILE_COMMANDS property should be \"ON\" for SetOn target (got \"${_on}\")")
+endif()
+
+get_property(_off TARGET SetOff PROPERTY EXPORT_COMPILE_COMMANDS)
+if(NOT _off STREQUAL "OFF")
+  message(SEND_ERROR "EXPORT_COMPILE_COMMANDS property should be \"OFF\" for SetOff target (got \"${_off}\")")
+endif()
diff --git a/Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand-check.cmake b/Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand-check.cmake
new file mode 100644 (file)
index 0000000..d698742
--- /dev/null
@@ -0,0 +1,32 @@
+if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/compile_commands.json")
+  set(RunCMake_TEST_FAILED "compile_commands.json not generated")
+  return()
+endif()
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/compile_commands.json" compile_commands)
+
+macro(check_error)
+  if(error)
+    message(SEND_ERROR "Unexpected error \"${error}\"\nFor: ${compile_commands}")
+  endif()
+endmacro()
+
+string(JSON num_commands ERROR_VARIABLE error LENGTH "${compile_commands}")
+check_error()
+
+# Only one of the targets has the EXPORT_COMPILE_COMMANDS property enabled.
+if(NOT num_commands STREQUAL 1)
+  message(SEND_ERROR "Expected 1 compile command, got ${num_commands} for ${compile_commands}")
+endif()
+
+# Get the compile command generated.
+string(JSON result ERROR_VARIABLE error GET "${compile_commands}" 0)
+check_error()
+string(JSON result ERROR_VARIABLE error GET "${result}" file)
+check_error()
+
+# And ensure the correct target is in that compile command.
+cmake_path(COMPARE "${result}" EQUAL "${RunCMake_TEST_SOURCE_DIR}/expected_file.c" good)
+if(NOT good)
+  message(SEND_ERROR "Expected \"${result}\" in \"${RunCMake_TEST_SOURCE_DIR}/expected_file.c\"")
+endif()
diff --git a/Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand.cmake b/Tests/RunCMake/ExportCompileCommands/PropertiesGenerateCommand.cmake
new file mode 100644 (file)
index 0000000..46c8845
--- /dev/null
@@ -0,0 +1,7 @@
+enable_language(C)
+
+add_library(Unset STATIC empty.c)
+add_library(ToBeSet STATIC expected_file.c)
+
+# Only one target with EXPORT_COMPILE_COMMANDS property.
+set_property(TARGET ToBeSet PROPERTY EXPORT_COMPILE_COMMANDS TRUE)
index 9e7e732..b691637 100644 (file)
@@ -1,4 +1,12 @@
 include(RunCMake)
 
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
+else()
+  set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+endif()
+
 run_cmake_with_options(BeforeProject -DCMAKE_PROJECT_INCLUDE_BEFORE=BeforeProjectBEFORE.cmake)
 run_cmake(CustomCompileRule)
+run_cmake(Properties)
+run_cmake(PropertiesGenerateCommand)
diff --git a/Tests/RunCMake/ExportCompileCommands/expected_file.c b/Tests/RunCMake/ExportCompileCommands/expected_file.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/ExternalData/BadArguments-stderr.txt b/Tests/RunCMake/ExternalData/BadArguments-stderr.txt
new file mode 100644 (file)
index 0000000..44efe7e
--- /dev/null
@@ -0,0 +1,7 @@
+CMake Warning \(dev\) at .*/Modules/ExternalData.cmake:[0-9]+ \(message\):
+  Ignoring unrecognized arguments passed to ExternalData_add_target:
+  `UNKNOWN_ARGUMENT`
+Call Stack \(most recent call first\):
+  BadArguments.cmake:[0-9]+ \(ExternalData_Add_Target\)
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/ExternalData/BadArguments.cmake b/Tests/RunCMake/ExternalData/BadArguments.cmake
new file mode 100644 (file)
index 0000000..dad0007
--- /dev/null
@@ -0,0 +1,5 @@
+include(ExternalData)
+set(ExternalData_URL_TEMPLATES
+  "file:///path/to/%(algo)/%(hash)"
+  )
+ExternalData_Add_Target(Data UNKNOWN_ARGUMENT)
index b5ab22d..b4cc95e 100644 (file)
@@ -2,6 +2,7 @@ include(RunCMake)
 
 run_cmake(BadAlgoMap1)
 run_cmake(BadAlgoMap2)
+run_cmake(BadArguments)
 run_cmake(BadCustom1)
 run_cmake(BadCustom2)
 run_cmake(BadCustom3)
diff --git a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
new file mode 100644 (file)
index 0000000..887da0f
--- /dev/null
@@ -0,0 +1,19 @@
+file(TIMESTAMP "${STAMP_DIR}/proj1-configure" PROJ1_CONFIGURE_TIMESTAMP_AFTER "%s")
+# When BUILD_ALWAYS is set, the build stamp is never created.
+file(TIMESTAMP "${STAMP_DIR}/proj2-configure" PROJ2_CONFIGURE_TIMESTAMP_AFTER "%s")
+file(TIMESTAMP "${STAMP_DIR}/proj2-build" PROJ2_BUILD_TIMESTAMP_AFTER "%s")
+
+if(NOT PROJ1_CONFIGURE_TIMESTAMP_BEFORE EQUAL PROJ1_CONFIGURE_TIMESTAMP_AFTER)
+  set(RunCMake_TEST_FAILED "Unexpected rebuild of proj1 configure step (${PROJ1_CONFIGURE_TIMESTAMP_BEFORE} != ${PROJ1_CONFIGURE_TIMESTAMP_AFTER})")
+  return()
+endif()
+
+if(NOT PROJ2_CONFIGURE_TIMESTAMP_BEFORE EQUAL PROJ2_CONFIGURE_TIMESTAMP_AFTER)
+  set(RunCMake_TEST_FAILED "Unexpected rebuild of proj2 configure step (${PROJ2_CONFIGURE_TIMESTAMP_BEFORE} != ${PROJ2_CONFIGURE_TIMESTAMP_AFTER})")
+  return()
+endif()
+
+if(PROJ2_BUILD_TIMESTAMP_BEFORE EQUAL PROJ2_BUILD_TIMESTAMP_AFTER)
+  set(RunCMake_TEST_FAILED "proj2 build step did not rebuild (${PROJ2_BUILD_TIMESTAMP_BEFORE} != ${PROJ2_BUILD_TIMESTAMP_AFTER})")
+  return()
+endif()
diff --git a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake
new file mode 100644 (file)
index 0000000..6dbf0f4
--- /dev/null
@@ -0,0 +1,28 @@
+include(ExternalProject)
+
+# Given this setup, on the first build, both configure steps and both build
+# steps will run. On a noop rebuild, only the build steps will run. Without
+# CONFIGURE_HANDLED_BY_BUILD, the configure step of proj2 would also run on a
+# noop rebuild.
+
+ExternalProject_Add(proj1
+  DOWNLOAD_COMMAND ""
+  SOURCE_DIR ""
+  CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something"
+  # file(TIMESTAMP) gives back the timestamp in seconds so we sleep a second to
+  # make sure we get a different timestamp on the stamp file
+  BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1.125
+  INSTALL_COMMAND ""
+  BUILD_ALWAYS ON
+  STAMP_DIR "stamp"
+)
+ExternalProject_Add(proj2
+  DOWNLOAD_COMMAND ""
+  SOURCE_DIR ""
+  CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something"
+  BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1.125
+  INSTALL_COMMAND ""
+  CONFIGURE_HANDLED_BY_BUILD ON
+  DEPENDS proj1
+  STAMP_DIR "stamp"
+)
diff --git a/Tests/RunCMake/ExternalProject/FetchGitTags.cmake b/Tests/RunCMake/ExternalProject/FetchGitTags.cmake
new file mode 100644 (file)
index 0000000..37d1b40
--- /dev/null
@@ -0,0 +1,67 @@
+find_package(Git QUIET REQUIRED)
+
+include(ExternalProject)
+
+set(srcRepo ${CMAKE_CURRENT_BINARY_DIR}/srcRepo)
+set(srcDir  ${CMAKE_CURRENT_BINARY_DIR}/src)
+set(binDir  ${CMAKE_CURRENT_BINARY_DIR}/build)
+file(MAKE_DIRECTORY ${srcRepo})
+file(MAKE_DIRECTORY ${srcDir})
+
+file(GLOB entries ${srcRepo}/*)
+file(REMOVE_RECURSE ${entries} ${binDir})
+file(TOUCH ${srcRepo}/firstFile.txt)
+configure_file(${CMAKE_CURRENT_LIST_DIR}/FetchGitTags/CMakeLists.txt
+    ${srcDir}/CMakeLists.txt COPYONLY)
+
+function(execGitCommand)
+  execute_process(
+    WORKING_DIRECTORY ${srcRepo}
+    COMMAND ${GIT_EXECUTABLE} ${ARGN}
+    COMMAND_ECHO STDOUT
+    COMMAND_ERROR_IS_FATAL ANY
+  )
+endfunction()
+
+function(configureAndBuild tag)
+  execute_process(COMMAND ${CMAKE_COMMAND}
+      -G ${CMAKE_GENERATOR} -T "${CMAKE_GENERATOR_TOOLSET}"
+      -A "${CMAKE_GENERATOR_PLATFORM}"
+      -D repoDir:PATH=${srcRepo}
+      -D gitTag:STRING=${tag}
+      -B ${binDir}
+      -S ${srcDir}
+    COMMAND_ECHO STDOUT
+    COMMAND_ERROR_IS_FATAL ANY
+  )
+
+  execute_process(COMMAND ${CMAKE_COMMAND} --build ${binDir} --target fetcher
+    WORKING_DIRECTORY ${binDir}
+    COMMAND_ECHO STDOUT
+    COMMAND_ERROR_IS_FATAL ANY
+  )
+endfunction()
+
+# Setup a fresh source repo with a predictable default branch across all
+# git versions
+execGitCommand(-c init.defaultBranch=master init)
+execGitCommand(config --add user.email "testauthor@cmake.org")
+execGitCommand(config --add user.name testauthor)
+
+# Create the initial repo structure
+execGitCommand(add firstFile.txt)
+execGitCommand(commit -m "First file")
+
+message(STATUS "First configure-and-build")
+configureAndBuild(master)
+
+# Create a tagged commit that is not on any branch. With git 2.20 or later,
+# this commit won't be fetched without the --tags option.
+file(TOUCH ${srcRepo}/secondFile.txt)
+execGitCommand(add secondFile.txt)
+execGitCommand(commit -m "Second file")
+execGitCommand(tag -a -m "Adding tag" tag_of_interest)
+execGitCommand(reset --hard HEAD~1)
+
+message(STATUS "Second configure-and-build")
+configureAndBuild(tag_of_interest)
diff --git a/Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt b/Tests/RunCMake/ExternalProject/FetchGitTags/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d9a380c
--- /dev/null
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.19)
+project(FetchTags LANGUAGES NONE)
+
+include(ExternalProject)
+
+# repoDir and gitTag are expected to be set as cache variables
+
+ExternalProject_Add(fetcher
+    GIT_REPOSITORY ${repoDir}
+    GIT_TAG ${gitTag}
+    GIT_REMOTE_UPDATE_STRATEGY CHECKOUT
+    CONFIGURE_COMMAND ""
+    BUILD_COMMAND ""
+    INSTALL_COMMAND ""
+)
diff --git a/Tests/RunCMake/ExternalProject/IncludeScope-Add-stderr.txt b/Tests/RunCMake/ExternalProject/IncludeScope-Add-stderr.txt
deleted file mode 100644 (file)
index ff3e5c1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-^CMake Error at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\):
-  error: ExternalProject module must be explicitly included before using
-  ExternalProject_Add function
-Call Stack \(most recent call first\):
-  .*/Modules/ExternalProject.cmake:[0-9]+ \(_ep_parse_arguments\)
-  IncludeScope-Add.cmake:[0-9]+ \(ExternalProject_Add\)
-  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/ExternalProject/IncludeScope-Add.cmake b/Tests/RunCMake/ExternalProject/IncludeScope-Add.cmake
deleted file mode 100644 (file)
index 1061ffd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-function(IncludeScope_IncludeOnly)
-  include(ExternalProject)
-endfunction()
-
-IncludeScope_IncludeOnly()
-
-ExternalProject_Add(MyProj
-    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
-    CONFIGURE_COMMAND ""
-    BUILD_COMMAND     ""
-    INSTALL_COMMAND   ""
-)
diff --git a/Tests/RunCMake/ExternalProject/IncludeScope-Add_Step-stderr.txt b/Tests/RunCMake/ExternalProject/IncludeScope-Add_Step-stderr.txt
deleted file mode 100644 (file)
index cbad4be..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-^CMake Error at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\):
-  error: ExternalProject module must be explicitly included before using
-  ExternalProject_Add_Step function
-Call Stack \(most recent call first\):
-  .*/Modules/ExternalProject.cmake:[0-9]+ \(_ep_parse_arguments\)
-  IncludeScope-Add_Step.cmake:[0-9]+ \(ExternalProject_Add_Step\)
-  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/ExternalProject/IncludeScope-Add_Step.cmake b/Tests/RunCMake/ExternalProject/IncludeScope-Add_Step.cmake
deleted file mode 100644 (file)
index 2a820f8..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-function(IncludeScope_DefineProj)
-  include(ExternalProject)
-  ExternalProject_Add(MyProj
-    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
-    CONFIGURE_COMMAND ""
-    BUILD_COMMAND     ""
-    INSTALL_COMMAND   ""
-  )
-endfunction()
-
-IncludeScope_DefineProj()
-
-ExternalProject_Add_Step(MyProj extraStep COMMENT "Foo")
index 598671f..3205dd5 100644 (file)
@@ -8,8 +8,6 @@ unset(ENV{https_proxy})
 
 run_cmake(BadIndependentStep1)
 run_cmake(BadIndependentStep2)
-run_cmake(IncludeScope-Add)
-run_cmake(IncludeScope-Add_Step)
 run_cmake(NoOptions)
 run_cmake(SourceEmpty)
 run_cmake(SourceMissing)
@@ -151,3 +149,42 @@ endif()
 if(doSubstitutionTest)
     __ep_test_with_build(Substitutions)
 endif()
+
+function(__ep_test_CONFIGURE_HANDLED_BY_BUILD)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CONFIGURE_HANDLED_BY_BUILD-build)
+  run_cmake(CONFIGURE_HANDLED_BY_BUILD)
+
+  if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(BUILD_CONFIG --config Debug)
+    set(STAMP_DIR "${RunCMake_TEST_BINARY_DIR}/stamp/Debug")
+  else()
+    set(BUILD_CONFIG "")
+    set(STAMP_DIR "${RunCMake_TEST_BINARY_DIR}/stamp")
+  endif()
+
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(CONFIGURE_HANDLED_BY_BUILD-build ${CMAKE_COMMAND} --build . ${BUILD_CONFIG})
+
+  # Calculate timestamps before rebuilding so we can compare before and after in
+  # CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
+
+  file(TIMESTAMP "${STAMP_DIR}/proj1-configure" PROJ1_CONFIGURE_TIMESTAMP_BEFORE "%s")
+  # When BUILD_ALWAYS is set, the build stamp is never created.
+  file(TIMESTAMP "${STAMP_DIR}/proj2-configure" PROJ2_CONFIGURE_TIMESTAMP_BEFORE "%s")
+  file(TIMESTAMP "${STAMP_DIR}/proj2-build" PROJ2_BUILD_TIMESTAMP_BEFORE "%s")
+
+  run_cmake_command(CONFIGURE_HANDLED_BY_BUILD-rebuild ${CMAKE_COMMAND} --build . ${BUILD_CONFIG})
+endfunction()
+
+if(NOT RunCMake_GENERATOR MATCHES "Visual Studio 9 ")
+  __ep_test_CONFIGURE_HANDLED_BY_BUILD()
+endif()
+
+find_package(Git QUIET)
+if(GIT_EXECUTABLE)
+  # Note that there appear to be differences in where git writes its output to
+  # on some platforms. It may go to stdout or stderr, so force it to be merged.
+  set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+  run_cmake(FetchGitTags)
+  set(RunCMake_TEST_OUTPUT_MERGE FALSE)
+endif()
index 4449ff1..ae3d179 100644 (file)
@@ -24,6 +24,7 @@ function(check_python case)
   file(GLOB index ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply/index-*.json)
   execute_process(
     COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/${case}-check.py" "${index}" "${CMAKE_CXX_COMPILER_ID}"
+      "${RunCMake_TEST_BINARY_DIR}"
     RESULT_VARIABLE result
     OUTPUT_VARIABLE output
     ERROR_VARIABLE output
@@ -50,7 +51,9 @@ run_cmake(ClientStateful)
 
 function(run_object object)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${object}-build)
+  list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0118=NEW)
   run_cmake(${object})
+  list(POP_BACK RunCMake_TEST_OPTIONS)
   set(RunCMake_TEST_NO_CLEAN 1)
   run_cmake_command(${object}-SharedStateless ${CMAKE_COMMAND} .)
   run_cmake_command(${object}-ClientStateless ${CMAKE_COMMAND} .)
@@ -60,3 +63,4 @@ endfunction()
 run_object(codemodel-v2)
 run_object(cache-v2)
 run_object(cmakeFiles-v1)
+run_object(toolchains-v1)
index c66757f..df2410a 100644 (file)
@@ -608,7 +608,7 @@ def gen_check_targets(c, g, inSource):
         read_codemodel_json_data("targets/generated_exe.json"),
     ]
 
-    if cxx_compiler_id in ['Clang', 'AppleClang', 'GNU', 'Intel', 'MSVC', 'Embarcadero'] and g["name"] != "Xcode":
+    if cxx_compiler_id in ['Clang', 'AppleClang', 'GNU', 'Intel', 'IntelLLVM', 'MSVC', 'Embarcadero'] and g["name"] != "Xcode":
         for e in expected:
             if e["name"] == "cxx_exe":
                 if matches(g["name"], "^(Visual Studio |Ninja Multi-Config)"):
index a7106fc..483ae79 100644 (file)
@@ -7,7 +7,7 @@
     "isGeneratorProvided": null,
     "sources": [
         {
-            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/custom_tgt$",
+            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/custom_tgt(-(Debug|Release|RelWithDebInfo|MinSizeRel))?$",
             "isGenerated": true,
             "sourceGroupName": "",
             "compileGroupLanguage": null,
@@ -27,7 +27,7 @@
             ]
         },
         {
-            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(custom/)?CMakeFiles/([0-9a-f]+/)?custom_tgt\\.rule$",
+            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(custom/)?CMakeFiles/([0-9a-f]+/)?custom_tgt(-\\(CONFIG\\))?\\.rule$",
             "isGenerated": true,
             "sourceGroupName": "CMake Rules",
             "compileGroupLanguage": null,
         {
             "name": "",
             "sourcePaths": [
-                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/custom_tgt$"
+                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/custom_tgt(-(Debug|Release|RelWithDebInfo|MinSizeRel))?$"
             ]
         },
         {
             "name": "CMake Rules",
             "sourcePaths": [
-                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(custom/)?CMakeFiles/([0-9a-f]+/)?custom_tgt\\.rule$"
+                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(custom/)?CMakeFiles/([0-9a-f]+/)?custom_tgt(-\\(CONFIG\\))?\\.rule$"
             ]
         }
     ],
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
new file mode 100644 (file)
index 0000000..ce38461
--- /dev/null
@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/query.json
+  reply
+  reply/index-[0-9.T-]+.json
+  reply/toolchains-v1-[0-9a-f]+.json
+  )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake
new file mode 100644 (file)
index 0000000..ca62edf
--- /dev/null
@@ -0,0 +1,4 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[
+{ "requests": [ { "kind": "toolchains", "version" : 1 } ] }
+]])
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake
new file mode 100644 (file)
index 0000000..4676dd8
--- /dev/null
@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/toolchains-v1
+  reply
+  reply/index-[0-9.T-]+.json
+  reply/toolchains-v1-[0-9a-f]+.json
+  )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake
new file mode 100644 (file)
index 0000000..7edff93
--- /dev/null
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/toolchains-v1" "")
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake
new file mode 100644 (file)
index 0000000..8e83758
--- /dev/null
@@ -0,0 +1,10 @@
+set(expect
+  query
+  query/toolchains-v1
+  reply
+  reply/index-[0-9.T-]+.json
+  reply/toolchains-v1-[0-9a-f]+.json
+  )
+check_api("^${expect}$")
+
+check_python(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake
new file mode 100644 (file)
index 0000000..2db73a1
--- /dev/null
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/toolchains-v1" "")
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-check.py b/Tests/RunCMake/FileAPI/toolchains-v1-check.py
new file mode 100644 (file)
index 0000000..a0e50c2
--- /dev/null
@@ -0,0 +1,86 @@
+from check_index import *
+import os
+
+class ExpectedVar(object):
+    def __init__(self, name):
+        self.name = name
+
+class ExpectedList(object):
+    def __init__(self, name):
+        self.name = name
+
+EXPECTED_TOOLCHAIN = {
+    "language": "CXX",
+    "compiler": {
+        "path": ExpectedVar("CMAKE_CXX_COMPILER"),
+        "id": ExpectedVar("CMAKE_CXX_COMPILER_ID"),
+        "version": ExpectedVar("CMAKE_CXX_COMPILER_VERSION"),
+        "target": ExpectedVar("CMAKE_CXX_COMPILER_TARGET"),
+        "implicit": {
+            "includeDirectories": \
+                ExpectedList("CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES"),
+            "linkDirectories": \
+                ExpectedList("CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES"),
+            "linkFrameworkDirectories": \
+                ExpectedList(
+                    "CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"),
+            "linkLibraries": \
+                ExpectedList("CMAKE_CXX_IMPLICIT_LINK_LIBRARIES"),
+        }
+    },
+    "sourceFileExtensions": \
+        ExpectedList("CMAKE_CXX_SOURCE_FILE_EXTENSIONS"),
+}
+
+def check_objects(o):
+    assert is_list(o)
+    assert len(o) == 1
+    check_index_object(o[0], "toolchains", 1, 0, check_object_toolchains)
+
+def check_object_toolchains(o):
+    assert sorted(o.keys()) == ["kind", "toolchains", "version"]
+    # The "kind" and "version" members are handled by check_index_object.
+    toolchains = o["toolchains"]
+    assert is_list(toolchains)
+
+    # Other platform-specific toolchains may exist (like RC on Windows).
+    has_cxx_toolchain = False
+    for toolchain in toolchains:
+        assert is_dict(toolchain)
+        assert "language" in toolchain
+        if toolchain["language"] == "CXX":
+            check_object_toolchain(toolchain, EXPECTED_TOOLCHAIN)
+            has_cxx_toolchain = True
+
+    assert has_cxx_toolchain
+
+def check_object_toolchain(o, expected):
+    expected_keys = [
+        key for (key, value) in expected.items()
+        if is_string(value) or is_dict(value)
+            or (type(value) in (ExpectedVar, ExpectedList)
+                and variables[value.name]["defined"])]
+    assert sorted(o.keys()) == sorted(expected_keys)
+
+    for key in expected_keys:
+        value = expected[key]
+        if is_string(value):
+            assert o[key] == value
+        elif is_dict(value):
+            check_object_toolchain(o[key], value)
+        elif type(value) == ExpectedVar:
+            assert o[key] == variables[value.name]["value"]
+        elif type(value) == ExpectedList:
+            expected_items = filter(
+                None, variables[value.name]["value"].split(";"))
+            check_list_match(lambda a, b: a == b, o[key], expected_items)
+        else:
+            assert False
+
+with open(os.path.join(sys.argv[3], "toolchain_variables.json")) as f:
+    variables = json.load(f)
+
+assert is_dict(variables)
+assert is_dict(index)
+assert sorted(index.keys()) == ["cmake", "objects", "reply"]
+check_objects(index["objects"])
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1.cmake b/Tests/RunCMake/FileAPI/toolchains-v1.cmake
new file mode 100644 (file)
index 0000000..367aade
--- /dev/null
@@ -0,0 +1,22 @@
+enable_language(CXX)
+
+set(variable_suffixes
+  COMPILER COMPILER_ID COMPILER_VERSION COMPILER_TARGET
+  IMPLICIT_INCLUDE_DIRECTORIES IMPLICIT_LINK_DIRECTORIES
+  IMPLICIT_LINK_FRAMEWORK_DIRECTORIES IMPLICIT_LINK_LIBRARIES
+  SOURCE_FILE_EXTENSIONS)
+set(language CXX)
+set(json "{}")
+
+foreach(variable_suffix ${variable_suffixes})
+  set(variable "CMAKE_${language}_${variable_suffix}")
+  string(JSON json SET "${json}" "${variable}" "{}")
+  if(DEFINED "${variable}")
+    string(JSON json SET "${json}" "${variable}" "defined" "true")
+    string(JSON json SET "${json}" "${variable}" "value" "\"${${variable}}\"")
+  else()
+    string(JSON json SET "${json}" "${variable}" "defined" "false")
+  endif()
+endforeach()
+
+file(WRITE ${CMAKE_BINARY_DIR}/toolchain_variables.json "${json}")
diff --git a/Tests/RunCMake/File_Configure/AtOnly.cmake b/Tests/RunCMake/File_Configure/AtOnly.cmake
new file mode 100644 (file)
index 0000000..cc5304a
--- /dev/null
@@ -0,0 +1,12 @@
+set(file_name  ${CMAKE_CURRENT_BINARY_DIR}/atonly.txt)
+set(var_a "a")
+set(var_b "b")
+file(CONFIGURE
+    OUTPUT ${file_name}
+    CONTENT "-->@var_a@<-- -->${var_b}<--"
+    @ONLY
+)
+file(READ ${file_name} file_content)
+if(NOT file_content STREQUAL "-->a<-- -->${var_b}<--")
+    message(FATAL_ERROR "@ONLY doesn't work")
+endif()
diff --git a/Tests/RunCMake/File_Configure/BadArg-stderr.txt b/Tests/RunCMake/File_Configure/BadArg-stderr.txt
deleted file mode 100644 (file)
index 5423a28..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-CMake Error at BadArg.cmake:[0-9]+ \(file\):
-  file Incorrect arguments to CONFIGURE subcommand.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/File_Configure/BadArgContent-result.txt b/Tests/RunCMake/File_Configure/BadArgContent-result.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt b/Tests/RunCMake/File_Configure/BadArgContent-stderr.txt
new file mode 100644 (file)
index 0000000..a6ea314
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at BadArgContent.cmake:[0-9]+ \(file\):
+  file CONFIGURE CONTENT option needs a value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/File_Configure/BadArgContent.cmake b/Tests/RunCMake/File_Configure/BadArgContent.cmake
new file mode 100644 (file)
index 0000000..282dc18
--- /dev/null
@@ -0,0 +1 @@
+file(CONFIGURE CONTENT)
diff --git a/Tests/RunCMake/File_Configure/BadArgOutput-result.txt b/Tests/RunCMake/File_Configure/BadArgOutput-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt b/Tests/RunCMake/File_Configure/BadArgOutput-stderr.txt
new file mode 100644 (file)
index 0000000..b5a924c
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at BadArgOutput.cmake:[0-9]+ \(file\):
+  file CONFIGURE OUTPUT option needs a value.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/File_Configure/EscapeQuotes.cmake b/Tests/RunCMake/File_Configure/EscapeQuotes.cmake
new file mode 100644 (file)
index 0000000..1136c87
--- /dev/null
@@ -0,0 +1,12 @@
+set(file_name  ${CMAKE_CURRENT_BINARY_DIR}/escape_quotes.txt)
+set(var "\t")
+set(ref "${var}")
+file(CONFIGURE
+    CONTENT "-->@ref@<--"
+    OUTPUT ${file_name}
+    ESCAPE_QUOTES
+)
+file(READ ${file_name} file_content)
+if(NOT file_content MATCHES "^-->\t<--$")
+    message(FATAL_ERROR "ESCAPE_QUOTES doesn't work")
+endif()
index e384873..5e35e5c 100644 (file)
@@ -1,10 +1,13 @@
 set(file_name  ${CMAKE_CURRENT_BINARY_DIR}/NewLineStyle.txt)
 
 function(test_eol style in out)
+    if (style)
+      set(newline_stle NEWLINE_STYLE ${style})
+    endif()
     file(CONFIGURE
         OUTPUT ${file_name}
         CONTENT "@in@"
-        NEWLINE_STYLE ${style}
+        ${newline_stle}
     )
     file(READ ${file_name} new HEX)
     if(NOT "${new}" STREQUAL "${out}")
@@ -18,3 +21,9 @@ test_eol(CRLF  "c" "630d0a")
 
 test_eol(UNIX  "d" "640a")
 test_eol(LF    "e" "650a")
+
+if (WIN32)
+    test_eol("" "a\nb" "610d0a62")
+elseif(UNIX)
+    test_eol("" "a\nb" "610a62")
+endif()
index e79de79..5022985 100644 (file)
@@ -1,10 +1,14 @@
 include(RunCMake)
 
 run_cmake(AngleBracketsContent)
-run_cmake(BadArg)
+run_cmake(BadArgOutput)
+run_cmake(BadArgContent)
 run_cmake(BadArgGeneratorExpressionOutput)
+run_cmake(UnrecognizedArgs)
 run_cmake(DirOutput)
 run_cmake(NewLineStyle-NoArg)
 run_cmake(NewLineStyle-ValidArg)
 run_cmake(NewLineStyle-WrongArg)
 run_cmake(SubDir)
+run_cmake(AtOnly)
+run_cmake(EscapeQuotes)
diff --git a/Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt b/Tests/RunCMake/File_Configure/UnrecognizedArgs-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt b/Tests/RunCMake/File_Configure/UnrecognizedArgs-stderr.txt
new file mode 100644 (file)
index 0000000..1dd1a20
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at UnrecognizedArgs.cmake:[0-9]+ \(file\):
+  file CONFIGURE Unrecognized argument: "INPUT"
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake b/Tests/RunCMake/File_Configure/UnrecognizedArgs.cmake
new file mode 100644 (file)
index 0000000..93ea7b5
--- /dev/null
@@ -0,0 +1 @@
+file(CONFIGURE INPUT)
diff --git a/Tests/RunCMake/File_Generate/CustomFilePermissions.cmake b/Tests/RunCMake/File_Generate/CustomFilePermissions.cmake
new file mode 100644 (file)
index 0000000..0000ef9
--- /dev/null
@@ -0,0 +1,15 @@
+file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/customfilepermissions.txt")
+
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/customfilepermissions.txt"
+  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+  FILE_PERMISSIONS
+    OWNER_READ OWNER_WRITE OWNER_EXECUTE
+    GROUP_EXECUTE
+    WORLD_EXECUTE
+  )
+
+add_custom_target(checkCustomFilePermissions ALL
+  COMMAND ${CMAKE_COMMAND}
+    -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/customfilepermissions.txt
+    -P "${CMAKE_CURRENT_SOURCE_DIR}/CustomFilePermissionsVerify.cmake"
+  )
diff --git a/Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake b/Tests/RunCMake/File_Generate/CustomFilePermissionsVerify.cmake
new file mode 100644 (file)
index 0000000..a87e916
--- /dev/null
@@ -0,0 +1,36 @@
+if(NOT EXISTS "${generatedFile}")
+  message(SEND_ERROR "Missing file:\n  ${generatedFile}")
+endif()
+
+if (UNIX)
+  find_program(STAT_EXECUTABLE NAMES stat)
+  if(NOT STAT_EXECUTABLE)
+    return()
+  endif()
+
+  if (CMAKE_HOST_SYSTEM_NAME MATCHES "FreeBSD")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${generatedFile}"
+      OUTPUT_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  elseif (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${generatedFile}"
+      OUTPUT_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  else()
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${generatedFile}"
+      OUTPUT_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  endif()
+
+  if (NOT output EQUAL "711")
+    message(SEND_ERROR "file generate has different permissions source "
+          "permissions: \"${output}\" desired permissions: \"711\"")
+  endif()
+
+endif()
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-Default.cmake b/Tests/RunCMake/File_Generate/NewLineStyle-Default.cmake
new file mode 100644 (file)
index 0000000..9df8ffe
--- /dev/null
@@ -0,0 +1,35 @@
+function(generate_from_file in out)
+  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/file_ip.txt "${in}")
+  file(GENERATE
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/file_op.txt
+    INPUT ${CMAKE_CURRENT_BINARY_DIR}/file_ip.txt
+    )
+
+  add_custom_target(verifyContentFromFile ALL
+    COMMAND ${CMAKE_COMMAND}
+      -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/file_op.txt
+      -DexpectedContent=${out}
+      -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyContent.cmake"
+    )
+endfunction()
+
+function(generate_from_content in out)
+  file(GENERATE
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/content_op.txt
+    CONTENT ${in}
+    )
+
+  add_custom_target(verifyContentFromContent ALL
+    COMMAND ${CMAKE_COMMAND}
+      -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/content_op.txt
+      -DexpectedContent=${out}
+      -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyContent.cmake"
+    )
+endfunction()
+
+if (WIN32)
+  generate_from_file("a" "610d0a") # 62->b, 0d0a->\r\n
+elseif(UNIX)
+  generate_from_file("a" "610a") # 62->b, 0a->\n
+endif()
+generate_from_content("a" "61")
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-result.txt b/Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-stderr.txt b/Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg-stderr.txt
new file mode 100644 (file)
index 0000000..44e32d0
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at NewLineStyle-InvalidArg.cmake:[0-9]+ \(file\):
+  file GENERATE NEWLINE_STYLE sets an unknown style, only LF, CRLF, UNIX,
+  DOS, and WIN32 are supported
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg.cmake b/Tests/RunCMake/File_Generate/NewLineStyle-InvalidArg.cmake
new file mode 100644 (file)
index 0000000..578cf21
--- /dev/null
@@ -0,0 +1,7 @@
+file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+  CONTENT "int main() { return 0; }\n"
+  NEWLINE_STYLE FOO
+  )
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-result.txt b/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt b/Tests/RunCMake/File_Generate/NewLineStyle-NoArg-stderr.txt
new file mode 100644 (file)
index 0000000..bc71f2f
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at NewLineStyle-NoArg.cmake:[0-9]+ \(file\):
+  file Incorrect arguments to GENERATE subcommand.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-NoArg.cmake b/Tests/RunCMake/File_Generate/NewLineStyle-NoArg.cmake
new file mode 100644 (file)
index 0000000..9bd2ffa
--- /dev/null
@@ -0,0 +1,7 @@
+file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+  CONTENT "int main() { return 0; }\n"
+  NEWLINE_STYLE
+  )
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-Unix.cmake b/Tests/RunCMake/File_Generate/NewLineStyle-Unix.cmake
new file mode 100644 (file)
index 0000000..7c26217
--- /dev/null
@@ -0,0 +1,33 @@
+function(generate_from_file in out)
+  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/file_ip.txt "${in}")
+  file(GENERATE
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/file_op.txt
+    INPUT ${CMAKE_CURRENT_BINARY_DIR}/file_ip.txt
+    NEWLINE_STYLE UNIX
+    )
+
+  add_custom_target(verifyContentFromFile ALL
+    COMMAND ${CMAKE_COMMAND}
+      -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/file_op.txt
+      -DexpectedContent=${out}
+      -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyContent.cmake"
+    )
+endfunction()
+
+function(generate_from_content in out)
+  file(GENERATE
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/content_op.txt
+    CONTENT ${in}
+    NEWLINE_STYLE UNIX
+    )
+
+  add_custom_target(verifyContentFromContent ALL
+    COMMAND ${CMAKE_COMMAND}
+      -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/content_op.txt
+      -DexpectedContent=${out}
+      -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyContent.cmake"
+    )
+endfunction()
+
+generate_from_file("a" "610a") # 62->b, 0a->\n
+generate_from_content("a" "610a")
diff --git a/Tests/RunCMake/File_Generate/NewLineStyle-Win32.cmake b/Tests/RunCMake/File_Generate/NewLineStyle-Win32.cmake
new file mode 100644 (file)
index 0000000..394ef75
--- /dev/null
@@ -0,0 +1,33 @@
+function(generate_from_file in out)
+  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/file_ip.txt "${in}")
+  file(GENERATE
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/file_op.txt
+    INPUT ${CMAKE_CURRENT_BINARY_DIR}/file_ip.txt
+    NEWLINE_STYLE WIN32
+    )
+
+  add_custom_target(verifyContentFromFile ALL
+    COMMAND ${CMAKE_COMMAND}
+      -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/file_op.txt
+      -DexpectedContent=${out}
+      -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyContent.cmake"
+    )
+endfunction()
+
+function(generate_from_content in out)
+  file(GENERATE
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/content_op.txt
+    CONTENT ${in}
+    NEWLINE_STYLE WIN32
+    )
+
+  add_custom_target(verifyContentFromContent ALL
+    COMMAND ${CMAKE_COMMAND}
+      -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/content_op.txt
+      -DexpectedContent=${out}
+      -P "${CMAKE_CURRENT_SOURCE_DIR}/VerifyContent.cmake"
+    )
+endfunction()
+
+generate_from_file("a" "610d0a") # 62->b, 0d0a->\r\n
+generate_from_content("a" "610d0a")
diff --git a/Tests/RunCMake/File_Generate/NoSourcePermissions.cmake b/Tests/RunCMake/File_Generate/NoSourcePermissions.cmake
new file mode 100644 (file)
index 0000000..868a045
--- /dev/null
@@ -0,0 +1,10 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/nosourcepermissions.txt"
+  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+  NO_SOURCE_PERMISSIONS
+  )
+
+add_custom_target(checkNoSourcePermission ALL
+  COMMAND ${CMAKE_COMMAND}
+    -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/nosourcepermissions.txt
+    -P "${CMAKE_CURRENT_SOURCE_DIR}/NoSourcePermissionsVerify.cmake"
+  )
diff --git a/Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake b/Tests/RunCMake/File_Generate/NoSourcePermissionsVerify.cmake
new file mode 100644 (file)
index 0000000..7981ccc
--- /dev/null
@@ -0,0 +1,36 @@
+if(NOT EXISTS "${generatedFile}")
+  message(SEND_ERROR "Missing generated file:\n  ${generatedFile}")
+endif()
+
+if (UNIX)
+  find_program(STAT_EXECUTABLE NAMES stat)
+  if(NOT STAT_EXECUTABLE)
+    return()
+  endif()
+
+  if (CMAKE_HOST_SYSTEM_NAME MATCHES "FreeBSD")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${generatedFile}"
+      OUTPUT_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${generatedFile}"
+      OUTPUT_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  else()
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${generatedFile}"
+      OUTPUT_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  endif()
+
+  if (NOT output EQUAL "644")
+    message(SEND_ERROR "generated file has different permissions than "
+        "desired, generated permissions: \"${output}\"")
+  endif()
+
+endif()
index 48fb71c..be3bf04 100644 (file)
@@ -123,3 +123,35 @@ set(RunCMake_TEST_NO_CLEAN 1)
 run_cmake_command(AdjacentInOut-nowork ${CMAKE_COMMAND} --build .)
 unset(RunCMake_TEST_BINARY_DIR)
 unset(RunCMake_TEST_NO_CLEAN)
+
+run_cmake(SourcePermissions1)
+run_cmake(SourcePermissions2)
+run_cmake(SourcePermissions3)
+run_cmake(SourcePermissions4)
+run_cmake(SourcePermissions5)
+
+function(run_cmake_and_verify_after_build case)
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${case}-build")
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
+  else()
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+  endif()
+  run_cmake(${case})
+  run_cmake_command("${case}-build" ${CMAKE_COMMAND} --build .)
+  unset(RunCMake_TEST_NO_CLEAN)
+  unset(RunCMake_TEST_BINARY_DIR)
+endfunction()
+
+run_cmake_and_verify_after_build(NoSourcePermissions)
+run_cmake_and_verify_after_build(UseSourcePermissions)
+run_cmake_and_verify_after_build(CustomFilePermissions)
+
+run_cmake(NewLineStyle-NoArg)
+run_cmake(NewLineStyle-InvalidArg)
+run_cmake_and_verify_after_build(NewLineStyle-Default)
+run_cmake_and_verify_after_build(NewLineStyle-Unix)
+run_cmake_and_verify_after_build(NewLineStyle-Win32)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions1-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions1-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions1-stderr.txt
new file mode 100644 (file)
index 0000000..730800d
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissions1.cmake:[0-9]+ \(file\):
+  file given both NO_SOURCE_PERMISSIONS and USE_SOURCE_PERMISSIONS.  Only one
+  option allowed.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions1.cmake b/Tests/RunCMake/File_Generate/SourcePermissions1.cmake
new file mode 100644 (file)
index 0000000..d25e66a
--- /dev/null
@@ -0,0 +1,5 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission1.txt"
+  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+  NO_SOURCE_PERMISSIONS
+  USE_SOURCE_PERMISSIONS
+  )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions2-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions2-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions2-stderr.txt
new file mode 100644 (file)
index 0000000..e8184cc
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissions2.cmake:[0-9]+ \(file\):
+  file given both NO_SOURCE_PERMISSIONS and FILE_PERMISSIONS.  Only one
+  option allowed.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions2.cmake b/Tests/RunCMake/File_Generate/SourcePermissions2.cmake
new file mode 100644 (file)
index 0000000..2a1e3ea
--- /dev/null
@@ -0,0 +1,5 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission2.txt"
+  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+  NO_SOURCE_PERMISSIONS
+  FILE_PERMISSIONS OWNER_READ
+  )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions3-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions3-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions3-stderr.txt
new file mode 100644 (file)
index 0000000..1143c78
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissions3.cmake:[0-9]+ \(file\):
+  file given both USE_SOURCE_PERMISSIONS and FILE_PERMISSIONS.  Only one
+  option allowed.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions3.cmake b/Tests/RunCMake/File_Generate/SourcePermissions3.cmake
new file mode 100644 (file)
index 0000000..97e0deb
--- /dev/null
@@ -0,0 +1,5 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission3.txt"
+  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+  USE_SOURCE_PERMISSIONS
+  FILE_PERMISSIONS OWNER_READ
+  )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions4-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions4-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions4-stderr.txt
new file mode 100644 (file)
index 0000000..84368cd
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissions4.cmake:[0-9]+ \(file\):
+  file given USE_SOURCE_PERMISSIONS without a file INPUT.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions4.cmake b/Tests/RunCMake/File_Generate/SourcePermissions4.cmake
new file mode 100644 (file)
index 0000000..f4127a6
--- /dev/null
@@ -0,0 +1,4 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission4.txt"
+  CONTENT "Input is content"
+  USE_SOURCE_PERMISSIONS
+  )
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions5-result.txt b/Tests/RunCMake/File_Generate/SourcePermissions5-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt b/Tests/RunCMake/File_Generate/SourcePermissions5-stderr.txt
new file mode 100644 (file)
index 0000000..d66d488
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissions5.cmake:[0-9]+ \(file\):
+  file given invalid permission "GROUP_RWX","USER_ALL".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/File_Generate/SourcePermissions5.cmake b/Tests/RunCMake/File_Generate/SourcePermissions5.cmake
new file mode 100644 (file)
index 0000000..4eb4c36
--- /dev/null
@@ -0,0 +1,4 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output-sourcepermission5.txt"
+  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+  FILE_PERMISSIONS OWNER_READ GROUP_RWX USER_ALL
+  )
diff --git a/Tests/RunCMake/File_Generate/UseSourcePermissions.cmake b/Tests/RunCMake/File_Generate/UseSourcePermissions.cmake
new file mode 100644 (file)
index 0000000..7cca9bf
--- /dev/null
@@ -0,0 +1,11 @@
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/usesourcepermissions.txt"
+  INPUT "${CMAKE_CURRENT_SOURCE_DIR}/input.txt"
+  USE_SOURCE_PERMISSIONS
+  )
+
+add_custom_target(checkUseSourcePermissions ALL
+  COMMAND ${CMAKE_COMMAND}
+    -DsourceFile=${CMAKE_CURRENT_SOURCE_DIR}/input.txt
+    -DgeneratedFile=${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/usesourcepermissions.txt
+    -P "${CMAKE_CURRENT_SOURCE_DIR}/UseSourcePermissionsVerify.cmake"
+  )
diff --git a/Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake b/Tests/RunCMake/File_Generate/UseSourcePermissionsVerify.cmake
new file mode 100644 (file)
index 0000000..8b30f96
--- /dev/null
@@ -0,0 +1,51 @@
+if(NOT EXISTS "${generatedFile}")
+  message(SEND_ERROR "Missing generated file:\n  ${generatedFile}")
+endif()
+
+if (UNIX)
+  find_program(STAT_EXECUTABLE NAMES stat)
+  if(NOT STAT_EXECUTABLE)
+    return()
+  endif()
+
+  if (CMAKE_HOST_SYSTEM_NAME MATCHES "FreeBSD")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${sourceFile}"
+      OUTPUT_VARIABLE output1
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${generatedFile}"
+      OUTPUT_VARIABLE output2
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  elseif (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${sourceFile}"
+      OUTPUT_VARIABLE output1
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${generatedFile}"
+      OUTPUT_VARIABLE output2
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  else()
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${sourceFile}"
+      OUTPUT_VARIABLE output1
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${generatedFile}"
+      OUTPUT_VARIABLE output2
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND_ERROR_IS_FATAL ANY
+      )
+  endif()
+
+  if (NOT output1 EQUAL output2)
+    message(SEND_ERROR "generated file has a different permissions source "
+          "permissions: \"${output1}\" generated permissions: \"${output2}\"")
+  endif()
+
+endif()
diff --git a/Tests/RunCMake/File_Generate/VerifyContent.cmake b/Tests/RunCMake/File_Generate/VerifyContent.cmake
new file mode 100644 (file)
index 0000000..8563708
--- /dev/null
@@ -0,0 +1,4 @@
+file(READ ${generatedFile} actualContent HEX)
+if(NOT "${actualContent}" STREQUAL "${expectedContent}")
+    message(SEND_ERROR "Content mismatch actual: \"${actualContent}\" expected: \"${expectedContent}\"")
+endif()
diff --git a/Tests/RunCMake/FindOpenSSL/CMakeLists.txt b/Tests/RunCMake/FindOpenSSL/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4fc11ae
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19...3.20)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/FindOpenSSL/RunCMakeTest.cmake b/Tests/RunCMake/FindOpenSSL/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..f941a85
--- /dev/null
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(version)
+run_cmake(version-exact)
+run_cmake(version-range)
diff --git a/Tests/RunCMake/FindOpenSSL/version-exact.cmake b/Tests/RunCMake/FindOpenSSL/version-exact.cmake
new file mode 100644 (file)
index 0000000..29c2ce3
--- /dev/null
@@ -0,0 +1,19 @@
+cmake_minimum_required (VERSION 3.19...3.20)
+
+find_package (OpenSSL REQUIRED COMPONENTS Crypto)
+# Store version without a possibly trailing letter.
+string (REGEX MATCH "^([0-9.]+)" version "${OPENSSL_VERSION}")
+
+# clean-up OpenSSL variables
+unset (OPENSSL_INCLUDE_DIR)
+unset (OPENSSL_CRYPTO_LIBRARY)
+unset (OPENSSL_CRYPTO_LIBRARIES)
+unset (OPENSSL_LIBRARIES)
+unset (OPENSSL_VERSION)
+unset (OPENSSL_FOUND)
+
+
+find_package (OpenSSL ${version} EXACT COMPONENTS Crypto)
+if (NOT OPENSSL_FOUND)
+  message (FATAL_ERROR "Failed to find OpenSSL with version ${version} EXACT")
+endif()
diff --git a/Tests/RunCMake/FindOpenSSL/version-range.cmake b/Tests/RunCMake/FindOpenSSL/version-range.cmake
new file mode 100644 (file)
index 0000000..9390032
--- /dev/null
@@ -0,0 +1,37 @@
+cmake_minimum_required (VERSION 3.19...3.20)
+
+find_package (OpenSSL REQUIRED COMPONENTS Crypto)
+# Store version without a possibly trailing letter.
+string (REGEX MATCH "^([0-9.]+)" version "${OPENSSL_VERSION}")
+
+# clean-up OpenSSL variables
+unset (OPENSSL_INCLUDE_DIR)
+unset (OPENSSL_CRYPTO_LIBRARY)
+unset (OPENSSL_CRYPTO_LIBRARIES)
+unset (OPENSSL_LIBRARIES)
+unset (OPENSSL_VERSION)
+unset (OPENSSL_FOUND)
+
+## Specify a range including current OpenSSL version
+string (REGEX MATCH "^([0-9]+)" upper_version "${version}")
+math (EXPR upper_version "${upper_version} + 1")
+
+find_package (OpenSSL 0.9...${upper_version}.0 COMPONENTS Crypto)
+if (NOT OPENSSL_FOUND)
+  message (FATAL_ERROR "Failed to find OpenSSL with version range 0.9...${upper_version}.0")
+endif()
+
+# clean-up OpenSSL variables
+unset (OPENSSL_INCLUDE_DIR)
+unset (OPENSSL_CRYPTO_LIBRARY)
+unset (OPENSSL_CRYPTO_LIBRARIES)
+unset (OPENSSL_LIBRARIES)
+unset (OPENSSL_VERSION)
+unset (OPENSSL_FOUND)
+
+## Specify a range excluding current OpenSSL version
+set (range 0.9...<${version})
+find_package (OpenSSL ${range} COMPONENTS Crypto)
+if (OPENSSL_FOUND)
+  message (FATAL_ERROR "Unexpectedly find OpenSSL with version range ${range}")
+endif()
diff --git a/Tests/RunCMake/FindOpenSSL/version.cmake b/Tests/RunCMake/FindOpenSSL/version.cmake
new file mode 100644 (file)
index 0000000..d06cd1f
--- /dev/null
@@ -0,0 +1,19 @@
+cmake_minimum_required (VERSION 3.19...3.20)
+
+find_package (OpenSSL REQUIRED COMPONENTS Crypto)
+# Store version without a possibly trailing letter.
+string (REGEX MATCH "^([0-9.]+)" version "${OPENSSL_VERSION}")
+
+# clean-up OpenSSL variables
+unset (OPENSSL_INCLUDE_DIR)
+unset (OPENSSL_CRYPTO_LIBRARY)
+unset (OPENSSL_CRYPTO_LIBRARIES)
+unset (OPENSSL_LIBRARIES)
+unset (OPENSSL_VERSION)
+unset (OPENSSL_FOUND)
+
+
+find_package (OpenSSL ${version} COMPONENTS Crypto)
+if (NOT OPENSSL_FOUND)
+  message (FATAL_ERROR "Failed to find OpenSSL with version ${version}")
+endif()
diff --git a/Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt b/Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt
new file mode 100644 (file)
index 0000000..ec9a2dd
--- /dev/null
@@ -0,0 +1,12 @@
+^PROJ1_FULL_BINDIR='/usr/bin'
+CMake Warning \(dev\) at [^
+]*/Modules/GNUInstallDirs.cmake:[0-9]+ \(message\):
+  GNUInstallDirs_get_absolute_install_dir called without third argument.
+  Using \${dir} from the caller's scope for compatibility with CMake 3.19 and
+  below.
+Call Stack \(most recent call first\):
+  GetAbs.cmake:10 \(GNUInstallDirs_get_absolute_install_dir\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
++
+PROJ2_FULL_BINDIR='/usr/bin'$
diff --git a/Tests/RunCMake/GNUInstallDirs/GetAbs.cmake b/Tests/RunCMake/GNUInstallDirs/GetAbs.cmake
new file mode 100644 (file)
index 0000000..7d5bfc8
--- /dev/null
@@ -0,0 +1,11 @@
+set(CMAKE_SIZEOF_VOID_P 8)
+set(CMAKE_LIBRARY_ARCHITECTURE "arch")
+set(CMAKE_INSTALL_PREFIX /usr)
+include(GNUInstallDirs)
+
+GNUInstallDirs_get_absolute_install_dir(PROJ1_FULL_BINDIR CMAKE_INSTALL_BINDIR BINDIR)
+message("PROJ1_FULL_BINDIR='${PROJ1_FULL_BINDIR}'")
+
+set(dir BINDIR)
+GNUInstallDirs_get_absolute_install_dir(PROJ2_FULL_BINDIR CMAKE_INSTALL_BINDIR)
+message("PROJ2_FULL_BINDIR='${PROJ2_FULL_BINDIR}'")
index 529e10a..395ff30 100644 (file)
@@ -21,4 +21,5 @@ foreach(case
   unset(RunCMake-stderr-file)
 endforeach()
 
+run_cmake(GetAbs)
 run_cmake(NoSystem)
index ae9a84c..431d1ce 100644 (file)
@@ -103,7 +103,7 @@ add_executable(GenerateExportHeader exportheader_test.cpp)
 
 target_link_libraries(GenerateExportHeader ${link_libraries})
 if (WIN32 OR CYGWIN)
-  if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+  if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") AND
     CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
     set(_platform Win32-Clang)
   elseif(MSVC AND COMPILER_HAS_DEPRECATED)
index 6349112..edeb6bd 100644 (file)
@@ -35,6 +35,9 @@ run_cmake(TARGET_NAME_IF_EXISTS-no-arg)
 run_cmake(TARGET_NAME_IF_EXISTS-empty-arg)
 run_cmake(TARGET_NAME_IF_EXISTS)
 run_cmake(TARGET_NAME_IF_EXISTS-not-a-target)
+run_cmake(TARGET_NAME_IF_EXISTS-alias-target)
+run_cmake(TARGET_NAME_IF_EXISTS-imported-target)
+run_cmake(TARGET_NAME_IF_EXISTS-imported-global-target)
 run_cmake(REMOVE_DUPLICATES-empty)
 run_cmake(REMOVE_DUPLICATES-1)
 run_cmake(REMOVE_DUPLICATES-2)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target-check.cmake
new file mode 100644 (file)
index 0000000..8ae2ecc
--- /dev/null
@@ -0,0 +1,5 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/TARGET_NAME_IF_EXISTS-generated-alias.txt" content)
+
+if(NOT content STREQUAL aliasTarget)
+  set(RunCMake_TEST_FAILED "actual content:\n ${content}\nbut expected [[aliasTarget]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-alias-target.cmake
new file mode 100644 (file)
index 0000000..d3ef0f8
--- /dev/null
@@ -0,0 +1,8 @@
+enable_language(CXX)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy_executable.cpp" "int main(int,char**) { return 0; }\n")
+add_executable(executableTarget "${CMAKE_CURRENT_BINARY_DIR}/dummy_executable.cpp")
+add_executable(aliasTarget ALIAS executableTarget)
+
+cmake_policy(SET CMP0070 NEW)
+file(GENERATE OUTPUT TARGET_NAME_IF_EXISTS-generated-alias.txt CONTENT "$<TARGET_NAME_IF_EXISTS:aliasTarget>")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target-check.cmake
new file mode 100644 (file)
index 0000000..b14c9e1
--- /dev/null
@@ -0,0 +1,5 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/TARGET_NAME_IF_EXISTS-generated-imported-global.txt" content)
+
+if(NOT content STREQUAL importedGlobalTarget)
+  set(RunCMake_TEST_FAILED "actual content:\n ${content}\nbut expected [[importedGlobalTarget]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-global-target.cmake
new file mode 100644 (file)
index 0000000..b685558
--- /dev/null
@@ -0,0 +1,4 @@
+add_executable(importedGlobalTarget IMPORTED GLOBAL)
+
+cmake_policy(SET CMP0070 NEW)
+file(GENERATE OUTPUT TARGET_NAME_IF_EXISTS-generated-imported-global.txt CONTENT "$<TARGET_NAME_IF_EXISTS:importedGlobalTarget>")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target-check.cmake
new file mode 100644 (file)
index 0000000..9615893
--- /dev/null
@@ -0,0 +1,5 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/TARGET_NAME_IF_EXISTS-generated-imported.txt" content)
+
+if(NOT content STREQUAL importedTarget)
+  set(RunCMake_TEST_FAILED "actual content:\n ${content}\nbut expected [[importedTarget]]")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_NAME_IF_EXISTS-imported-target.cmake
new file mode 100644 (file)
index 0000000..2008907
--- /dev/null
@@ -0,0 +1,4 @@
+add_executable(importedTarget IMPORTED)
+
+cmake_policy(SET CMP0070 NEW)
+file(GENERATE OUTPUT TARGET_NAME_IF_EXISTS-generated-imported.txt CONTENT "$<TARGET_NAME_IF_EXISTS:importedTarget>")
index 7fb3919..2a53c5b 100644 (file)
@@ -1,31 +1,35 @@
 Test project .*
       Start  1: TEST:basic\.case_foo!1
- 1/11 Test  #1: TEST:basic\.case_foo!1 \.+ +Passed +[0-9.]+ sec
+ 1/13 Test  #1: TEST:basic\.case_foo!1 \.+ +Passed +[0-9.]+ sec
       Start  2: TEST:basic\.case_bar!1
- 2/11 Test  #2: TEST:basic\.case_bar!1 \.+ +Passed +[0-9.]+ sec
+ 2/13 Test  #2: TEST:basic\.case_bar!1 \.+ +Passed +[0-9.]+ sec
       Start  3: TEST:basic\.disabled_case!1
- 3/11 Test  #3: TEST:basic\.disabled_case!1 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
-      Start  4: TEST:disabled\.case!1
- 4/11 Test  #4: TEST:disabled\.case!1 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
-      Start  5: TEST:typed/short\.case!1
- 5/11 Test  #5: TEST:typed/short\.case!1 \.+ +Passed +[0-9.]+ sec
-      Start  6: TEST:typed/float\.case!1
- 6/11 Test  #6: TEST:typed/float\.case!1 \.+ +Passed +[0-9.]+ sec
-      Start  7: TEST:value/test\.case/1!1
- 7/11 Test  #7: TEST:value/test\.case/1!1 \.+ +Passed +[0-9.]+ sec
-      Start  8: TEST:value/test\.case/"foo"!1
- 8/11 Test  #8: TEST:value/test\.case/"foo"!1 \.+ +Passed +[0-9.]+ sec
-      Start  9: TEST:param/special\.case/"semicolon;"!1
- 9/11 Test  #9: TEST:param/special\.case/"semicolon;"!1 \.+ +Passed +[0-9.]+ sec
-      Start 10: TEST:param/special\.case/"backslash\\"!1
-10/11 Test #10: TEST:param/special\.case/"backslash\\"!1 \.+ +Passed +[0-9.]+ sec
-      Start 11: TEST:param/special\.case/"\$\{var\}"!1
-11/11 Test #11: TEST:param/special\.case/"\$\{var\}"!1 \.+ +Passed +[0-9.]+ sec
+ 3/13 Test  #3: TEST:basic\.disabled_case!1 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
+      Start  4: TEST:basic\.DISABLEDnot_really_case!1
+ 4/13 Test  #4: TEST:basic\.DISABLEDnot_really_case!1 \.+ +Passed +[0-9.]+ sec
+      Start  5: TEST:disabled\.case!1
+ 5/13 Test  #5: TEST:disabled\.case!1 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
+      Start  6: TEST:DISABLEDnotreally\.case!1
+ 6/13 Test  #6: TEST:DISABLEDnotreally\.case!1 \.+ +Passed +[0-9.]+ sec
+      Start  7: TEST:typed/short\.case!1
+ 7/13 Test  #7: TEST:typed/short\.case!1 \.+ +Passed +[0-9.]+ sec
+      Start  8: TEST:typed/float\.case!1
+ 8/13 Test  #8: TEST:typed/float\.case!1 \.+ +Passed +[0-9.]+ sec
+      Start  9: TEST:value/test\.case/1!1
+ 9/13 Test  #9: TEST:value/test\.case/1!1 \.+ +Passed +[0-9.]+ sec
+      Start 10: TEST:value/test\.case/"foo"!1
+10/13 Test #10: TEST:value/test\.case/"foo"!1 \.+ +Passed +[0-9.]+ sec
+      Start 11: TEST:param/special\.case/"semicolon;"!1
+11/13 Test #11: TEST:param/special\.case/"semicolon;"!1 \.+ +Passed +[0-9.]+ sec
+      Start 12: TEST:param/special\.case/"backslash\\"!1
+12/13 Test #12: TEST:param/special\.case/"backslash\\"!1 \.+ +Passed +[0-9.]+ sec
+      Start 13: TEST:param/special\.case/"\$\{var\}"!1
+13/13 Test #13: TEST:param/special\.case/"\$\{var\}"!1 \.+ +Passed +[0-9.]+ sec
 
-100% tests passed, 0 tests failed out of 9
+100% tests passed, 0 tests failed out of 11
 
 Total Test time \(real\) = +[0-9.]+ sec
 
 The following tests did not run:
 .*3 - TEST:basic\.disabled_case!1 \(Disabled\)
-.*4 - TEST:disabled\.case!1 \(Disabled\)
+.*5 - TEST:disabled\.case!1 \(Disabled\)
index 58c4d10..5b68e10 100644 (file)
@@ -1,31 +1,35 @@
 Test project .*
-      Start 12: TEST:basic\.case_foo!2
- 1/11 Test #12: TEST:basic\.case_foo!2 \.+ +Passed +[0-9.]+ sec
-      Start 13: TEST:basic\.case_bar!2
- 2/11 Test #13: TEST:basic\.case_bar!2 \.+ +Passed +[0-9.]+ sec
-      Start 14: TEST:basic\.disabled_case!2
- 3/11 Test #14: TEST:basic\.disabled_case!2 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
-      Start 15: TEST:disabled\.case!2
- 4/11 Test #15: TEST:disabled\.case!2 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
-      Start 16: TEST:typed/short\.case!2
- 5/11 Test #16: TEST:typed/short\.case!2 \.+ +Passed +[0-9.]+ sec
-      Start 17: TEST:typed/float\.case!2
- 6/11 Test #17: TEST:typed/float\.case!2 \.+ +Passed +[0-9.]+ sec
-      Start 18: TEST:value/test\.case/1!2
- 7/11 Test #18: TEST:value/test\.case/1!2 \.+ +Passed +[0-9.]+ sec
-      Start 19: TEST:value/test\.case/"foo"!2
- 8/11 Test #19: TEST:value/test\.case/"foo"!2 \.+ +Passed +[0-9.]+ sec
-      Start 20: TEST:param/special\.case/"semicolon;"!2
- 9/11 Test #20: TEST:param/special\.case/"semicolon;"!2 \.+ +Passed +[0-9.]+ sec
-      Start 21: TEST:param/special\.case/"backslash\\"!2
-10/11 Test #21: TEST:param/special\.case/"backslash\\"!2 \.+ +Passed +[0-9.]+ sec
-      Start 22: TEST:param/special\.case/"\$\{var\}"!2
-11/11 Test #22: TEST:param/special\.case/"\$\{var\}"!2 \.+ +Passed +[0-9.]+ sec
+      Start 14: TEST:basic\.case_foo!2
+ 1/13 Test #14: TEST:basic\.case_foo!2 \.+ +Passed +[0-9.]+ sec
+      Start 15: TEST:basic\.case_bar!2
+ 2/13 Test #15: TEST:basic\.case_bar!2 \.+ +Passed +[0-9.]+ sec
+      Start 16: TEST:basic\.disabled_case!2
+ 3/13 Test #16: TEST:basic\.disabled_case!2 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
+      Start 17: TEST:basic\.DISABLEDnot_really_case!2
+ 4/13 Test #17: TEST:basic\.DISABLEDnot_really_case!2 \.+ +Passed +[0-9.]+ sec
+      Start 18: TEST:disabled\.case!2
+ 5/13 Test #18: TEST:disabled\.case!2 \.+\*+Not Run \(Disabled\) +[0-9.]+ sec
+      Start 19: TEST:DISABLEDnotreally\.case!2
+ 6/13 Test #19: TEST:DISABLEDnotreally\.case!2 \.+ +Passed +[0-9.]+ sec
+      Start 20: TEST:typed/short\.case!2
+ 7/13 Test #20: TEST:typed/short\.case!2 \.+ +Passed +[0-9.]+ sec
+      Start 21: TEST:typed/float\.case!2
+ 8/13 Test #21: TEST:typed/float\.case!2 \.+ +Passed +[0-9.]+ sec
+      Start 22: TEST:value/test\.case/1!2
+ 9/13 Test #22: TEST:value/test\.case/1!2 \.+ +Passed +[0-9.]+ sec
+      Start 23: TEST:value/test\.case/"foo"!2
+10/13 Test #23: TEST:value/test\.case/"foo"!2 \.+ +Passed +[0-9.]+ sec
+      Start 24: TEST:param/special\.case/"semicolon;"!2
+11/13 Test #24: TEST:param/special\.case/"semicolon;"!2 \.+ +Passed +[0-9.]+ sec
+      Start 25: TEST:param/special\.case/"backslash\\"!2
+12/13 Test #25: TEST:param/special\.case/"backslash\\"!2 \.+ +Passed +[0-9.]+ sec
+      Start 26: TEST:param/special\.case/"\$\{var\}"!2
+13/13 Test #26: TEST:param/special\.case/"\$\{var\}"!2 \.+ +Passed +[0-9.]+ sec
 
-100% tests passed, 0 tests failed out of 9
+100% tests passed, 0 tests failed out of 11
 
 Total Test time \(real\) = +[0-9.]+ sec
 
 The following tests did not run:
-.*14 - TEST:basic\.disabled_case!2 \(Disabled\)
-.*15 - TEST:disabled\.case!2 \(Disabled\)
+.*16 - TEST:basic\.disabled_case!2 \(Disabled\)
+.*18 - TEST:disabled\.case!2 \(Disabled\)
index 6aa2658..8efd117 100644 (file)
@@ -1,9 +1,12 @@
-project(test_include_dirs LANGUAGES CXX)
+enable_language(CXX)
 include(GoogleTest)
 
 enable_testing()
 
+include(xcode_sign_adhoc.cmake)
+
 add_executable(fake_gtest fake_gtest.cpp)
+xcode_sign_adhoc(fake_gtest)
 
 gtest_discover_tests(
   fake_gtest
@@ -22,6 +25,7 @@ gtest_discover_tests(
 )
 
 add_executable(no_tests_defined no_tests_defined.cpp)
+xcode_sign_adhoc(no_tests_defined)
 
 gtest_discover_tests(
   no_tests_defined
@@ -33,6 +37,7 @@ gtest_discover_tests(
 # 3.10.3 and later behavior, old behavior added in 3.10.1
 # is not supported.
 add_executable(property_timeout_test timeout_test.cpp)
+xcode_sign_adhoc(property_timeout_test)
 target_compile_definitions(property_timeout_test PRIVATE sleepSec=10)
 
 gtest_discover_tests(
@@ -50,6 +55,7 @@ gtest_discover_tests(
 )
 
 add_executable(skip_test skip_test.cpp)
+xcode_sign_adhoc(skip_test)
 
 gtest_discover_tests(
   skip_test
index df784fe..2fae1e2 100644 (file)
@@ -1,9 +1,12 @@
-project(test_include_dirs LANGUAGES CXX)
+enable_language(CXX)
 include(GoogleTest)
 
 enable_testing()
 
+include(xcode_sign_adhoc.cmake)
+
 add_executable(configuration_gtest configuration_gtest.cpp)
+xcode_sign_adhoc(configuration_gtest)
 target_compile_definitions(configuration_gtest PRIVATE $<$<CONFIG:Debug>:DEBUG=1>)
 
 gtest_discover_tests(
index 20e9d65..5c24d41 100644 (file)
@@ -1,9 +1,12 @@
-project(test_include_dirs LANGUAGES CXX)
+enable_language(CXX)
 include(GoogleTest)
 
 enable_testing()
 
+include(xcode_sign_adhoc.cmake)
+
 add_executable(discovery_timeout_test timeout_test.cpp)
+xcode_sign_adhoc(discovery_timeout_test)
 target_compile_definitions(discovery_timeout_test PRIVATE discoverySleepSec=10)
 gtest_discover_tests(
   discovery_timeout_test
index fb91c0e..53eedc0 100644 (file)
@@ -1,8 +1,10 @@
-project(test_include_dirs LANGUAGES CXX)
+enable_language(CXX)
 include(GoogleTest)
 
 enable_testing()
 
+include(xcode_sign_adhoc.cmake)
+
 # This creates the folder structure for the paramterized tests
 # to avoid handling missing folders in C++
 #
@@ -15,6 +17,7 @@ enable_testing()
 file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/GoogleTestXMLSpecial/cases.case")
 
 add_executable(xml_output xml_output.cpp)
+xcode_sign_adhoc(xml_output)
 gtest_discover_tests(
   xml_output
   XML_OUTPUT_DIR ${CMAKE_BINARY_DIR}
index a8127bf..1956c37 100644 (file)
@@ -12,8 +12,11 @@ int main(int argc, char** argv)
     std::cout << "  case_foo" << std::endl;
     std::cout << "  case_bar" << std::endl;
     std::cout << "  DISABLED_disabled_case" << std::endl;
+    std::cout << "  DISABLEDnot_really_case" << std::endl;
     std::cout << "DISABLED_disabled." << std::endl;
     std::cout << "  case" << std::endl;
+    std::cout << "DISABLEDnotreally." << std::endl;
+    std::cout << "  case" << std::endl;
     std::cout << "typed/0.  # TypeParam = short" << std::endl;
     std::cout << "  case" << std::endl;
     std::cout << "typed/1.  # TypeParam = float" << std::endl;
diff --git a/Tests/RunCMake/GoogleTest/xcode_sign_adhoc.cmake b/Tests/RunCMake/GoogleTest/xcode_sign_adhoc.cmake
new file mode 100644 (file)
index 0000000..d2dc530
--- /dev/null
@@ -0,0 +1,8 @@
+function(xcode_sign_adhoc target)
+  if(CMAKE_GENERATOR STREQUAL "Xcode" AND
+     "${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Darwin;arm64")
+    # Xcode runs POST_BUILD before signing, so let the linker use ad-hoc signing.
+    # See CMake Issue 21845.
+    target_link_options(${target} PRIVATE LINKER:-adhoc_codesign)
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-NEW.cmake b/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-NEW.cmake
new file mode 100644 (file)
index 0000000..c8b0a91
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0117 NEW)
+include(CMP0117-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-OLD.cmake b/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-OLD.cmake
new file mode 100644 (file)
index 0000000..c0a61d0
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0117 OLD)
+include(CMP0117-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-WARN.cmake b/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-WARN.cmake
new file mode 100644 (file)
index 0000000..37d1b64
--- /dev/null
@@ -0,0 +1,2 @@
+
+include(CMP0117-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-common.cmake b/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-common.cmake
new file mode 100644 (file)
index 0000000..5dda623
--- /dev/null
@@ -0,0 +1,12 @@
+enable_language(CXX)
+
+cmake_policy(GET CMP0117 cmp0117)
+if(cmp0117 STREQUAL "NEW")
+  if(" ${CMAKE_CXX_FLAGS} " MATCHES " ([/-]GR) ")
+    message(SEND_ERROR "CMAKE_CXX_FLAGS has '${CMAKE_MATCH_1}' under NEW behavior")
+  endif()
+else()
+  if(NOT " ${CMAKE_CXX_FLAGS} " MATCHES " /GR ")
+    message(SEND_ERROR "CMAKE_CXX_FLAGS does not have '/GR' under OLD behavior")
+  endif()
+endif()
diff --git a/Tests/RunCMake/MSVCRuntimeTypeInfo/CMakeLists.txt b/Tests/RunCMake/MSVCRuntimeTypeInfo/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3e470a2
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeTypeInfo/RunCMakeTest.cmake b/Tests/RunCMake/MSVCRuntimeTypeInfo/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..c870f59
--- /dev/null
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0117-WARN)
+run_cmake(CMP0117-OLD)
+run_cmake(CMP0117-NEW)
diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt
deleted file mode 100644 (file)
index 74d62a4..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-^CMake Error at CustomCommandDepfile-ERROR.cmake:1 \(add_custom_command\):
-  add_custom_command Option DEPFILE not supported by [^
-]+
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake
deleted file mode 100644 (file)
index bad7955..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-add_custom_command(
-  OUTPUT hello.copy.c
-  COMMAND "${CMAKE_COMMAND}" -E copy
-          "${CMAKE_CURRENT_SOURCE_DIR}/hello.c"
-          hello.copy.c
-  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
-  DEPFILE "test.d"
-  )
diff --git a/Tests/RunCMake/Make/MakefileConflict.cmake b/Tests/RunCMake/Make/MakefileConflict.cmake
new file mode 100644 (file)
index 0000000..6a8406f
--- /dev/null
@@ -0,0 +1,5 @@
+add_custom_target(Custom)
+
+# Write a file that GNU make will prefer over "Makefile"
+# if 'cmake --build' does not explicitly specify it.
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/GNUmakefile" "")
index 5562aca..c7717ec 100644 (file)
@@ -39,9 +39,16 @@ function(run_VerboseBuild)
 endfunction()
 run_VerboseBuild()
 
-run_cmake(CustomCommandDepfile-ERROR)
 run_cmake(IncludeRegexSubdir)
 
+function(run_MakefileConflict)
+  run_cmake(MakefileConflict)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/MakefileConflict-build)
+  run_cmake_command(MakefileConflict-build ${CMAKE_COMMAND} --build . --target Custom)
+endfunction()
+run_MakefileConflict()
+
 function(run_CMP0113 val)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0113-${val}-build)
   run_cmake(CMP0113-${val})
diff --git a/Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-OFF-build-check.cmake
new file mode 100644 (file)
index 0000000..74a0564
--- /dev/null
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES OFF)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
index 77a582a..8d98f9d 100644 (file)
@@ -1,5 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-ON-build-check.cmake
new file mode 100644 (file)
index 0000000..afd8efb
--- /dev/null
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES ON)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
index a827624..8d98f9d 100644 (file)
@@ -1,8 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*
-Built target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-VAR-OFF-build-check.cmake
new file mode 100644 (file)
index 0000000..74a0564
--- /dev/null
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES OFF)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
index 77a582a..8d98f9d 100644 (file)
@@ -1,5 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake b/Tests/RunCMake/Make/TargetMessages-VAR-ON-build-check.cmake
new file mode 100644 (file)
index 0000000..afd8efb
--- /dev/null
@@ -0,0 +1,3 @@
+
+set (CHECK_TARGET_MESSAGES ON)
+include ("${CMAKE_CURRENT_LIST_DIR}/TargetMessages-validation.cmake")
index a827624..8d98f9d 100644 (file)
@@ -1,8 +1 @@
-^(([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*
-)*Scanning dependencies of target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*
-Built target CustomTarget(
-([^B]|B[^u]|Bu[^i]|Bui[^l]|Buil[^t]|Built[^ ])[^
-]*)*$
+.*
diff --git a/Tests/RunCMake/Make/TargetMessages-validation.cmake b/Tests/RunCMake/Make/TargetMessages-validation.cmake
new file mode 100644 (file)
index 0000000..f3d7af1
--- /dev/null
@@ -0,0 +1,10 @@
+
+if (CHECK_TARGET_MESSAGES)
+  if (NOT actual_stdout MATCHES "Built target CustomTarget")
+    set (RunCMake_TEST_FAILED "Not found expected 'Built target' message.")
+  endif()
+else()
+  if (actual_stdout MATCHES "Built target CustomTarget")
+    set (RunCMake_TEST_FAILED "Found unexpected 'Built target' message.")
+  endif()
+endif()
index 5fb0219..d5364f0 100644 (file)
@@ -1,4 +1,5 @@
 cmake_minimum_required(VERSION 3.8)
+cmake_policy(SET CMP0118 NEW)
 project(AssumedSources)
 
 set_source_files_properties(
index d69a119..7456608 100644 (file)
@@ -7,3 +7,7 @@ set(CMAKE_AUTOMOC ON)
 add_library(simple_lib SHARED simple_lib.cpp)
 add_executable(app_with_qt app.cpp app_qt.cpp)
 target_link_libraries(app_with_qt PRIVATE simple_lib Qt5::Core)
+
+add_subdirectory(QtSubDir1)
+add_subdirectory(QtSubDir2)
+add_subdirectory(QtSubDir3)
diff --git a/Tests/RunCMake/Ninja/QtSubDir1/CMakeLists.txt b/Tests/RunCMake/Ninja/QtSubDir1/CMakeLists.txt
new file mode 100644 (file)
index 0000000..64016b6
--- /dev/null
@@ -0,0 +1,4 @@
+cmake_policy(SET CMP0116 OLD)
+
+add_executable(sub_exe_1 ../app.cpp)
+target_link_libraries(sub_exe_1 PRIVATE Qt5::Core)
diff --git a/Tests/RunCMake/Ninja/QtSubDir2/CMakeLists.txt b/Tests/RunCMake/Ninja/QtSubDir2/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3176426
--- /dev/null
@@ -0,0 +1,4 @@
+cmake_policy(SET CMP0116 NEW)
+
+add_executable(sub_exe_2 ../app.cpp)
+target_link_libraries(sub_exe_2 PRIVATE Qt5::Core)
diff --git a/Tests/RunCMake/Ninja/QtSubDir3/CMakeLists.txt b/Tests/RunCMake/Ninja/QtSubDir3/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d38cfe0
--- /dev/null
@@ -0,0 +1,2 @@
+add_executable(sub_exe_3 ../app.cpp)
+target_link_libraries(sub_exe_3 PRIVATE Qt5::Core)
index 35be2ec..1b252cd 100644 (file)
@@ -340,8 +340,17 @@ function(run_Qt5AutoMocDeps)
     # Build and assert that AUTOMOC was not run for app_with_qt.
     run_ninja("${RunCMake_TEST_BINARY_DIR}")
     if(ninja_stdout MATCHES "Automatic MOC for target app_with_qt")
-        message(FATAL_ERROR
-               "AUTOMOC should not have executed for 'app_with_qt' target:\nstdout:\n${ninja_stdout}")
+      message(FATAL_ERROR
+        "AUTOMOC should not have executed for 'app_with_qt' target:\nstdout:\n${ninja_stdout}")
+    endif()
+    # Assert that the subdir executables were not rebuilt.
+    if(ninja_stdout MATCHES "Automatic MOC for target sub_exe_1")
+      message(FATAL_ERROR
+        "AUTOMOC should not have executed for 'sub_exe_1' target:\nstdout:\n${ninja_stdout}")
+    endif()
+    if(ninja_stdout MATCHES "Automatic MOC for target sub_exe_2")
+      message(FATAL_ERROR
+        "AUTOMOC should not have executed for 'sub_exe_2' target:\nstdout:\n${ninja_stdout}")
     endif()
   endif()
 endfunction()
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..cc2e49a
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_genex_Debug\.txt
+depend_echo_genex_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..cc2e49a
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_genex_Debug\.txt
+depend_echo_genex_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..214e747
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Release[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Release[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_genex_cmd_Debug\.txt
+depend_echo_genex_cmd_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_cmd-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..842336d
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_genex_cmd_Debug\.txt
+depend_echo_genex_cmd_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..eafe30b
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_genex_out_Debug\.txt
+depend_echo_genex_out_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_genex_out-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..eafe30b
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_genex_out_Debug\.txt
+depend_echo_genex_out_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..e7b74b9
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Release[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Release[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_raw_Debug\.txt
+depend_echo_raw_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-depend_echo_raw-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..2e01d6a
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating depend_echo_raw_Debug\.txt
+depend_echo_raw_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..7455c25
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] Generating echo_depend_Debug\.txt
+echo_depend_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..7455c25
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] Generating echo_depend_Debug\.txt
+echo_depend_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..6d5620d
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Release\.txt
+depend_Release\.txt
+\[2/2\] Generating echo_depend_cmd_Debug\.txt
+echo_depend_cmd_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_cmd-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..2f0f1f1
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] Generating echo_depend_cmd_Debug\.txt
+echo_depend_cmd_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..39f5471
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] Generating echo_depend_out_Debug\.txt
+echo_depend_out_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_depend_out-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..39f5471
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] Generating echo_depend_out_Debug\.txt
+echo_depend_out_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..cc43cda
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Release[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Release[\/]echo(\.exe)?
+\[3/3\] Generating echo_genex_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Release' 'echo_genex_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..11985c6
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_genex_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_genex_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..68a8cd1
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_genex_out_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_genex_out_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_genex_out-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..76b409d
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_genex_out_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_genex_out_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-result.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-result.txt
new file mode 100644 (file)
index 0000000..d197c91
--- /dev/null
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-in-release-graph-ninja-stderr.txt
new file mode 100644 (file)
index 0000000..86f7995
--- /dev/null
@@ -0,0 +1 @@
+ninja: error: 'echo_no_cross_byproduct_Debug\.txt', needed by 'CMakeFiles/echo_no_cross_byproduct-Debug', missing and no known rule to make it
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..1c74b71
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_no_cross_byproduct_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_no_cross_byproduct_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-result.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-in-release-graph-ninja-stderr.txt
new file mode 100644 (file)
index 0000000..e41cb17
--- /dev/null
@@ -0,0 +1 @@
+ninja: error: 'echo_no_cross_byproduct_if_Debug\.txt', needed by 'CMakeFiles/echo_no_cross_byproduct_if-Debug', missing and no known rule to make it
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_byproduct_if-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..294d48b
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_no_cross_byproduct_if_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_no_cross_byproduct_if_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-result.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-result.txt
new file mode 100644 (file)
index 0000000..d197c91
--- /dev/null
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-in-release-graph-ninja-stderr.txt
new file mode 100644 (file)
index 0000000..2ea22fa
--- /dev/null
@@ -0,0 +1 @@
+ninja: error: 'echo_no_cross_output_Debug\.txt', needed by 'CMakeFiles/echo_no_cross_output-Debug', missing and no known rule to make it
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..1f4cc41
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_no_cross_output\.txt, echo_no_cross_output_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_no_cross_output_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-result.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-in-release-graph-ninja-stderr.txt
new file mode 100644 (file)
index 0000000..fde66ea
--- /dev/null
@@ -0,0 +1 @@
+ninja: error: 'echo_no_cross_output_if_Debug\.txt', needed by 'CMakeFiles/echo_no_cross_output_if-Debug', missing and no known rule to make it
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_no_cross_output_if-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..dc31f3b
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_no_cross_output_a\.txt, echo_no_cross_output_if_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_no_cross_output_if_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..01ebae3
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Release[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Release[\/]echo(\.exe)?
+\[3/3\] Generating echo_raw_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Debug' 'echo_raw_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_raw-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..242c9b0
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] Generating echo_raw_Debug\.txt
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_raw_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..e77ef1a
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] echo_target_depend
+echo_target_depend_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..e77ef1a
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] echo_target_depend
+echo_target_depend_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..8196fcb
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Release\.txt
+depend_Release\.txt
+\[2/2\] echo_target_depend_cmd
+echo_target_depend_cmd_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_cmd-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..d45dcc2
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] echo_target_depend_cmd
+echo_target_depend_cmd_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..45f2e57
--- /dev/null
@@ -0,0 +1,5 @@
+^(Recompacting log\.\.\.
+)?\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] echo_target_depend_out
+echo_target_depend_out_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_depend_out-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..d90a2f3
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/2\] Generating depend_Debug\.txt
+depend_Debug\.txt
+\[2/2\] echo_target_depend_out
+echo_target_depend_out_Debug\.txt$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..73b403f
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Release[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Release[\/]echo(\.exe)?
+\[3/3\] echo_target_genex
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Release' 'echo_target_genex_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..c374ce8
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] echo_target_genex
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_target_genex_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..ad6d6e0
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] echo_target_genex_out
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_target_genex_out_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_genex_out-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..e819fdf
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] echo_target_genex_out
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_target_genex_out_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..34df645
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Release[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Release[\/]echo(\.exe)?
+\[3/3\] echo_target_raw
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Debug' 'echo_target_raw_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-echo_target_raw-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..3fa5488
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] echo_target_raw
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'echo_target_raw_Debug\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-in-release-graph-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-in-release-graph-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..f504d98
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Release[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Release[\/]echo(\.exe)?
+\[3/3\] target_no_cross_byproduct
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Release' 'target_no_cross_byproduct\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex-target_no_cross_byproduct-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..6e933b2
--- /dev/null
@@ -0,0 +1,4 @@
+^\[1/3\] Building C object CMakeFiles[\/]echo.dir[\/]Debug[\/]echo\.c\.(o|obj)
+\[2/3\] Linking C executable Debug[\/]echo(\.exe)?
+\[3/3\] target_no_cross_byproduct
+'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug' 'target_no_cross_byproduct\.txt'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake
new file mode 100644 (file)
index 0000000..5d6f421
--- /dev/null
@@ -0,0 +1,167 @@
+enable_language(C)
+
+add_executable(echo echo.c)
+
+add_custom_command(
+  OUTPUT echo_raw_$<CONFIG>.txt
+  COMMAND echo $<CONFIG> echo_raw_$<CONFIG>.txt
+  WORKING_DIRECTORY $<CONFIG>
+  )
+
+add_custom_command(
+  OUTPUT echo_genex_$<IF:$<CONFIG:Debug>,Debug,$<IF:$<CONFIG:Release>,Release,$<IF:$<CONFIG:MinSizeRel>,MinSizeRel,RelWithDebInfo>>>.txt
+  COMMAND $<TARGET_FILE:echo> $<COMMAND_CONFIG:$<CONFIG>> echo_genex_$<OUTPUT_CONFIG:$<CONFIG>>.txt
+  WORKING_DIRECTORY $<OUTPUT_CONFIG:$<CONFIG>>
+  )
+
+add_custom_command(
+  OUTPUT echo_genex_out_$<CONFIG>.txt
+  COMMAND $<OUTPUT_CONFIG:$<TARGET_FILE:echo>> $<CONFIG> echo_genex_out_$<CONFIG>.txt
+  WORKING_DIRECTORY $<COMMAND_CONFIG:$<CONFIG>>
+  )
+
+add_custom_command(
+  OUTPUT depend_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo depend_$<CONFIG>.txt
+  )
+
+add_custom_command(
+  OUTPUT echo_depend_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo echo_depend_$<CONFIG>.txt
+  DEPENDS depend_$<CONFIG>.txt
+  )
+
+add_custom_command(
+  OUTPUT echo_depend_out_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo echo_depend_out_$<CONFIG>.txt
+  DEPENDS $<OUTPUT_CONFIG:depend_$<CONFIG>.txt>
+  )
+
+add_custom_command(
+  OUTPUT echo_depend_cmd_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo echo_depend_cmd_$<CONFIG>.txt
+  DEPENDS $<COMMAND_CONFIG:depend_$<CONFIG>.txt>
+  )
+
+add_custom_command(
+  OUTPUT depend_echo_raw_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo depend_echo_raw_$<CONFIG>.txt
+  DEPENDS echo
+  )
+
+add_custom_command(
+  OUTPUT depend_echo_genex_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo depend_echo_genex_$<CONFIG>.txt
+  DEPENDS $<TARGET_FILE:echo>
+  )
+
+add_custom_command(
+  OUTPUT depend_echo_genex_out_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo depend_echo_genex_out_$<CONFIG>.txt
+  DEPENDS $<OUTPUT_CONFIG:$<TARGET_FILE:echo>>
+  )
+
+add_custom_command(
+  OUTPUT depend_echo_genex_cmd_$<CONFIG>.txt
+  COMMAND ${CMAKE_COMMAND} -E echo depend_echo_genex_cmd_$<CONFIG>.txt
+  DEPENDS $<COMMAND_CONFIG:$<TARGET_FILE:echo>>
+  )
+
+# An OUTPUT that is not per-config prevents cross-config generation.
+add_custom_command(
+  OUTPUT echo_no_cross_output.txt echo_no_cross_output_$<CONFIG>.txt
+  COMMAND echo $<CONFIG> echo_no_cross_output_$<CONFIG>.txt
+  WORKING_DIRECTORY $<CONFIG>
+  )
+add_custom_command(
+  OUTPUT echo_no_cross_output_$<IF:$<CONFIG:Debug>,a,b>.txt echo_no_cross_output_if_$<CONFIG>.txt
+  COMMAND echo $<CONFIG> echo_no_cross_output_if_$<CONFIG>.txt
+  WORKING_DIRECTORY $<CONFIG>
+  )
+
+# BYPRODUCTS that are not per-config prevent cross-config generation.
+add_custom_command(
+  OUTPUT echo_no_cross_byproduct_$<CONFIG>.txt
+  BYPRODUCTS echo_no_cross_byproduct.txt
+  COMMAND echo $<CONFIG> echo_no_cross_byproduct_$<CONFIG>.txt
+  WORKING_DIRECTORY $<CONFIG>
+  )
+add_custom_command(
+  OUTPUT echo_no_cross_byproduct_if_$<CONFIG>.txt
+  BYPRODUCTS echo_no_cross_byproduct_$<IF:$<CONFIG:Debug>,a,b>.txt
+  COMMAND echo $<CONFIG> echo_no_cross_byproduct_if_$<CONFIG>.txt
+  WORKING_DIRECTORY $<CONFIG>
+  )
+
+foreach(case
+    echo_raw
+    echo_genex
+    echo_genex_out
+    echo_depend
+    echo_depend_out
+    echo_depend_cmd
+    depend
+    depend_echo_raw
+    depend_echo_genex
+    depend_echo_genex_out
+    depend_echo_genex_cmd
+    echo_no_cross_output
+    echo_no_cross_output_if
+    echo_no_cross_byproduct
+    echo_no_cross_byproduct_if
+    )
+  set_property(SOURCE
+    ${CMAKE_CURRENT_BINARY_DIR}/${case}_Debug.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/${case}_Release.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/${case}_MinSizeRel.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/${case}_RelWithDebInfo.txt
+    PROPERTY SYMBOLIC 1)
+  add_custom_target(${case} DEPENDS ${case}_$<CONFIG>.txt)
+endforeach()
+
+add_custom_target(echo_target_raw
+  BYPRODUCTS echo_target_raw_$<CONFIG>.txt
+  COMMENT echo_target_raw
+  COMMAND echo $<CONFIG> echo_target_raw_$<CONFIG>.txt
+  WORKING_DIRECTORY $<CONFIG>
+  )
+
+add_custom_target(echo_target_genex
+  BYPRODUCTS echo_target_genex_$<CONFIG>.txt
+  COMMENT echo_target_genex
+  COMMAND $<TARGET_FILE:echo> $<COMMAND_CONFIG:$<CONFIG>> echo_target_genex_$<OUTPUT_CONFIG:$<CONFIG>>.txt
+  WORKING_DIRECTORY $<OUTPUT_CONFIG:$<CONFIG>>
+  )
+
+add_custom_target(echo_target_genex_out
+  BYPRODUCTS echo_target_genex_out_$<CONFIG>.txt
+  COMMENT echo_target_genex_out
+  COMMAND $<OUTPUT_CONFIG:$<TARGET_FILE:echo>> $<CONFIG> echo_target_genex_out_$<CONFIG>.txt
+  WORKING_DIRECTORY $<COMMAND_CONFIG:$<CONFIG>>
+  )
+
+add_custom_target(echo_target_depend
+  COMMAND ${CMAKE_COMMAND} -E echo echo_target_depend_$<CONFIG>.txt
+  DEPENDS depend_$<CONFIG>.txt
+  COMMENT echo_target_depend
+  )
+
+add_custom_target(echo_target_depend_out
+  COMMAND ${CMAKE_COMMAND} -E echo echo_target_depend_out_$<CONFIG>.txt
+  DEPENDS $<OUTPUT_CONFIG:depend_$<CONFIG>.txt>
+  COMMENT echo_target_depend_out
+  )
+
+add_custom_target(echo_target_depend_cmd
+  COMMAND ${CMAKE_COMMAND} -E echo echo_target_depend_cmd_$<CONFIG>.txt
+  DEPENDS $<COMMAND_CONFIG:depend_$<CONFIG>.txt>
+  COMMENT echo_target_depend_cmd
+  )
+
+# BYPRODUCTS that are not per-config block cross-configs.
+add_custom_target(target_no_cross_byproduct
+  BYPRODUCTS target_no_cross_byproduct.txt
+  COMMENT target_no_cross_byproduct
+  COMMAND echo $<CONFIG> target_no_cross_byproduct.txt
+  WORKING_DIRECTORY $<CONFIG>
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt
new file mode 100644 (file)
index 0000000..fad923a
--- /dev/null
@@ -0,0 +1,2 @@
+Running post-build command with Debug
+Generating Debug\.txt
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt
new file mode 100644 (file)
index 0000000..485a52c
--- /dev/null
@@ -0,0 +1,3 @@
+Running post-build command with Release
+Generating out\.txt with Release
+Generating Release\.txt
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake b/Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake
new file mode 100644 (file)
index 0000000..5fcff74
--- /dev/null
@@ -0,0 +1,6 @@
+enable_language(C)
+
+add_executable(Exe main.c)
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Running post-build command with $<CONFIG>")
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating out.txt with $<CONFIG>" BYPRODUCTS out.txt)
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating $<CONFIG>.txt" BYPRODUCTS $<CONFIG>.txt)
index 3a1c7f5..578256a 100644 (file)
@@ -16,12 +16,13 @@ if(Qt5Core_VERSION VERSION_GREATER_EQUAL "5.15.0")
   set(moc_writes_depfiles 1)
 endif()
 
-set(autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/mocs_compilation.cpp")
+set(autogen_files)
 if(moc_writes_depfiles)
   list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/deps")
   list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/timestamp")
 endif()
 foreach(c IN LISTS CMAKE_CONFIGURATION_TYPES)
+  list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/mocs_compilation_${c}.cpp")
   list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/include_${c}/moc_qt5.cpp")
   if(moc_writes_depfiles)
     list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/include_${c}/moc_qt5.cpp.d")
index 6699a09..21c2658 100644 (file)
@@ -85,6 +85,9 @@ set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo\\;Debug\\;
 run_cmake_configure(Simple)
 unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_ninja(Simple targets-default build.ninja -t targets)
+run_ninja(Simple targets-debug build-Debug.ninja -t targets)
+run_ninja(Simple targets-release build-Debug.ninja -t targets)
 run_cmake_build(Simple debug-target Debug simpleexe)
 run_ninja(Simple debug-target build-Debug.ninja simplestatic)
 get_filename_component(simpleshared_Release "${TARGET_FILE_simpleshared_Release}" NAME)
@@ -187,6 +190,12 @@ run_ninja(SimpleCrossConfigs clean-all-in-release-graph build-Release.ninja clea
 run_cmake_build(SimpleCrossConfigs all-all-in-release-graph Release all:all)
 run_cmake_build(SimpleCrossConfigs all-relwithdebinfo-in-release-graph Release all:RelWithDebInfo)
 
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PostBuild-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(PostBuild)
+run_cmake_build(PostBuild release Release Exe)
+run_cmake_build(PostBuild debug-in-release-graph Release Exe:Debug)
+
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Framework-build)
 set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
 run_cmake_configure(Framework)
@@ -215,7 +224,7 @@ run_ninja(CustomCommandGenerator debug-clean build-Debug.ninja clean)
 run_cmake_build(CustomCommandGenerator release-clean Release clean)
 run_cmake_build(CustomCommandGenerator debug-in-release-graph Release generated:Debug)
 run_cmake_command(CustomCommandGenerator-debug-in-release-graph-generated "${TARGET_FILE_generated_Debug}")
-run_ninja(CustomCommandGenerator debug-in-release-graph-clean build-Debug.ninja clean:Debug)
+run_ninja(CustomCommandGenerator debug-clean-again build-Debug.ninja clean:Debug)
 run_ninja(CustomCommandGenerator release-in-debug-graph build-Debug.ninja generated:Release)
 run_cmake_command(CustomCommandGenerator-release-in-debug-graph-generated "${TARGET_FILE_generated_Release}")
 unset(RunCMake_TEST_NO_CLEAN)
@@ -242,6 +251,102 @@ run_ninja(CustomCommandsAndTargets release-leaf-exe build-Release.ninja LeafExe)
 run_cmake_build(CustomCommandsAndTargets release-clean Release clean:all)
 run_ninja(CustomCommandsAndTargets release-leaf-byproduct build-Release.ninja main.c)
 
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandOutputGenex-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo;-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(CustomCommandOutputGenex)
+set(RunCMake_TEST_NO_CLEAN 1)
+unset(RunCMake_TEST_OPTIONS)
+# echo_raw
+run_ninja(CustomCommandOutputGenex echo_raw-debug build-Debug.ninja echo_raw:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_raw-debug-in-release-graph build-Release.ninja echo_raw:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_genex
+run_ninja(CustomCommandOutputGenex echo_genex-debug build-Debug.ninja echo_genex:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_genex-debug-in-release-graph build-Release.ninja echo_genex:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_genex_out
+run_ninja(CustomCommandOutputGenex echo_genex_out-debug build-Debug.ninja echo_genex_out:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_genex_out-debug-in-release-graph build-Release.ninja echo_genex_out:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_depend*
+run_ninja(CustomCommandOutputGenex echo_depend-debug build-Debug.ninja echo_depend:Debug)
+run_ninja(CustomCommandOutputGenex echo_depend_out-debug build-Debug.ninja echo_depend_out_Debug.txt)
+run_ninja(CustomCommandOutputGenex echo_depend_cmd-debug build-Debug.ninja echo_depend_cmd_Debug.txt)
+run_ninja(CustomCommandOutputGenex echo_depend-debug-in-release-graph build-Release.ninja echo_depend:Debug)
+run_ninja(CustomCommandOutputGenex echo_depend_out-debug-in-release-graph build-Release.ninja echo_depend_out_Debug.txt)
+run_ninja(CustomCommandOutputGenex echo_depend_cmd-debug-in-release-graph build-Release.ninja echo_depend_cmd_Debug.txt)
+# depend_echo_raw
+run_ninja(CustomCommandOutputGenex depend_echo_raw-debug build-Debug.ninja depend_echo_raw:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex depend_echo_raw-debug-in-release-graph build-Release.ninja depend_echo_raw:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# depend_echo_genex
+run_ninja(CustomCommandOutputGenex depend_echo_genex-debug build-Debug.ninja depend_echo_genex:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex depend_echo_genex-debug-in-release-graph build-Release.ninja depend_echo_genex:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# depend_echo_genex_out
+run_ninja(CustomCommandOutputGenex depend_echo_genex_out-debug build-Debug.ninja depend_echo_genex_out:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex depend_echo_genex_out-debug-in-release-graph build-Release.ninja depend_echo_genex_out:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# depend_echo_genex_cmd
+run_ninja(CustomCommandOutputGenex depend_echo_genex_cmd-debug build-Debug.ninja depend_echo_genex_cmd:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex depend_echo_genex_cmd-debug-in-release-graph build-Release.ninja depend_echo_genex_cmd:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# no_cross_output
+run_ninja(CustomCommandOutputGenex echo_no_cross_output-debug build-Debug.ninja echo_no_cross_output:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_no_cross_output-debug-in-release-graph build-Release.ninja echo_no_cross_output:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# no_cross_output_if
+run_ninja(CustomCommandOutputGenex echo_no_cross_output_if-debug build-Debug.ninja echo_no_cross_output_if:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_no_cross_output_if-debug-in-release-graph build-Release.ninja echo_no_cross_output_if:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# no_cross_byproduct
+run_ninja(CustomCommandOutputGenex echo_no_cross_byproduct-debug build-Debug.ninja echo_no_cross_byproduct:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_no_cross_byproduct-debug-in-release-graph build-Release.ninja echo_no_cross_byproduct:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# no_cross_byproduct_if
+run_ninja(CustomCommandOutputGenex echo_no_cross_byproduct_if-debug build-Debug.ninja echo_no_cross_byproduct_if:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_no_cross_byproduct_if-debug-in-release-graph build-Release.ninja echo_no_cross_byproduct_if:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_target_raw
+run_ninja(CustomCommandOutputGenex echo_target_raw-debug build-Debug.ninja echo_target_raw:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_target_raw-debug-in-release-graph build-Release.ninja echo_target_raw:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_target_genex
+run_ninja(CustomCommandOutputGenex echo_target_genex-debug build-Debug.ninja echo_target_genex:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_target_genex-debug-in-release-graph build-Release.ninja echo_target_genex:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_target_genex_out
+run_ninja(CustomCommandOutputGenex echo_target_genex_out-debug build-Debug.ninja echo_target_genex_out:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex echo_target_genex_out-debug-in-release-graph build-Release.ninja echo_target_genex_out:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+# echo_target_depend*
+run_ninja(CustomCommandOutputGenex echo_target_depend-debug build-Debug.ninja echo_target_depend:Debug)
+run_ninja(CustomCommandOutputGenex echo_target_depend_out-debug build-Debug.ninja echo_target_depend_out:Debug)
+run_ninja(CustomCommandOutputGenex echo_target_depend_cmd-debug build-Debug.ninja CMakeFiles/echo_target_depend_cmd-Debug) # undocumented
+run_ninja(CustomCommandOutputGenex echo_target_depend-debug-in-release-graph build-Release.ninja echo_target_depend:Debug)
+run_ninja(CustomCommandOutputGenex echo_target_depend_out-debug-in-release-graph build-Release.ninja echo_target_depend_out:Debug)
+run_ninja(CustomCommandOutputGenex echo_target_depend_cmd-debug-in-release-graph build-Release.ninja CMakeFiles/echo_target_depend_cmd-Debug) # undocumented
+# target_no_cross_*
+run_ninja(CustomCommandOutputGenex target_no_cross_byproduct-debug build-Debug.ninja target_no_cross_byproduct:Debug)
+run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
+run_ninja(CustomCommandOutputGenex target_no_cross_byproduct-debug-in-release-graph build-Release.ninja target_no_cross_byproduct:Debug)
+run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
+unset(RunCMake_TEST_NO_CLEAN)
+
 unset(RunCMake_TEST_BINARY_DIR)
 
 run_cmake(CustomCommandDepfile)
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-targets-debug-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/Simple-targets-debug-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..f72516f
--- /dev/null
@@ -0,0 +1,3 @@
+(rebuild_cache: phony.*
+edit_cache: phony|edit_cache: phony.*
+rebuild_cache: phony)
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-targets-default-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/Simple-targets-default-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..f72516f
--- /dev/null
@@ -0,0 +1,3 @@
+(rebuild_cache: phony.*
+edit_cache: phony|edit_cache: phony.*
+rebuild_cache: phony)
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-targets-release-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/Simple-targets-release-ninja-stdout.txt
new file mode 100644 (file)
index 0000000..f72516f
--- /dev/null
@@ -0,0 +1,3 @@
+(rebuild_cache: phony.*
+edit_cache: phony|edit_cache: phony.*
+rebuild_cache: phony)
diff --git a/Tests/RunCMake/NinjaMultiConfig/echo.c b/Tests/RunCMake/NinjaMultiConfig/echo.c
new file mode 100644 (file)
index 0000000..48a187f
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#if defined(_WIN32)
+#  include <direct.h>
+#  define getcwd _getcwd
+#else
+#  include <unistd.h>
+#endif
+
+int main(int argc, char** argv)
+{
+  int i;
+  char cwd[1024];
+  if (getcwd(cwd, sizeof(cwd)) != NULL) {
+    printf("'%s'$", cwd);
+  }
+  for (i = 0; i < argc; ++i) {
+    printf(" '%s'", argv[i]);
+  }
+  printf("\n");
+  return 0;
+}
diff --git a/Tests/RunCMake/ObjectLibrary/ImportMultiArch-check.cmake b/Tests/RunCMake/ObjectLibrary/ImportMultiArch-check.cmake
new file mode 100644 (file)
index 0000000..af1df78
--- /dev/null
@@ -0,0 +1,15 @@
+set(xcProjectFile "${RunCMake_TEST_BINARY_DIR}/ImportMultiArch.xcodeproj/project.pbxproj")
+if(NOT EXISTS "${xcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${xcProjectFile} does not exist.")
+  return()
+endif()
+
+file(READ ${xcProjectFile} pbxFileContents)
+foreach(config IN ITEMS Debug Release RelWithDebInfo MinSizeRel)
+  set(regex "--findconfig-${config}[^
+]*\\$\\(CURRENT_ARCH\\)")
+  if(NOT pbxFileContents MATCHES "${regex}")
+    set(RunCMake_TEST_FAILED "$(CURRENT_ARCH) not preserved for config ${config}")
+    return()
+  endif()
+endforeach()
diff --git a/Tests/RunCMake/ObjectLibrary/ImportMultiArch.cmake b/Tests/RunCMake/ObjectLibrary/ImportMultiArch.cmake
new file mode 100644 (file)
index 0000000..64029ee
--- /dev/null
@@ -0,0 +1,13 @@
+
+add_library(A OBJECT IMPORTED)
+
+# We don't actually build this example so just configure dummy
+# object files to test.  They do not have to exist.
+set_target_properties(A PROPERTIES
+  IMPORTED_OBJECTS "${CMAKE_CURRENT_BINARY_DIR}/$(CURRENT_ARCH)/does_not_exist.o"
+)
+
+add_library(B SHARED $<TARGET_OBJECTS:A> b.c)
+
+# We use this to find the relevant lines of the project.pbx file
+target_link_options(B PRIVATE --findconfig-$<CONFIG>)
diff --git a/Tests/RunCMake/ObjectLibrary/ImportNotSupported-stderr.txt b/Tests/RunCMake/ObjectLibrary/ImportNotSupported-stderr.txt
deleted file mode 100644 (file)
index 0fadac2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-CMake Error at ImportNotSupported.cmake:[0-9]+ \(add_library\):
-  The OBJECT library type may not be used for IMPORTED libraries under Xcode
-  with multiple architectures.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/ObjectLibrary/ImportNotSupported.cmake b/Tests/RunCMake/ObjectLibrary/ImportNotSupported.cmake
deleted file mode 100644 (file)
index 806b44a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-add_library(A OBJECT IMPORTED)
index 0a76932..3d60556 100644 (file)
@@ -12,4 +12,10 @@ add_executable(LinkObjLHSShared LinkObjLHSShared.c)
 target_link_libraries(LinkObjLHSShared AnObjLib)
 
 # Verify that our dependency on OtherLib generated its versioning symlinks.
+if(CMAKE_GENERATOR STREQUAL "Xcode" AND
+   "${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "Darwin;arm64")
+  # Xcode runs POST_BUILD before signing, so let the linker use ad-hoc signing.
+  # See CMake Issue 21845.
+  target_link_options(LinkObjLHSShared PRIVATE LINKER:-adhoc_codesign)
+endif()
 add_custom_command(TARGET LinkObjLHSShared POST_BUILD COMMAND LinkObjLHSShared)
index 5ec4018..8515ba5 100644 (file)
@@ -6,7 +6,7 @@ run_cmake(BadSourceExpression3)
 run_cmake(BadObjSource1)
 run_cmake(BadObjSource2)
 if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
-  run_cmake(ImportNotSupported)
+  run_cmake(ImportMultiArch)
   run_cmake(InstallNotSupported)
 else()
   run_cmake(Import)
index bb6beb2..c46d044 100644 (file)
@@ -50,6 +50,7 @@ else()
 endif()
 
 include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
+include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake)
 
 #
 # load_compiler_info: read infile, parsing out cmake compiler info
@@ -80,6 +81,7 @@ function(load_compiler_info infile lang_var outcmvars_var outstr_var)
     message("load_compiler_info: ${infile} no LANG info; default to C")
     set(lang C)
   endif()
+
   set(${lang_var} "${lang}" PARENT_SCOPE)
   set(${outcmvars_var} "${outcmvars}" PARENT_SCOPE)
   set(${outstr_var} "${outstr}" PARENT_SCOPE)
@@ -94,6 +96,21 @@ function(unload_compiler_info cmvars)
   endforeach()
 endfunction()
 
+
+#
+# load_platform_info: establish CMAKE_LIBRARY_ARCHITECTURE_REGEX
+# based on the target platform.
+#
+function(load_platform_info target)
+  if(target MATCHES "linux-")
+    set(CMAKE_LIBRARY_ARCHITECTURE_REGEX "[a-z0-9_]+(-[a-z0-9_]+)?-linux-gnu[a-z0-9_]*" PARENT_SCOPE)
+    set(CMAKE_LIBRARY_ARCHITECTURE_REGEX_VERSIONED "gcc/[a-z0-9_]+(-[a-z0-9_]+)?-linux(-gnu)?/[0-9]+(\\.[0-9]+\\.[0-9]+)*" PARENT_SCOPE)
+  else()
+    unset(CMAKE_LIBRARY_ARCHITECTURE_REGEX PARENT_SCOPE)
+    unset(CMAKE_LIBRARY_ARCHITECTURE_REGEX_VERSIONED PARENT_SCOPE)
+  endif()
+endfunction()
+
 #
 # main test loop
 #
@@ -112,10 +129,12 @@ foreach(t ${targets})
   endif()
 
   load_compiler_info(${infile} lang cmvars input)
+  load_platform_info(${t})
 
   # Need to handle files with empty entries for both libs or dirs
   set(implicit_lib_output "")
   set(idirs_output "")
+  set(library_arch_output "")
   file(STRINGS ${outfile} outputs)
   foreach(line IN LISTS outputs)
     if(line MATCHES "libs=")
@@ -124,13 +143,19 @@ foreach(t ${targets})
     if(line MATCHES "dirs=")
       string(REPLACE "dirs=" "" idirs_output "${line}")
     endif()
+    if(line MATCHES "library_arch=")
+      string(REPLACE "library_arch=" "" library_arch_output "${line}")
+    endif()
   endforeach()
 
   cmake_parse_implicit_link_info("${input}" implicit_libs idirs implicit_fwks log
       "${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}")
 
+  set(library_arch)
+  cmake_parse_library_architecture("${idirs}" library_arch)
+
   # File format
-  # file(WRITE ${outfile} "libs=${implicit_libs}\ndirs=${idirs}\n")
+  # file(WRITE ${outfile} "libs=${implicit_libs}\ndirs=${idirs}\nlibrary_arch=${library_arch}")
 
   if(t MATCHES "-empty$")          # empty isn't supposed to parse
     if("${state}" STREQUAL "done")
@@ -140,6 +165,8 @@ foreach(t ${targets})
     message("${t} parse failed: state=${state}, '${idirs}' does not match '${idirs_output}'")
   elseif(NOT "${implicit_libs}" STREQUAL "${implicit_lib_output}")
     message("${t} parse failed: state=${state}, '${implicit_libs}' does not match '${implicit_lib_output}'")
+  elseif(library_arch AND NOT "${library_arch}" STREQUAL "${library_arch_output}")
+    message("${t} parse failed: state=${state}, '${library_arch}' does not match '${library_arch_output}'")
   endif()
 
   unload_compiler_info("${cmvars}")
index 63b51a1..0cf3a49 100644 (file)
@@ -1,2 +1,3 @@
 libs=gcc;gcc_s;c;gcc;gcc_s
 dirs=/usr/lib/gcc/x86_64-linux-gnu/7;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib
+library_arch=x86_64-linux-gnu
index b61e097..55852c0 100644 (file)
@@ -1,2 +1,3 @@
 libs=imf;svml;irng;m;ipgo;decimal;cilkrts;stdc++;gcc;gcc_s;irc;svml;c;gcc;gcc_s;irc_s;dl;c
 dirs=/opt/intel/compilers_and_libraries_2018.0.128/linux/ipp/lib/intel64;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/lib/intel64_lin;/opt/intel/compilers_and_libraries_2018.0.128/linux/mkl/lib/intel64_lin;/opt/intel/compilers_and_libraries_2018.0.128/linux/tbb/lib/intel64/gcc4.7;/usr/lib/gcc/x86_64-redhat-linux/4.8.5;/usr/lib64;/lib64;/usr/lib;/lib
+library_arch=x86_64-redhat-linux
index 7b20915..7931102 100644 (file)
@@ -1,2 +1,3 @@
 libs=pgmp;numa;pthread;pgmath;nspgc;pgc;m;gcc;c;gcc;gcc_s
 dirs=/mnt/pgi/linux86-64/18.10/lib;/usr/lib64;/usr/lib/gcc/x86_64-linux-gnu/7
+library_arch=x86_64-linux-gnu
index de407f2..de8c8eb 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlopt;xl;dl;gcc_s;gcc;m;c;gcc_s;gcc
 dirs=/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/lib64;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/lib64;/soft/compilers/ibmcmp-oct2017/vac/bg/12.1/lib64;/soft/compilers/ibmcmp-oct2017/vacpp/bg/12.1/lib64;/usr/lib/gcc/ppc64-redhat-linux/4.4.7;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64-redhat-linux
index de515e7..cd672d5 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlopt;xl;dl;gcc_s;pthread;gcc;m;c;gcc_s;gcc
 dirs=/opt/ibm/xlsmp/5.1.0/lib;/opt/ibm/xlmass/9.1.0/lib;/opt/ibm/xlC/16.1.0/lib;/usr/lib/gcc/ppc64le-redhat-linux/4.8.5;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64le-redhat-linux
index a657b85..813457a 100644 (file)
@@ -1,2 +1,3 @@
 libs=cudadevrt;cudart_static;rt;pthread;dl;stdc++;m;gcc_s;gcc;c;gcc_s;gcc
 dirs=/usr/local/cuda/targets/x86_64-linux/lib/stubs;/usr/local/cuda/targets/x86_64-linux/lib;/usr/lib/gcc/x86_64-linux-gnu/8;/usr/lib/x86_64-linux-gnu;/lib/x86_64-linux-gnu;/lib64;/usr/lib;/usr/lib/llvm-8/lib;/lib
+library_arch=x86_64-linux-gnu
index 58ae64d..8824772 100644 (file)
@@ -1,2 +1,3 @@
 libs=cudadevrt;cudart_static;rt;pthread;dl;xlopt;xl;ibmc++;stdc++;m;dl;gcc_s;gcc;pthread;m;c;gcc_s;gcc
 dirs=/sw/summit/cuda/10.1.168/targets/ppc64le-linux/lib/stubs;/sw/summit/cuda/10.1.168/targets/ppc64le-linux/lib;/autofs/nccs-svm1_sw/summit/.swci/1-compute/opt/spack/20180914/linux-rhel7-ppc64le/xl-16.1.1-3/spectrum-mpi-10.3.0.1-20190611-aqjt3jo53mogrrhcrd2iufr435azcaha/lib;/autofs/nccs-svm1_sw/summit/.swci/1-compute/opt/spack/20180914/linux-rhel7-ppc64le/gcc-4.8.5/darshan-runtime-3.1.7-csygoqyym3m3ysoaperhxlhoiluvpa2u/lib;/autofs/nccs-svm1_sw/summit/xl/16.1.1-3/xlsmp/5.1.1/lib;/autofs/nccs-svm1_sw/summit/xl/16.1.1-3/xlmass/9.1.1/lib;/autofs/nccs-svm1_sw/summit/xl/16.1.1-3/xlC/16.1.1/lib;/usr/lib/gcc/ppc64le-redhat-linux/4.8.5;/usr/lib64;/lib64;/autofs/nccs-svm1_sw/peak/.swci/1-compute/opt/spack/20180914/linux-rhel7-ppc64le/gcc-4.8.5/darshan-runtime-3.1.7-ytwv7xbkub6mqnpvygdthwqa7mhjqbc5/lib;/usr/lib
+library_arch=ppc64le-redhat-linux
index 7c99bf6..275fe40 100644 (file)
@@ -1,2 +1,3 @@
 libs=cudadevrt;cudart_static;rt;pthread;dl;stdc++;m;gcc_s;gcc;c;gcc_s;gcc
 dirs=/usr/lib/x86_64-linux-gnu/stubs;/usr/lib/gcc/x86_64-linux-gnu/5;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib
+library_arch=x86_64-linux-gnu
index 4fc7937..4957f5c 100644 (file)
@@ -1,2 +1,3 @@
 libs=stdc++;m;gcc_s;gcc;c;gcc_s;gcc
 dirs=/usr/lib/gcc/x86_64-linux-gnu/7;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib
+library_arch=x86_64-linux-gnu
index 5d85789..6a2a105 100644 (file)
@@ -1,2 +1,3 @@
 libs=imf;svml;irng;stdc++;m;ipgo;decimal;cilkrts;stdc++;gcc;gcc_s;irc;svml;c;gcc;gcc_s;irc_s;dl;c
 dirs=/opt/intel/compilers_and_libraries_2018.0.128/linux/ipp/lib/intel64;/opt/intel/compilers_and_libraries_2018.0.128/linux/compiler/lib/intel64_lin;/opt/intel/compilers_and_libraries_2018.0.128/linux/mkl/lib/intel64_lin;/opt/intel/compilers_and_libraries_2018.0.128/linux/tbb/lib/intel64/gcc4.7;/usr/lib/gcc/x86_64-redhat-linux/4.8.5;/usr/lib64;/lib64;/usr/lib;/lib
+library_arch=x86_64-redhat-linux
index db0b29c..cd15054 100644 (file)
@@ -1,2 +1,3 @@
 libs=atomic;pgatm;stdc++;pgmp;numa;pthread;pgmath;nspgc;pgc;m;gcc;c;gcc;gcc_s
 dirs=/mnt/pgi/linux86-64/18.10/lib;/usr/lib64;/usr/lib/gcc/x86_64-linux-gnu/7
+library_arch=x86_64-linux-gnu
index 4466415..9fbc844 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlopt;xl;ibmc++;xlopt;xl;stdc++;m;dl;gcc_s;gcc;m;c;gcc_s;gcc;dl;gcc_s;gcc;m;c;gcc_s;gcc
 dirs=/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/lib64;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/lib64;/soft/compilers/ibmcmp-oct2017/vac/bg/12.1/lib64;/soft/compilers/ibmcmp-oct2017/vacpp/bg/12.1/lib64;/usr/lib/gcc/ppc64-redhat-linux/4.4.7;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64-redhat-linux
index 8124911..4e9ab0a 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlopt;xl;ibmc++;stdc++;m;dl;gcc_s;gcc;pthread;m;c;gcc_s;gcc
 dirs=/opt/ibm/xlsmp/5.1.0/lib;/opt/ibm/xlmass/9.1.0/lib;/opt/ibm/xlC/16.1.0/lib;/usr/lib/gcc/ppc64le-redhat-linux/4.8.5;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64le-redhat-linux
index f985a03..09b720e 100644 (file)
@@ -1,2 +1,3 @@
 libs=gfortran;m;gcc_s;gcc;quadmath;m;gcc_s;gcc;c;gcc_s;gcc
 dirs=/usr/lib/gcc/x86_64-linux-gnu/7;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib
+library_arch=x86_64-linux-gnu
index d40f81e..f3cc551 100644 (file)
@@ -1,2 +1,3 @@
 libs=pgf90rtl;pgf90;pgf90_rpm1;pgf902;pgf90rtl;pgftnrtl;pgmp;numa;pthread;pgmath;nspgc;pgc;rt;pthread;m;gcc;c;gcc;gcc_s
 dirs=/mnt/pgi/linux86-64/18.10/lib;/usr/lib64;/usr/lib/gcc/x86_64-linux-gnu/7
+library_arch=x86_64-linux-gnu
index 3c5d23b..68be4c5 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlf90;xlopt;xlomp_ser;xl;xlfmath;gcc_s;dl;rt;pthread;gcc;m;c;gcc_s;gcc
 dirs=/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/lib64;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/lib64;/soft/compilers/ibmcmp-oct2017/xlf/bg/14.1/lib64;/usr/lib/gcc/ppc64-redhat-linux/4.4.7;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64-redhat-linux
index 7b20915..e44c84d 100644 (file)
@@ -1,2 +1,3 @@
 libs=pgmp;numa;pthread;pgmath;nspgc;pgc;m;gcc;c;gcc;gcc_s
 dirs=/mnt/pgi/linux86-64/18.10/lib;/usr/lib64;/usr/lib/gcc/x86_64-linux-gnu/7
+library_arch=x86_64-linux-gnu2
index de407f2..de8c8eb 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlopt;xl;dl;gcc_s;gcc;m;c;gcc_s;gcc
 dirs=/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/lib64;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/lib64;/soft/compilers/ibmcmp-oct2017/vac/bg/12.1/lib64;/soft/compilers/ibmcmp-oct2017/vacpp/bg/12.1/lib64;/usr/lib/gcc/ppc64-redhat-linux/4.4.7;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64-redhat-linux
index db0b29c..cd15054 100644 (file)
@@ -1,2 +1,3 @@
 libs=atomic;pgatm;stdc++;pgmp;numa;pthread;pgmath;nspgc;pgc;m;gcc;c;gcc;gcc_s
 dirs=/mnt/pgi/linux86-64/18.10/lib;/usr/lib64;/usr/lib/gcc/x86_64-linux-gnu/7
+library_arch=x86_64-linux-gnu
index 4466415..9fbc844 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlopt;xl;ibmc++;xlopt;xl;stdc++;m;dl;gcc_s;gcc;m;c;gcc_s;gcc;dl;gcc_s;gcc;m;c;gcc_s;gcc
 dirs=/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/lib64;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/lib64;/soft/compilers/ibmcmp-oct2017/vac/bg/12.1/lib64;/soft/compilers/ibmcmp-oct2017/vacpp/bg/12.1/lib64;/usr/lib/gcc/ppc64-redhat-linux/4.4.7;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64-redhat-linux
index d40f81e..f3cc551 100644 (file)
@@ -1,2 +1,3 @@
 libs=pgf90rtl;pgf90;pgf90_rpm1;pgf902;pgf90rtl;pgftnrtl;pgmp;numa;pthread;pgmath;nspgc;pgc;rt;pthread;m;gcc;c;gcc;gcc_s
 dirs=/mnt/pgi/linux86-64/18.10/lib;/usr/lib64;/usr/lib/gcc/x86_64-linux-gnu/7
+library_arch=x86_64-linux-gnu
index de407f2..de8c8eb 100644 (file)
@@ -1,2 +1,3 @@
 libs=xlopt;xl;dl;gcc_s;gcc;m;c;gcc_s;gcc
 dirs=/soft/compilers/ibmcmp-oct2017/xlsmp/bg/3.1/lib64;/soft/compilers/ibmcmp-oct2017/xlmass/bg/7.3/lib64;/soft/compilers/ibmcmp-oct2017/vac/bg/12.1/lib64;/soft/compilers/ibmcmp-oct2017/vacpp/bg/12.1/lib64;/usr/lib/gcc/ppc64-redhat-linux/4.4.7;/usr/lib64;/lib64;/usr/lib
+library_arch=ppc64-redhat-linux
index 7b523ea..8f68358 100644 (file)
@@ -1,2 +1,3 @@
 libs=pgftnrtl;pgmp;numa;pthread;pgmath;nspgc;pgc;rt;pthread;m;gcc;c;gcc;gcc_s
 dirs=/mnt/pgi/linux86-64/18.10/lib;/usr/lib64;/usr/lib/gcc/x86_64-linux-gnu/7
+library_arch=x86_64-linux-gnu
diff --git a/Tests/RunCMake/Policy/CMakeLists.txt b/Tests/RunCMake/Policy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..667561e
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/Policy/InvalidMaxVersion-result.txt b/Tests/RunCMake/Policy/InvalidMaxVersion-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Policy/InvalidMaxVersion-stderr.txt b/Tests/RunCMake/Policy/InvalidMaxVersion-stderr.txt
new file mode 100644 (file)
index 0000000..25d22f5
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at InvalidMaxVersion.cmake:[0-9]+ \(cmake_policy\):
+  Invalid policy max version value "[A-Za-z0-9]+.[A-Za-z0-9]*.[A-Za-z0-9]*.[A-Za-z0-9]*"\.  A numeric
+  major.minor\[\.patch\[\.tweak\]\] must be given\.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/InvalidMaxVersion.cmake b/Tests/RunCMake/Policy/InvalidMaxVersion.cmake
new file mode 100644 (file)
index 0000000..be3270f
--- /dev/null
@@ -0,0 +1,5 @@
+if(NOT version)
+  message(SEND_ERROR "Vesrion string is empty: ${version}")
+endif()
+
+cmake_policy(VERSION 3.1...${version})
diff --git a/Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-result.txt b/Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-result.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-stderr.txt b/Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven-stderr.txt
new file mode 100644 (file)
index 0000000..a48feb3
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at InvalidRangeMaxVersionNotGiven.cmake:[0-9]+ \(cmake_policy\):
+  cmake_policy VERSION "3.15..." does not have a version on both sides of
+  "...".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven.cmake b/Tests/RunCMake/Policy/InvalidRangeMaxVersionNotGiven.cmake
new file mode 100644 (file)
index 0000000..e55803c
--- /dev/null
@@ -0,0 +1 @@
+cmake_policy(VERSION 3.15...)
diff --git a/Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-result.txt b/Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-stderr.txt b/Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven-stderr.txt
new file mode 100644 (file)
index 0000000..84e9b88
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at InvalidRangeMinVersionNotGiven.cmake:[0-9]+ \(cmake_policy\):
+  cmake_policy VERSION "...3.15" does not have a version on both sides of
+  "...".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven.cmake b/Tests/RunCMake/Policy/InvalidRangeMinVersionNotGiven.cmake
new file mode 100644 (file)
index 0000000..60e7e25
--- /dev/null
@@ -0,0 +1 @@
+cmake_policy(VERSION ...3.15)
diff --git a/Tests/RunCMake/Policy/InvalidVersion-result.txt b/Tests/RunCMake/Policy/InvalidVersion-result.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/Policy/InvalidVersion-stderr.txt b/Tests/RunCMake/Policy/InvalidVersion-stderr.txt
new file mode 100644 (file)
index 0000000..783f4ed
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at InvalidVersion.cmake:[0-9]+ \(cmake_policy\):
+  Invalid policy version value "[A-Za-z0-9]+.[A-Za-z0-9]*.[A-Za-z0-9]*.[A-Za-z0-9]*"\.  A numeric
+  major\.minor\[\.patch\[\.tweak\]\] must be given\.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/InvalidVersion.cmake b/Tests/RunCMake/Policy/InvalidVersion.cmake
new file mode 100644 (file)
index 0000000..b135ba6
--- /dev/null
@@ -0,0 +1,5 @@
+if(NOT version)
+  message(SEND_ERROR "Vesrion string is empty: ${version}")
+endif()
+
+cmake_policy(VERSION ${version})
diff --git a/Tests/RunCMake/Policy/MinVersionLargerThanMax-result.txt b/Tests/RunCMake/Policy/MinVersionLargerThanMax-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt b/Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt
new file mode 100644 (file)
index 0000000..0b0308f
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at MinVersionLargerThanMax.cmake:[0-9]+ \(cmake_policy\):
+  Policy VERSION range "3.12...3.8" specifies a larger minimum than maximum.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/MinVersionLargerThanMax.cmake b/Tests/RunCMake/Policy/MinVersionLargerThanMax.cmake
new file mode 100644 (file)
index 0000000..67d5f85
--- /dev/null
@@ -0,0 +1 @@
+cmake_policy(VERSION 3.12...3.8)
diff --git a/Tests/RunCMake/Policy/RunCMakeTest.cmake b/Tests/RunCMake/Policy/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..74c7d63
--- /dev/null
@@ -0,0 +1,19 @@
+include(RunCMake)
+
+run_cmake(VersionNotGiven)
+run_cmake(TooManyVersionsGiven)
+run_cmake(InvalidRangeMinVersionNotGiven)
+run_cmake(InvalidRangeMaxVersionNotGiven)
+
+set(RunCMake_TEST_OPTIONS "-Dversion=three")
+run_cmake(InvalidVersion)
+run_cmake(InvalidMaxVersion)
+unset(RunCMake_TEST_OPTIONS)
+set(RunCMake_TEST_OPTIONS "-Dversion=3.one")
+run_cmake(InvalidVersion)
+run_cmake(InvalidMaxVersion)
+unset(RunCMake_TEST_OPTIONS)
+
+run_cmake(VersionLowerThan2_4)
+run_cmake(MinVersionLargerThanMax)
+run_cmake(VeryHighVersion)
diff --git a/Tests/RunCMake/Policy/TooManyVersionsGiven-result.txt b/Tests/RunCMake/Policy/TooManyVersionsGiven-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Policy/TooManyVersionsGiven-stderr.txt b/Tests/RunCMake/Policy/TooManyVersionsGiven-stderr.txt
new file mode 100644 (file)
index 0000000..7a4f8c7
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at TooManyVersionsGiven.cmake:[0-9]+ \(cmake_policy\):
+  cmake_policy VERSION given too many arguments
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/TooManyVersionsGiven.cmake b/Tests/RunCMake/Policy/TooManyVersionsGiven.cmake
new file mode 100644 (file)
index 0000000..6c99af2
--- /dev/null
@@ -0,0 +1 @@
+cmake_policy(VERSION 1 2 3)
diff --git a/Tests/RunCMake/Policy/VersionLowerThan2_4-result.txt b/Tests/RunCMake/Policy/VersionLowerThan2_4-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Policy/VersionLowerThan2_4-stderr.txt b/Tests/RunCMake/Policy/VersionLowerThan2_4-stderr.txt
new file mode 100644 (file)
index 0000000..3f19192
--- /dev/null
@@ -0,0 +1,6 @@
+CMake Error at VersionLowerThan2_4.cmake:[0-9]+ \(cmake_policy\):
+  Compatibility with CMake < 2.4 is not supported by CMake >= 3.0.  For
+  compatibility with older versions please use any CMake 2.8.x release or
+  lower.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/VersionLowerThan2_4.cmake b/Tests/RunCMake/Policy/VersionLowerThan2_4.cmake
new file mode 100644 (file)
index 0000000..f1a4fd9
--- /dev/null
@@ -0,0 +1 @@
+cmake_policy(VERSION 2.2)
diff --git a/Tests/RunCMake/Policy/VersionNotGiven-result.txt b/Tests/RunCMake/Policy/VersionNotGiven-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Policy/VersionNotGiven-stderr.txt b/Tests/RunCMake/Policy/VersionNotGiven-stderr.txt
new file mode 100644 (file)
index 0000000..8eeb177
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at VersionNotGiven.cmake:[0-9]+ \(cmake_policy\):
+  cmake_policy VERSION not given an argument
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/VersionNotGiven.cmake b/Tests/RunCMake/Policy/VersionNotGiven.cmake
new file mode 100644 (file)
index 0000000..53b3d7f
--- /dev/null
@@ -0,0 +1 @@
+cmake_policy(VERSION)
diff --git a/Tests/RunCMake/Policy/VeryHighVersion-result.txt b/Tests/RunCMake/Policy/VeryHighVersion-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Policy/VeryHighVersion-stderr.txt b/Tests/RunCMake/Policy/VeryHighVersion-stderr.txt
new file mode 100644 (file)
index 0000000..7cca91b
--- /dev/null
@@ -0,0 +1,7 @@
+CMake Error at VeryHighVersion.cmake:[0-9]+ \(cmake_policy\):
+  An attempt was made to set the policy version of CMake to "99.1" which is
+  greater than this version of CMake.  This is not allowed because the
+  greater version may have new policies not known to this CMake.  You may
+  need a newer CMake version to build this project.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/Policy/VeryHighVersion.cmake b/Tests/RunCMake/Policy/VeryHighVersion.cmake
new file mode 100644 (file)
index 0000000..3d4af8c
--- /dev/null
@@ -0,0 +1 @@
+cmake_policy(VERSION 99.1)
diff --git a/Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake b/Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake
new file mode 100644 (file)
index 0000000..9ec1b36
--- /dev/null
@@ -0,0 +1,15 @@
+enable_language(C)
+enable_language(CXX)
+
+add_executable(main
+  no_pch.c
+  use_pch.cxx
+)
+
+target_include_directories(main PUBLIC include)
+target_precompile_headers(main PRIVATE
+  "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/include/cxx_pch.h>"
+  )
+
+enable_testing()
+add_test(NAME main COMMAND main)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake
new file mode 100644 (file)
index 0000000..ba504a3
--- /dev/null
@@ -0,0 +1,131 @@
+cmake_minimum_required(VERSION 3.18)
+
+project(PchReuseFromObjLib)
+
+set(CMAKE_PCH_WARN_INVALID OFF)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/CONFIG/config.hxx "/*empty*/\n")
+
+file(WRITE ${CMAKE_BINARY_DIR}/pch.cxx [=[
+void nothing()
+{
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/string.hxx [=[
+#include <string.h>
+
+namespace std {
+  struct string
+  {
+    char storage[20];
+
+    string(const char* s) {
+      strcpy(storage, s);
+    }
+
+    const char* c_str() const {
+      return storage;
+    }
+  };
+}
+]=])
+
+add_library(pch-generator OBJECT ${CMAKE_BINARY_DIR}/pch.cxx)
+set_property(TARGET pch-generator PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_precompile_headers(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/string.hxx)
+
+target_include_directories(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/CONFIG)
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.cxx [=[
+#include "message.hxx"
+
+#ifndef HAVE_PCH_SUPPORT
+  #include "string.hxx"
+#endif
+
+const char* message()
+{
+  static std::string greeting("hi there");
+  return greeting.c_str();
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.hxx [=[
+#include "config.hxx"
+#ifdef WIN32_BUILD_SHARED
+  #ifdef BUILD_LIBRARY
+    #define MESSAGE_EXPORT __declspec(dllexport)
+  #else
+    #define MESSAGE_EXPORT __declspec(dllimport)
+  #endif
+#else
+  #define MESSAGE_EXPORT
+#endif
+
+MESSAGE_EXPORT const char* message();
+]=])
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/main.cxx [=[
+#include "message.hxx"
+#include <string.h>
+
+int main()
+{
+  return strcmp(message(), "hi there");
+}
+]=])
+
+######################################################################
+
+enable_testing()
+
+function(add_library_and_executable type)
+  add_library(message_${type} ${type} ${CMAKE_BINARY_DIR}/message.cxx)
+  target_precompile_headers(message_${type} REUSE_FROM pch-generator)
+
+  set_property(TARGET message_${type} PROPERTY POSITION_INDEPENDENT_CODE ON)
+  set_property(TARGET message_${type} PROPERTY DEFINE_SYMBOL "")
+
+  if (WIN32 AND type STREQUAL "SHARED")
+    file(WRITE ${CMAKE_BINARY_DIR}/SHARED/config.hxx [=[
+      #define BUILD_LIBRARY
+      #define WIN32_BUILD_SHARED
+    ]=])
+    target_include_directories(message_${type} PRIVATE ${CMAKE_BINARY_DIR}/SHARED)
+
+    # Workaround for VS2008, the compiler fails with
+    # c1xx : fatal error C1083: Cannot open source file: '_WINDLL': No such file or directory
+    file(WRITE ${CMAKE_BINARY_DIR}/_WINDLL "/*empty*/\n")
+  else()
+    target_include_directories(message_${type} PRIVATE ${CMAKE_BINARY_DIR}/CONFIG)
+  endif()
+
+  add_executable(main_${type} ${CMAKE_BINARY_DIR}/main.cxx)
+  target_include_directories(main_${type} PRIVATE ${CMAKE_BINARY_DIR})
+
+  if (WIN32 AND type STREQUAL "SHARED")
+    file(WRITE ${CMAKE_BINARY_DIR}/main_SHARED/config.hxx "#define WIN32_BUILD_SHARED\n")
+    target_include_directories(main_${type} PRIVATE ${CMAKE_BINARY_DIR}/main_SHARED)
+  else()
+    target_include_directories(main_${type} PRIVATE ${CMAKE_BINARY_DIR}/CONFIG)
+  endif()
+
+  target_link_libraries(main_${type} PRIVATE message_${type})
+
+  add_test(NAME main_${type} COMMAND main_${type})
+endfunction()
+
+foreach(type OBJECT STATIC SHARED)
+  add_library_and_executable(${type})
+endforeach()
index 74670ba..8cc59d2 100644 (file)
@@ -14,6 +14,7 @@ run_cmake(PchDebugGenex)
 run_test(PchInterface)
 run_cmake(PchPrologueEpilogue)
 run_test(SkipPrecompileHeaders)
+run_test(CXXnotC)
 run_test(PchReuseFrom)
 run_test(PchReuseFromPrefixed)
 run_test(PchReuseFromSubdir)
@@ -26,3 +27,4 @@ if(RunCMake_GENERATOR MATCHES "Make|Ninja")
     run_cmake(PchInstantiateTemplates)
   endif()
 endif()
+run_test(PchReuseFromObjLib)
diff --git a/Tests/RunCMake/PrecompileHeaders/include/cxx_pch.h b/Tests/RunCMake/PrecompileHeaders/include/cxx_pch.h
new file mode 100644 (file)
index 0000000..3282cec
--- /dev/null
@@ -0,0 +1 @@
+#define CXX_PCH
diff --git a/Tests/RunCMake/PrecompileHeaders/no_pch.c b/Tests/RunCMake/PrecompileHeaders/no_pch.c
new file mode 100644 (file)
index 0000000..8d22580
--- /dev/null
@@ -0,0 +1,7 @@
+#ifdef CXX_PCH
+#  error "CXX PCH included in C source."
+#endif
+int no_pch(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/PrecompileHeaders/use_pch.cxx b/Tests/RunCMake/PrecompileHeaders/use_pch.cxx
new file mode 100644 (file)
index 0000000..caf115b
--- /dev/null
@@ -0,0 +1,9 @@
+#include "cxx_pch.h"
+#ifndef CXX_PCH
+#  error "CXX PCH not included in CXX source."
+#endif
+extern "C" int no_pch(void);
+int main()
+{
+  return no_pch();
+}
index 1a69059..a26f632 100644 (file)
@@ -214,11 +214,6 @@ function(run_cmake_command test)
   run_cmake(${test})
 endfunction()
 
-function(run_cmake_script test)
-  set(RunCMake_TEST_COMMAND ${CMAKE_COMMAND} ${ARGN} -P ${RunCMake_SOURCE_DIR}/${test}.cmake)
-  run_cmake(${test})
-endfunction()
-
 function(run_cmake_with_options test)
   set(RunCMake_TEST_OPTIONS "${ARGN}")
   run_cmake(${test})
index 306c255..87fa746 100644 (file)
@@ -1,8 +1,4 @@
-^CMake Error in FunctionUnmatched.cmake:
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/FunctionUnmatched.cmake:[0-9]+ \(function\)
-
-  is not closed.
+^CMake Error at FunctionUnmatched\.cmake:[0-9]+ \(function\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
index f4ff709..7904b87 100644 (file)
@@ -1,8 +1,4 @@
-^CMake Error at FunctionUnmatchedForeach.cmake:[0-9]+ \(f\):
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/FunctionUnmatchedForeach.cmake:[0-9]+ \(foreach\)
-
-  is not closed.
+^CMake Error at FunctionUnmatchedForeach\.cmake:[0-9]+ \(endfunction\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/Syntax/ImproperNesting-result.txt b/Tests/RunCMake/Syntax/ImproperNesting-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt b/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt
new file mode 100644 (file)
index 0000000..a209ef6
--- /dev/null
@@ -0,0 +1,4 @@
+^CMake Error at ImproperNesting\.cmake:[0-9]+ \(endforeach\):
+  Flow control statements are not properly nested\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/Syntax/ImproperNesting.cmake b/Tests/RunCMake/Syntax/ImproperNesting.cmake
new file mode 100644 (file)
index 0000000..47ff9f9
--- /dev/null
@@ -0,0 +1,7 @@
+message(FATAL_ERROR "This should not happen")
+
+foreach(i 1 2)
+  if(1)
+endforeach()
+endif()
+endif()
index 440d863..a7af590 100644 (file)
@@ -1,8 +1,4 @@
-^CMake Error in MacroUnmatched.cmake:
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/MacroUnmatched.cmake:[0-9]+ \(macro\)
-
-  is not closed.
+^CMake Error at MacroUnmatched\.cmake:[0-9]+ \(macro\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
index 820cd2e..30c4a4c 100644 (file)
@@ -1,8 +1,4 @@
-^CMake Error at MacroUnmatchedForeach.cmake:[0-9]+ \(m\):
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/Syntax/MacroUnmatchedForeach.cmake:[0-9]+ \(foreach\)
-
-  is not closed.
+^CMake Error at MacroUnmatchedForeach\.cmake:[0-9]+ \(endmacro\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
index cf6dad5..71e8db3 100644 (file)
@@ -7,6 +7,6 @@
 
     \${var
 
-  syntax error, unexpected \$end, expecting } \(6\)
+  syntax error, unexpected end of file, expecting } \(6\)
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)$
index 70e7c12..84ccdbe 100644 (file)
@@ -7,6 +7,6 @@
 
     \${var
 
-  syntax error, unexpected \$end, expecting } \(6\)
+  syntax error, unexpected end of file, expecting } \(6\)
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/Syntax/Override.cmake b/Tests/RunCMake/Syntax/Override.cmake
new file mode 100644 (file)
index 0000000..af62db1
--- /dev/null
@@ -0,0 +1,6 @@
+function(override)
+  function(${FUNCTION_NAME})
+  endfunction()
+endfunction()
+override()
+message(FATAL_ERROR "This shouldn't happen")
diff --git a/Tests/RunCMake/Syntax/OverrideBreak-result.txt b/Tests/RunCMake/Syntax/OverrideBreak-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideContinue-result.txt b/Tests/RunCMake/Syntax/OverrideContinue-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideElse-result.txt b/Tests/RunCMake/Syntax/OverrideElse-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideElseIf-result.txt b/Tests/RunCMake/Syntax/OverrideElseIf-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideEndForeach-result.txt b/Tests/RunCMake/Syntax/OverrideEndForeach-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideEndFunction-result.txt b/Tests/RunCMake/Syntax/OverrideEndFunction-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideEndIf-result.txt b/Tests/RunCMake/Syntax/OverrideEndIf-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideEndMacro-result.txt b/Tests/RunCMake/Syntax/OverrideEndMacro-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideEndWhile-result.txt b/Tests/RunCMake/Syntax/OverrideEndWhile-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideForeach-result.txt b/Tests/RunCMake/Syntax/OverrideForeach-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideFunction-result.txt b/Tests/RunCMake/Syntax/OverrideFunction-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideIf-result.txt b/Tests/RunCMake/Syntax/OverrideIf-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideMacro-result.txt b/Tests/RunCMake/Syntax/OverrideMacro-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideReturn-result.txt b/Tests/RunCMake/Syntax/OverrideReturn-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Syntax/OverrideWhile-result.txt b/Tests/RunCMake/Syntax/OverrideWhile-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
index 144b57c..24c810b 100644 (file)
@@ -9,12 +9,12 @@ This warning is for project developers.  Use -Wno-dev to suppress it.
 CMake Error at ParenInENV.cmake:2 \(message\):
   Syntax error in cmake code at
 
-    .*Tests/RunCMake/Syntax/ParenInENV.cmake:2
+    .*/Tests/RunCMake/Syntax/ParenInENV.cmake:2
 
   when parsing string
 
     -->\$ENV{e
 
-  syntax error, unexpected \$end, expecting } \(10\)
+  syntax error, unexpected end of file, expecting } \(10\)
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
index 8d74dc1..4d24657 100644 (file)
@@ -72,6 +72,7 @@ run_cmake(UnterminatedBrace2)
 run_cmake(UnterminatedBracket0)
 run_cmake(UnterminatedBracket1)
 run_cmake(UnterminatedBracketComment)
+run_cmake(ImproperNesting)
 
 # Variable expansion tests
 run_cmake(ExpandInAt)
@@ -122,3 +123,30 @@ run_cmake(FunctionUnmatched)
 run_cmake(FunctionUnmatchedForeach)
 run_cmake(MacroUnmatched)
 run_cmake(MacroUnmatchedForeach)
+
+function(run_override name)
+  string(TOLOWER "${name}" lname)
+  set(RunCMake_DEFAULT_stderr "^CMake Error at [^
+]*/Tests/RunCMake/Syntax/Override\\.cmake:[0-9]+ \\(function\\):
+  Built-in flow control command \"${lname}\" cannot be overridden\\.
+Call Stack \\(most recent call first\\):
+  [^
+]*/Tests/RunCMake/Syntax/Override\\.cmake:[0-9]+ \\(override\\)$")
+  run_cmake_command(Override${name} "${CMAKE_COMMAND}" -DFUNCTION_NAME=${name} -P "${RunCMake_SOURCE_DIR}/Override.cmake")
+endfunction()
+
+run_override(Break)
+run_override(Continue)
+run_override(Else)
+run_override(ElseIf)
+run_override(EndForeach)
+run_override(EndFunction)
+run_override(EndIf)
+run_override(EndMacro)
+run_override(EndWhile)
+run_override(Foreach)
+run_override(Function)
+run_override(If)
+run_override(Macro)
+run_override(Return)
+run_override(While)
index cf63dbe..b309c3b 100644 (file)
@@ -7,6 +7,6 @@ CMake Error at UnterminatedBrace0.cmake:2 \(set\):
 
     \${
 
-  syntax error, unexpected \$end, expecting } \(3\)
+  syntax error, unexpected end of file, expecting } \(3\)
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
index 0e6f786..ffe0e2a 100644 (file)
@@ -7,7 +7,7 @@ CMake Warning \(dev\) at UnterminatedBrace1.cmake:3 \(set\):
 
     \${
 
-  syntax error, unexpected \$end, expecting } \(3\)
+  syntax error, unexpected end of file, expecting } \(3\)
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 This warning is for project developers.  Use -Wno-dev to suppress it.
index 44b5d30..e9a0a3f 100644 (file)
@@ -1,3 +1,3 @@
 cmake_minimum_required(VERSION 3.3)
-project(${RunCMake_TEST})
+project(${RunCMake_TEST} LANGUAGES NONE)
 include(${RunCMake_TEST}.cmake)
index 30b9fee..d2b3032 100644 (file)
@@ -2,3 +2,7 @@ include(RunCMake)
 
 run_cmake(NoTarget)
 run_cmake(NotObjlibTarget)
+
+if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
+  run_cmake(XcodeVariableNoGenexExpansion)
+endif()
diff --git a/Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-result.txt b/Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-stderr.txt b/Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion-stderr.txt
new file mode 100644 (file)
index 0000000..1360015
--- /dev/null
@@ -0,0 +1,10 @@
+CMake Error at XcodeVariableNoGenexExpansion\.cmake:9 \(file\):
+  Error evaluating generator expression:
+
+    \$\<TARGET_OBJECTS:A\>
+
+  The evaluation of the TARGET_OBJECTS generator expression is only suitable
+  for consumption by CMake \(limited under Xcode with multiple architectures\)\.
+  It is not suitable for writing out elsewhere\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion.cmake b/Tests/RunCMake/TargetObjects/XcodeVariableNoGenexExpansion.cmake
new file mode 100644 (file)
index 0000000..83d7210
--- /dev/null
@@ -0,0 +1,12 @@
+add_library(A OBJECT IMPORTED)
+
+# We don't actually build this example so just configure a dummy
+# object file to test.  It does not have to exist.
+set_target_properties(A PROPERTIES
+  IMPORTED_OBJECTS "${CMAKE_CURRENT_BINARY_DIR}/$(CURRENT_ARCH)/does_not_exist.o"
+)
+
+file(GENERATE
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/objects.txt
+  CONTENT "$<TARGET_OBJECTS:A>"
+)
index b3f3a5e..3846d7c 100644 (file)
@@ -34,6 +34,7 @@
    \* CMP0108
    \* CMP0112
    \* CMP0113
+   \* CMP0119
 
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetCheckProperty.cmake b/Tests/RunCMake/TargetSources/AddCustomTargetCheckProperty.cmake
new file mode 100644 (file)
index 0000000..1787e87
--- /dev/null
@@ -0,0 +1,16 @@
+add_custom_target(target1 ALL)
+target_sources(target1 PRIVATE main.cpp)
+get_property(actualProp1 TARGET target1 PROPERTY SOURCES)
+set(desiredProp1 main.cpp)
+if(NOT desiredProp1 STREQUAL actualProp1)
+  message("source property not set. desired: \"${desiredProp1}\" actual: \"${actualProp1}\"")
+endif()
+
+add_custom_target(target2 ALL SOURCES main.cpp)
+target_sources(target2 PRIVATE empty_1.cpp empty_2.cpp)
+target_sources(target2 PRIVATE empty_3.cpp)
+get_property(actualProp2 TARGET target2 PROPERTY SOURCES)
+set(desiredProp2 main.cpp empty_1.cpp empty_2.cpp empty_3.cpp)
+if (NOT desiredProp2 STREQUAL actualProp2)
+  message("source property not set. desired: \"${desiredProp2}\" actual: \"${actualProp2}\"")
+endif()
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetGenx.cmake b/Tests/RunCMake/TargetSources/AddCustomTargetGenx.cmake
new file mode 100644 (file)
index 0000000..0078eab
--- /dev/null
@@ -0,0 +1,2 @@
+add_custom_target(target ALL)
+target_sources(target PRIVATE $<IF:1,${CMAKE_CURRENT_LIST_DIR}/main.cpp,${CMAKE_CURRENT_LIST_DIR}/empty_1.cpp>)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-result.txt b/Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-stderr.txt b/Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources-stderr.txt
new file mode 100644 (file)
index 0000000..9334bf6
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at AddCustomTargetInterfaceSources.cmake:2 \(target_sources\):
+  target_sources may only set PRIVATE properties on custom targets
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources.cmake b/Tests/RunCMake/TargetSources/AddCustomTargetInterfaceSources.cmake
new file mode 100644 (file)
index 0000000..42a8ca2
--- /dev/null
@@ -0,0 +1,2 @@
+add_custom_target(target ALL)
+target_sources(target INTERFACE main.cpp)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetPrivateSources.cmake b/Tests/RunCMake/TargetSources/AddCustomTargetPrivateSources.cmake
new file mode 100644 (file)
index 0000000..11f0258
--- /dev/null
@@ -0,0 +1,2 @@
+add_custom_target(target ALL)
+target_sources(target PRIVATE main.cpp)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-result.txt b/Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-stderr.txt b/Tests/RunCMake/TargetSources/AddCustomTargetPublicSources-stderr.txt
new file mode 100644 (file)
index 0000000..afba4be
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at AddCustomTargetPublicSources.cmake:2 \(target_sources\):
+  target_sources may only set PRIVATE properties on custom targets
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetPublicSources.cmake b/Tests/RunCMake/TargetSources/AddCustomTargetPublicSources.cmake
new file mode 100644 (file)
index 0000000..d9e82c0
--- /dev/null
@@ -0,0 +1,2 @@
+add_custom_target(target ALL)
+target_sources(target PUBLIC main.cpp)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetSources-result.txt b/Tests/RunCMake/TargetSources/AddCustomTargetSources-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetSources-stderr.txt b/Tests/RunCMake/TargetSources/AddCustomTargetSources-stderr.txt
new file mode 100644 (file)
index 0000000..4a153e9
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at AddCustomTargetSources.cmake:2 \(target_sources\):
+  target_sources called with invalid arguments
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/TargetSources/AddCustomTargetSources.cmake b/Tests/RunCMake/TargetSources/AddCustomTargetSources.cmake
new file mode 100644 (file)
index 0000000..dd688d3
--- /dev/null
@@ -0,0 +1,2 @@
+add_custom_target(target ALL)
+target_sources(target main.cpp)
index 0d462ba..b56ee44 100644 (file)
@@ -14,3 +14,9 @@ run_cmake(RelativePathInSubdirInterface)
 run_cmake(RelativePathInSubdirPrivate)
 run_cmake(RelativePathInSubdirInclude)
 run_cmake(ExportBuild)
+run_cmake(AddCustomTargetPublicSources)
+run_cmake(AddCustomTargetPrivateSources)
+run_cmake(AddCustomTargetInterfaceSources)
+run_cmake(AddCustomTargetSources)
+run_cmake(AddCustomTargetCheckProperty)
+run_cmake(AddCustomTargetGenx)
diff --git a/Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt b/Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt
new file mode 100644 (file)
index 0000000..b96eee6
--- /dev/null
@@ -0,0 +1 @@
+-- Looking for a C compiler - NOTFOUND
diff --git a/Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake b/Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake
new file mode 100644 (file)
index 0000000..081f905
--- /dev/null
@@ -0,0 +1,4 @@
+get_property(in_try_compile GLOBAL PROPERTY IN_TRY_COMPILE)
+if(in_try_compile)
+  message(FATAL_ERROR "Toolchain file included")
+endif()
diff --git a/Tests/RunCMake/ToolchainFile/CheckLanguage.cmake b/Tests/RunCMake/ToolchainFile/CheckLanguage.cmake
new file mode 100644 (file)
index 0000000..854b3d4
--- /dev/null
@@ -0,0 +1,2 @@
+include(CheckLanguage)
+check_language(C)
index 7eb4485..659523c 100644 (file)
@@ -7,6 +7,7 @@ endfunction()
 
 run_cmake_toolchain(CallEnableLanguage)
 run_cmake_toolchain(CallProject)
+run_cmake_toolchain(CheckLanguage)
 run_cmake_toolchain(FlagsInit)
 run_cmake_toolchain(LinkFlagsInit)
 
diff --git a/Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake b/Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..9a38b95
--- /dev/null
@@ -0,0 +1,21 @@
+include(RunCMake)
+
+function(run_transform_depfile name)
+  set(RunCMake-check-file gccdepfile.cmake)
+  run_cmake_command(${name}-gcc
+    ${CMAKE_COMMAND} -E cmake_transform_depfile "${RunCMake_GENERATOR}" gccdepfile "${RunCMake_SOURCE_DIR}" "${RunCMake_SOURCE_DIR}/subdir" "${RunCMake_BINARY_DIR}" "${RunCMake_BINARY_DIR}/subdir" "${CMAKE_CURRENT_LIST_DIR}/${name}.d" out.d
+    )
+  set(RunCMake-check-file vstlog.cmake)
+  run_cmake_command(${name}-tlog
+    ${CMAKE_COMMAND} -E cmake_transform_depfile "${RunCMake_GENERATOR}" vstlog "${RunCMake_SOURCE_DIR}" "${RunCMake_SOURCE_DIR}/subdir" "${RunCMake_BINARY_DIR}" "${RunCMake_BINARY_DIR}/subdir" "${CMAKE_CURRENT_LIST_DIR}/${name}.d" out.tlog
+    )
+endfunction()
+
+if(WIN32)
+  run_transform_depfile(deps-windows)
+else()
+  run_transform_depfile(deps-unix)
+endif()
+run_transform_depfile(noexist)
+run_transform_depfile(empty)
+run_transform_depfile(invalid)
diff --git a/Tests/RunCMake/TransformDepfile/deps-unix.d b/Tests/RunCMake/TransformDepfile/deps-unix.d
new file mode 100644 (file)
index 0000000..5da5be8
--- /dev/null
@@ -0,0 +1,6 @@
+out1 /home/build/out2: in1 /home/build/in2
+
+out3 \
+  /home/build/out4: \
+  in3 \
+  /home/build/in4
diff --git a/Tests/RunCMake/TransformDepfile/deps-unix.d.txt b/Tests/RunCMake/TransformDepfile/deps-unix.d.txt
new file mode 100644 (file)
index 0000000..fbdecc0
--- /dev/null
@@ -0,0 +1,8 @@
+subdir/out1 \
+  /home/build/out2: \
+  subdir/in1 \
+  /home/build/in2
+subdir/out3 \
+  /home/build/out4: \
+  subdir/in3 \
+  /home/build/in4
diff --git a/Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt b/Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt
new file mode 100644 (file)
index 0000000..70bac5d
--- /dev/null
@@ -0,0 +1,6 @@
+^subdir/out1|/home/build/out2
+subdir/in1
+/home/build/in2
+^subdir/out3|/home/build/out4
+subdir/in3
+/home/build/in4
diff --git a/Tests/RunCMake/TransformDepfile/deps-windows.d b/Tests/RunCMake/TransformDepfile/deps-windows.d
new file mode 100644 (file)
index 0000000..c926670
--- /dev/null
@@ -0,0 +1,6 @@
+out1 C:/build/out2: in1 C:/build/in2
+
+out3 \
+  C:/build/out4: \
+  in3 \
+  C:/build/in4
diff --git a/Tests/RunCMake/TransformDepfile/deps-windows.d.txt b/Tests/RunCMake/TransformDepfile/deps-windows.d.txt
new file mode 100644 (file)
index 0000000..e09ae37
--- /dev/null
@@ -0,0 +1,8 @@
+subdir/out1 \
+  C:/build/out2: \
+  subdir/in1 \
+  C:/build/in2
+subdir/out3 \
+  C:/build/out4: \
+  subdir/in3 \
+  C:/build/in4
diff --git a/Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt b/Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt
new file mode 100644 (file)
index 0000000..09f9e97
--- /dev/null
@@ -0,0 +1,6 @@
+^subdir\out1|C:\build\out2
+subdir\in1
+C:\build\in2
+^subdir\out3|C:\build\out4
+subdir\in3
+C:\build\in4
diff --git a/Tests/RunCMake/TransformDepfile/empty.d b/Tests/RunCMake/TransformDepfile/empty.d
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/TransformDepfile/empty.d.txt b/Tests/RunCMake/TransformDepfile/empty.d.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/TransformDepfile/empty.tlog.txt b/Tests/RunCMake/TransformDepfile/empty.tlog.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/TransformDepfile/gccdepfile.cmake b/Tests/RunCMake/TransformDepfile/gccdepfile.cmake
new file mode 100644 (file)
index 0000000..be1e210
--- /dev/null
@@ -0,0 +1,16 @@
+if(EXISTS "${RunCMake_SOURCE_DIR}/${name}.d.txt")
+  file(READ "${RunCMake_SOURCE_DIR}/${name}.d.txt" expected_contents)
+
+  if(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.d")
+    file(READ "${RunCMake_TEST_BINARY_DIR}/out.d" actual_contents)
+    if(NOT actual_contents STREQUAL expected_contents)
+      string(REPLACE "\n" "\n  " p_expected_contents "${expected_contents}")
+      string(REPLACE "\n" "\n  " p_actual_contents "${actual_contents}")
+      string(APPEND RunCMake_TEST_FAILED "Expected contents of ${RunCMake_TEST_BINARY_DIR}/out.d:\n  ${p_expected_contents}\nActual contents:\n  ${p_actual_contents}")
+    endif()
+  else()
+    string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.d should exist\n")
+  endif()
+elseif(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.d")
+  string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.d should not exist\n")
+endif()
diff --git a/Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt b/Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt
new file mode 100644 (file)
index 0000000..0cfbf08
--- /dev/null
@@ -0,0 +1 @@
+2
diff --git a/Tests/RunCMake/TransformDepfile/invalid.d b/Tests/RunCMake/TransformDepfile/invalid.d
new file mode 100644 (file)
index 0000000..9977a28
--- /dev/null
@@ -0,0 +1 @@
+invalid
diff --git a/Tests/RunCMake/TransformDepfile/noexist.d.txt b/Tests/RunCMake/TransformDepfile/noexist.d.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/TransformDepfile/noexist.tlog.txt b/Tests/RunCMake/TransformDepfile/noexist.tlog.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/TransformDepfile/vstlog.cmake b/Tests/RunCMake/TransformDepfile/vstlog.cmake
new file mode 100644 (file)
index 0000000..afa78d0
--- /dev/null
@@ -0,0 +1,16 @@
+if(EXISTS "${RunCMake_SOURCE_DIR}/${name}.tlog.txt")
+  file(READ "${RunCMake_SOURCE_DIR}/${name}.tlog.txt" expected_contents)
+
+  if(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.tlog")
+    file(READ "${RunCMake_TEST_BINARY_DIR}/out.tlog" actual_contents)
+    if(NOT actual_contents STREQUAL expected_contents)
+      string(REPLACE "\n" "\n  " p_expected_contents "${expected_contents}")
+      string(REPLACE "\n" "\n  " p_actual_contents "${actual_contents}")
+      string(APPEND RunCMake_TEST_FAILED "Expected contents of ${RunCMake_TEST_BINARY_DIR}/out.tlog:\n  ${p_expected_contents}\nActual contents:\n  ${p_actual_contents}")
+    endif()
+  else()
+    string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.tlog should exist\n")
+  endif()
+elseif(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.tlog")
+  string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.tlog should not exist\n")
+endif()
index 9ba3c85..c00f78b 100644 (file)
@@ -1,5 +1,14 @@
 include(RunCMake)
 
+function(run_build name)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake(${name})
+  run_cmake_command(${name}-build ${CMAKE_COMMAND} --build . --config Debug)
+  unset(RunCMake_TEST_BINARY_DIR)
+  unset(RunCMake_TEST_NO_CLEAN)
+endfunction()
+
 run_cmake(unitybuild_c)
 run_cmake(unitybuild_c_batch)
 run_cmake(unitybuild_c_group)
@@ -15,6 +24,9 @@ run_cmake(unitybuild_c_no_unity_build)
 run_cmake(unitybuild_c_no_unity_build_group)
 run_cmake(unitybuild_order)
 run_cmake(unitybuild_invalid_mode)
+run_build(unitybuild_anon_ns)
+run_build(unitybuild_anon_ns_no_unity_build)
+run_build(unitybuild_anon_ns_group_mode)
 
 function(run_test name)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
diff --git a/Tests/RunCMake/UnityBuild/f.cxx b/Tests/RunCMake/UnityBuild/f.cxx
new file mode 100644 (file)
index 0000000..d5813c6
--- /dev/null
@@ -0,0 +1,5 @@
+int f(int x)
+{
+  (void)x;
+  return 0;
+}
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_anon_ns-build-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_anon_ns-build-check.cmake
new file mode 100644 (file)
index 0000000..746be32
--- /dev/null
@@ -0,0 +1,10 @@
+set(unitybuild_0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_cxx.cxx")
+
+file(STRINGS ${unitybuild_0} src)
+
+foreach(expectedRegex IN ITEMS "SRC_f\\.cxx" "BLD_s1\\.cpp")
+  if(NOT "${src}" MATCHES "${expectedRegex}")
+    set(RunCMake_TEST_FAILED "Generated unity file doesn't have a match for expected unity ID regex ${expectedRegex}")
+    return()
+  endif()
+endforeach()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake b/Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake
new file mode 100644 (file)
index 0000000..e05863d
--- /dev/null
@@ -0,0 +1,11 @@
+project(unitybuild_anon_ns CXX)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/unitybuild_anon_ns_test_files.cmake)
+
+write_unity_build_anon_ns_test_files(srcs)
+
+add_library(tgt SHARED f.cxx ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON)
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD_UNIQUE_ID MY_ANON_ID)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_anon_ns_group_mode.cmake b/Tests/RunCMake/UnityBuild/unitybuild_anon_ns_group_mode.cmake
new file mode 100644 (file)
index 0000000..a91fc74
--- /dev/null
@@ -0,0 +1,19 @@
+project(unitybuild_anon_ns_group_mode CXX)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/unitybuild_anon_ns_test_files.cmake)
+
+write_unity_build_anon_ns_test_files(srcs)
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+                                     UNITY_BUILD_MODE GROUP)
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD_UNIQUE_ID MY_ANON_ID)
+
+set_source_files_properties(s1.cpp s2.cpp s5.cpp s7.cpp s8.cpp
+                            PROPERTIES UNITY_GROUP "a"
+                            )
+set_source_files_properties(s3.cpp s4.cpp s6.cpp
+                            PROPERTIES UNITY_GROUP "b"
+                            )
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_anon_ns_no_unity_build.cmake b/Tests/RunCMake/UnityBuild/unitybuild_anon_ns_no_unity_build.cmake
new file mode 100644 (file)
index 0000000..9f0a9e1
--- /dev/null
@@ -0,0 +1,11 @@
+project(unitybuild_anon_ns_no_unity_build CXX)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/unitybuild_anon_ns_test_files.cmake)
+
+write_unity_build_anon_ns_test_files(srcs)
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD OFF)
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD_UNIQUE_ID MY_ANON_ID)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_anon_ns_test_files.cmake b/Tests/RunCMake/UnityBuild/unitybuild_anon_ns_test_files.cmake
new file mode 100644 (file)
index 0000000..06a600e
--- /dev/null
@@ -0,0 +1,31 @@
+
+function(write_unity_build_anon_ns_test_files OUTVAR)
+  set(srcs)
+  foreach(s RANGE 1 8)
+    set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cpp")
+    file(WRITE "${src}" "
+#ifndef CONFIG_H
+#define CONFIG_H
+#define MY_ANON_NAMESPACE MY_ANON_ID
+#define MY_ANON(Name) MY_ANON_NAMESPACE::Name
+#define MY_ANON_USING_NAMESPACE using namespace MY_ANON_NAMESPACE
+#endif
+
+namespace { namespace MY_ANON_NAMESPACE {
+  int i = ${s};
+}}
+int use_plain_${s}() {
+  return MY_ANON_NAMESPACE::i;
+}
+int func_like_macro_${s}() {
+  return MY_ANON(i);
+}
+int using_macro_${s}() {
+  MY_ANON_USING_NAMESPACE;
+  return i;
+}
+")
+    list(APPEND srcs "${src}")
+  endforeach()
+  set(${OUTVAR} ${srcs} PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake b/Tests/RunCMake/VS10Project/CustomCommandGenex-check.cmake
new file mode 100644 (file)
index 0000000..a7047bc
--- /dev/null
@@ -0,0 +1,37 @@
+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_out 0)
+set(found_CustomBuild_out_CONFIG 0)
+set(found_CustomBuild_out_CONFIG_CONFIG 0)
+set(found_CustomBuild_out_HASH 0)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES [[<CustomBuild Include=".*\\out\.txt\.rule">]])
+    set(found_CustomBuild_out 1)
+  endif()
+  if(line MATCHES [[<CustomBuild Include=".*\\out-\(CONFIG\)\.txt\.rule">]])
+    set(found_CustomBuild_out_CONFIG 1)
+  endif()
+  if(line MATCHES [[<CustomBuild Include=".*\\out-\(CONFIG\)-\(CONFIG\)\.txt\.rule">]])
+    set(found_CustomBuild_out_CONFIG_CONFIG 1)
+  endif()
+  if(line MATCHES [[<CustomBuild Include=".*\\[0-9A-Fa-f]+\.rule">]])
+    set(found_CustomBuild_out_HASH 1)
+  endif()
+endforeach()
+if(NOT found_CustomBuild_out)
+  string(APPEND RunCMake_TEST_FAILED "CustomBuild for out.txt.rule not found in\n  ${vcProjectFile}\n")
+endif()
+if(NOT found_CustomBuild_out_CONFIG)
+  string(APPEND RunCMake_TEST_FAILED "CustomBuild for out-(CONFIG).txt.rule not found in\n  ${vcProjectFile}\n")
+endif()
+if(NOT found_CustomBuild_out_CONFIG_CONFIG)
+  string(APPEND RunCMake_TEST_FAILED "CustomBuild for out-(CONFIG)-(CONFIG).txt.rule not found in\n  ${vcProjectFile}\n")
+endif()
+if(NOT found_CustomBuild_out_HASH)
+  string(APPEND RunCMake_TEST_FAILED "CustomBuild for <hash>.rule not found in\n  ${vcProjectFile}\n")
+endif()
diff --git a/Tests/RunCMake/VS10Project/CustomCommandGenex.cmake b/Tests/RunCMake/VS10Project/CustomCommandGenex.cmake
new file mode 100644 (file)
index 0000000..5b69dc2
--- /dev/null
@@ -0,0 +1,21 @@
+add_custom_command(
+  OUTPUT "$<1:out.txt>"
+  COMMAND ${CMAKE_COMMAND} -E touch "out.txt"
+  VERBATIM
+  )
+add_custom_command(
+  OUTPUT "out-$<CONFIG>.txt"
+  COMMAND ${CMAKE_COMMAND} -E touch "out-$<CONFIG>.txt"
+  VERBATIM
+  )
+add_custom_command(
+  OUTPUT "out-$<CONFIG>-$<CONFIG>.txt"
+  COMMAND ${CMAKE_COMMAND} -E touch "out-$<CONFIG>-$<CONFIG>.txt"
+  VERBATIM
+  )
+add_custom_command(
+  OUTPUT "out-$<CONFIG>-$<CONFIG:Debug>.txt"
+  COMMAND ${CMAKE_COMMAND} -E touch "out-$<CONFIG>-$<CONFIG:Debug>.txt"
+  VERBATIM
+  )
+add_custom_target(foo DEPENDS "out.txt" "out-$<CONFIG>.txt" "out-$<CONFIG>-$<CONFIG>.txt" "out-$<CONFIG>-$<CONFIG:Debug>.txt")
index 133dacc..d5ed136 100644 (file)
@@ -7,6 +7,7 @@ if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREA
   run_cmake(LanguageStandard)
 endif()
 
+run_cmake(CustomCommandGenex)
 run_cmake(VsCsharpSourceGroup)
 run_cmake(VsCSharpCompilerOpts)
 run_cmake(ExplicitCMakeLists)
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-result.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-stderr.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct-stderr.txt
new file mode 100644 (file)
index 0000000..4e0d756
--- /dev/null
@@ -0,0 +1,6 @@
+^CMake Error at [^
+]*/Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(message\):
+  The WriteCompilerDetectionHeader module has been removed by policy CMP0120.
+Call Stack \(most recent call first\):
+  CMP0120-NEW-Direct.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct.cmake b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-Direct.cmake
new file mode 100644 (file)
index 0000000..4cd2c56
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0120 NEW)
+include(${CMAKE_ROOT}/Modules/WriteCompilerDetectionHeader.cmake)
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-result.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-stderr.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW-stderr.txt
new file mode 100644 (file)
index 0000000..2f7ad70
--- /dev/null
@@ -0,0 +1,6 @@
+^CMake Error at CMP0120-NEW.cmake:[0-9]+ \(include\):
+  include could not find requested file:
+
+    WriteCompilerDetectionHeader
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW.cmake b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-NEW.cmake
new file mode 100644 (file)
index 0000000..3d39a97
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0120 NEW)
+include(WriteCompilerDetectionHeader)
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-Direct.cmake b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-Direct.cmake
new file mode 100644 (file)
index 0000000..48517e6
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0120 OLD)
+include(${CMAKE_ROOT}/Modules/WriteCompilerDetectionHeader.cmake)
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD.cmake b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD.cmake
new file mode 100644 (file)
index 0000000..c513186
--- /dev/null
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0120 OLD)
+include(WriteCompilerDetectionHeader)
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct-stderr.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct-stderr.txt
new file mode 100644 (file)
index 0000000..88cd8f7
--- /dev/null
@@ -0,0 +1,9 @@
+^CMake Warning \(dev\) at [^
+]*/Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(message\):
+  The WriteCompilerDetectionHeader module will be removed by policy CMP0120.
+  Projects should be ported away from the module, perhaps by bundling a copy
+  of the generated header or using a third-party alternative.
+Call Stack \(most recent call first\):
+  CMP0120-WARN-Direct.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct.cmake b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-Direct.cmake
new file mode 100644 (file)
index 0000000..d3c7f77
--- /dev/null
@@ -0,0 +1,2 @@
+
+include(${CMAKE_ROOT}/Modules/WriteCompilerDetectionHeader.cmake)
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-stderr.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN-stderr.txt
new file mode 100644 (file)
index 0000000..315b4b1
--- /dev/null
@@ -0,0 +1,18 @@
+^CMake Warning \(dev\) at CMP0120-WARN.cmake:[0-9]+ \(include\):
+  Policy CMP0120 is not set: The WriteCompilerDetectionHeader module is
+  removed.  Run "cmake --help-policy CMP0120" 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.
+
+CMake Warning \(dev\) at [^
+]*/Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(message\):
+  The WriteCompilerDetectionHeader module will be removed by policy CMP0120.
+  Projects should be ported away from the module, perhaps by bundling a copy
+  of the generated header or using a third-party alternative.
+Call Stack \(most recent call first\):
+  CMP0120-WARN.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN.cmake b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-WARN.cmake
new file mode 100644 (file)
index 0000000..1f95e3e
--- /dev/null
@@ -0,0 +1,2 @@
+
+include(WriteCompilerDetectionHeader)
index a834e6d..7589f74 100644 (file)
@@ -1,5 +1,12 @@
 include(RunCMake)
 
+run_cmake(CMP0120-WARN)
+run_cmake(CMP0120-OLD)
+run_cmake(CMP0120-NEW)
+run_cmake(CMP0120-WARN-Direct)
+run_cmake(CMP0120-OLD-Direct)
+run_cmake(CMP0120-NEW-Direct)
+
 run_cmake(InvalidArgs)
 run_cmake(NoCompiler)
 run_cmake(NoFeature)
diff --git a/Tests/RunCMake/XcodeProject-Embed/CMakeLists.txt b/Tests/RunCMake/XcodeProject-Embed/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0400d1a
--- /dev/null
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} LANGUAGES C)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff-check.cmake
new file mode 100644 (file)
index 0000000..9cc03b9
--- /dev/null
@@ -0,0 +1,14 @@
+function(findAttribute project attr)
+  execute_process(
+      COMMAND grep ${attr} ${RunCMake_TEST_BINARY_DIR}/${project}.xcodeproj/project.pbxproj
+      OUTPUT_VARIABLE output_var
+      RESULT_VARIABLE result_var
+  )
+
+  if(NOT result_var)
+    set(RunCMake_TEST_FAILED "${attr} attribute is set" PARENT_SCOPE)
+  endif()
+endfunction()
+
+findAttribute(${test} "RemoveHeadersOnCopy")
+findAttribute(${test} "CodeSignOnCopy")
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOff.cmake
new file mode 100644 (file)
index 0000000..f4fe07f
--- /dev/null
@@ -0,0 +1,7 @@
+add_executable(app MACOSX_BUNDLE main.m)
+
+set_target_properties(app PROPERTIES
+  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_FWK}"
+  XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY OFF
+  XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY OFF
+)
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-build-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-build-check.cmake
new file mode 100644 (file)
index 0000000..e4ea55d
--- /dev/null
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/Debug/app.app/Contents/Frameworks/sharedFrameworkExt.framework)
+  set(RunCMake_TEST_FAILED "Framework was not embedded at the expected location")
+endif()
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir-check.cmake
new file mode 100644 (file)
index 0000000..3f62640
--- /dev/null
@@ -0,0 +1,14 @@
+function(findAttribute project attr)
+  execute_process(
+      COMMAND grep ${attr} ${RunCMake_TEST_BINARY_DIR}/${project}.xcodeproj/project.pbxproj
+      OUTPUT_VARIABLE output_var
+      RESULT_VARIABLE result_var
+  )
+
+  if(result_var)
+    set(RunCMake_TEST_FAILED "${attr} attribute not set" PARENT_SCOPE)
+  endif()
+endfunction()
+
+findAttribute(${test} "RemoveHeadersOnCopy")
+findAttribute(${test} "CodeSignOnCopy")
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnNoSubdir.cmake
new file mode 100644 (file)
index 0000000..79d8d77
--- /dev/null
@@ -0,0 +1,7 @@
+add_executable(app MACOSX_BUNDLE main.m)
+
+set_target_properties(app PROPERTIES
+  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_FWK}"
+  XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY ON
+  XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY ON
+)
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-build-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-build-check.cmake
new file mode 100644 (file)
index 0000000..57c79ea
--- /dev/null
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/Debug/app.app/Contents/Frameworks/subdir/sharedFrameworkExt.framework)
+  set(RunCMake_TEST_FAILED "Framework was not embedded at the expected location")
+endif()
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir-check.cmake
new file mode 100644 (file)
index 0000000..3f62640
--- /dev/null
@@ -0,0 +1,14 @@
+function(findAttribute project attr)
+  execute_process(
+      COMMAND grep ${attr} ${RunCMake_TEST_BINARY_DIR}/${project}.xcodeproj/project.pbxproj
+      OUTPUT_VARIABLE output_var
+      RESULT_VARIABLE result_var
+  )
+
+  if(result_var)
+    set(RunCMake_TEST_FAILED "${attr} attribute not set" PARENT_SCOPE)
+  endif()
+endfunction()
+
+findAttribute(${test} "RemoveHeadersOnCopy")
+findAttribute(${test} "CodeSignOnCopy")
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOnWithSubdir.cmake
new file mode 100644 (file)
index 0000000..4c78199
--- /dev/null
@@ -0,0 +1,8 @@
+add_executable(app MACOSX_BUNDLE main.m)
+
+set_target_properties(app PROPERTIES
+  XCODE_EMBED_FRAMEWORKS "${EXTERNAL_FWK}"
+  XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY ON
+  XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY ON
+  XCODE_EMBED_FRAMEWORKS_PATH "subdir"
+)
diff --git a/Tests/RunCMake/XcodeProject-Embed/ExternalFramework.cmake b/Tests/RunCMake/XcodeProject-Embed/ExternalFramework.cmake
new file mode 100644 (file)
index 0000000..64e2f95
--- /dev/null
@@ -0,0 +1,2 @@
+add_library(sharedFrameworkExt SHARED func.m)
+set_target_properties(sharedFrameworkExt PROPERTIES FRAMEWORK TRUE)
diff --git a/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..0dc1cf3
--- /dev/null
@@ -0,0 +1,43 @@
+include(RunCMake)
+
+# Build a framework that the other tests will use and treat as external.
+# Always build in the Debug configuration so that the path to the framework
+# is predictable.
+function(ExternalFramework)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExternalFramework-build)
+  set(externalFramework ${RunCMake_TEST_BINARY_DIR}/Debug/sharedFrameworkExt.framework PARENT_SCOPE)
+
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  run_cmake(ExternalFramework)
+  run_cmake_command(ExternalFramework-build
+    ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR}
+                     --config Debug
+                     --target sharedFrameworkExt
+  )
+endfunction()
+ExternalFramework()
+
+set(RunCMake_TEST_OPTIONS -DEXTERNAL_FWK=${externalFramework})
+
+run_cmake(EmbedFrameworksFlagsOff)
+
+function(TestFlagsOn testName)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${testName}-build)
+
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  run_cmake(${testName})
+  run_cmake_command(${testName}-build
+    ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR}
+                     --config Debug
+                     --target app
+  )
+endfunction()
+
+TestFlagsOn(EmbedFrameworksFlagsOnNoSubdir)
+TestFlagsOn(EmbedFrameworksFlagsOnWithSubdir)
diff --git a/Tests/RunCMake/XcodeProject-Embed/func.m b/Tests/RunCMake/XcodeProject-Embed/func.m
new file mode 100644 (file)
index 0000000..29c6689
--- /dev/null
@@ -0,0 +1,6 @@
+#import <CoreFoundation/CoreFoundation.h>
+
+int func()
+{
+  return 1;
+}
diff --git a/Tests/RunCMake/XcodeProject-Embed/main.m b/Tests/RunCMake/XcodeProject-Embed/main.m
new file mode 100644 (file)
index 0000000..72e425d
--- /dev/null
@@ -0,0 +1,6 @@
+#import <CoreFoundation/CoreFoundation.h>
+
+int main(int argc, char** argv)
+{
+  return 0;
+}
index 794274c..8b03216 100644 (file)
@@ -3,6 +3,7 @@ include(RunCMake)
 run_cmake(ExplicitCMakeLists)
 run_cmake(ImplicitCMakeLists)
 run_cmake(InterfaceLibSources)
+run_cmake_with_options(SearchPaths -DCMAKE_CONFIGURATION_TYPES=Debug)
 
 run_cmake(XcodeFileType)
 run_cmake(XcodeAttributeLocation)
@@ -51,6 +52,35 @@ run_cmake(PerConfigPerSourceOptions)
 run_cmake(PerConfigPerSourceDefinitions)
 run_cmake(PerConfigPerSourceIncludeDirs)
 
+if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
+
+  function(XcodeObjectLibsInTwoProjectsiOS)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeObjectLibsInTwoProjects-build-ios)
+    set(RunCMake_TEST_OPTIONS "-DCMAKE_SYSTEM_NAME=iOS")
+
+    run_cmake(XcodeObjectLibsInTwoProjects)
+
+    set(RunCMake_TEST_NO_CLEAN 1)
+
+    run_cmake_command(XcodeObjectLibsInTwoProjects-build-ios ${CMAKE_COMMAND} --build . --target shared_lib -- -sdk iphonesimulator)
+  endfunction()
+
+  XcodeObjectLibsInTwoProjectsiOS()
+
+  function(XcodeObjectLibsInTwoProjectsMacOS)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeObjectLibsInTwoProjects-build-macos)
+
+    run_cmake(XcodeObjectLibsInTwoProjects)
+
+    set(RunCMake_TEST_NO_CLEAN 1)
+
+    run_cmake_command(XcodeObjectLibsInTwoProjects-build-macos ${CMAKE_COMMAND} --build . --target shared_lib)
+  endfunction()
+
+  XcodeObjectLibsInTwoProjectsMacOS()
+
+endif()
+
 function(XcodeSchemaGeneration)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeSchemaGeneration-build)
   set(RunCMake_TEST_NO_CLEAN 1)
diff --git a/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake b/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake
new file mode 100644 (file)
index 0000000..71b7d8f
--- /dev/null
@@ -0,0 +1,76 @@
+set(xcProjectFile "${RunCMake_TEST_BINARY_DIR}/SearchPaths.xcodeproj/project.pbxproj")
+if(NOT EXISTS "${xcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${xcProjectFile} does not exist.")
+  return()
+endif()
+
+set(relevant_lines "")
+set(found_project_FRAMEWORK_SEARCH_PATHS 0)
+set(found_target_both_FRAMEWORK_SEARCH_PATHS 0)
+set(found_target_include_FRAMEWORK_SEARCH_PATHS 0)
+set(found_target_library_FRAMEWORK_SEARCH_PATHS 0)
+set(found_inherited_FRAMEWORK_SEARCH_PATHS 0)
+set(found_project_LIBRARY_SEARCH_PATHS 0)
+set(found_target_library_LIBRARY_SEARCH_PATHS 0)
+set(found_inherited_LIBRARY_SEARCH_PATHS 0)
+file(STRINGS "${xcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES [[FRAMEWORK_SEARCH_PATHS]])
+    string(APPEND relevant_lines "  ${line}\n")
+    if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = "[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/ProjectSearchPath";]])
+      set(found_project_FRAMEWORK_SEARCH_PATHS 1)
+    endif()
+    if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathInc(\\")?","(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib(\\")?","\$\(inherited\)"\);]])
+      set(found_target_both_FRAMEWORK_SEARCH_PATHS 1)
+    endif()
+    if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathInc(\\")?","\$\(inherited\)"\);]])
+      set(found_target_include_FRAMEWORK_SEARCH_PATHS 1)
+    endif()
+    if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib(\\")?","\$\(inherited\)"\);]])
+      set(found_target_library_FRAMEWORK_SEARCH_PATHS 1)
+    endif()
+    if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("\$\(inherited\)"\);]])
+      set(found_inherited_FRAMEWORK_SEARCH_PATHS 1)
+    endif()
+  endif()
+
+  if(line MATCHES [[LIBRARY_SEARCH_PATHS]])
+    string(APPEND relevant_lines "  ${line}\n")
+    if(line MATCHES [[LIBRARY_SEARCH_PATHS = "[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/ProjectSearchPath";]])
+      set(found_project_LIBRARY_SEARCH_PATHS 1)
+    endif()
+    if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib/\$\(CONFIGURATION\)\$\(EFFECTIVE_PLATFORM_NAME\)(\\")?","(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib(\\")?","\$\(inherited\)"\);]])
+      set(found_target_library_LIBRARY_SEARCH_PATHS 1)
+    endif()
+    if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("\$\(inherited\)"\);]])
+      set(found_inherited_LIBRARY_SEARCH_PATHS 1)
+    endif()
+  endif()
+endforeach()
+if(NOT found_project_FRAMEWORK_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected FRAMEWORK_SEARCH_PATHS for project in\n  ${xcProjectFile}\n")
+endif()
+if(NOT found_target_both_FRAMEWORK_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected FRAMEWORK_SEARCH_PATHS for target 'both' in\n  ${xcProjectFile}\n")
+endif()
+if(NOT found_target_include_FRAMEWORK_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'include' in\n  ${xcProjectFile}\n")
+endif()
+if(NOT found_target_library_FRAMEWORK_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'library' in\n  ${xcProjectFile}\n")
+endif()
+if(found_inherited_FRAMEWORK_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Found unexpected LIBRARY_SEARCH_PATHS inherited-only value in\n  ${xcProjectFile}\n")
+endif()
+if(NOT found_project_LIBRARY_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for project in\n  ${xcProjectFile}\n")
+endif()
+if(NOT found_target_library_LIBRARY_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'library' in\n  ${xcProjectFile}\n")
+endif()
+if(found_inherited_LIBRARY_SEARCH_PATHS)
+  string(APPEND RunCMake_TEST_FAILED "Found unexpected LIBRARY_SEARCH_PATHS inherited-only value in\n  ${xcProjectFile}\n")
+endif()
+if(RunCMake_TEST_FAILED)
+  string(APPEND RunCMake_TEST_FAILED "Relevant lines include\n${relevant_lines}")
+endif()
diff --git a/Tests/RunCMake/XcodeProject/SearchPaths.cmake b/Tests/RunCMake/XcodeProject/SearchPaths.cmake
new file mode 100644 (file)
index 0000000..ef97709
--- /dev/null
@@ -0,0 +1,21 @@
+enable_language(C)
+
+file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
+file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathInc/TargetInc.framework")
+file(MAKE_DIRECTORY  "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
+
+set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
+set(CMAKE_XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
+
+add_executable(neither main.c)
+
+add_executable(both main.c)
+target_include_directories(both PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathInc/TargetInc.framework")
+target_link_libraries(both PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
+
+add_executable(include main.c)
+target_include_directories(include PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathInc/TargetInc.framework")
+
+add_executable(library main.c)
+target_link_libraries(library PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
+target_link_directories(library PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib")
diff --git a/Tests/RunCMake/XcodeProject/XcodeObjectLibsInTwoProjects.cmake b/Tests/RunCMake/XcodeProject/XcodeObjectLibsInTwoProjects.cmake
new file mode 100644 (file)
index 0000000..3ca24af
--- /dev/null
@@ -0,0 +1,5 @@
+cmake_minimum_required (VERSION 3.19)
+
+project (test_xcode_fail NONE)
+
+add_subdirectory(subproject_two_object_libs)
diff --git a/Tests/RunCMake/XcodeProject/subproject_two_object_libs/CMakeLists.txt b/Tests/RunCMake/XcodeProject/subproject_two_object_libs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e55836d
--- /dev/null
@@ -0,0 +1,31 @@
+cmake_minimum_required (VERSION 3.16)
+
+enable_language(CXX)
+
+project (subproject_two_object_libs)
+
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED NO)
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
+
+if(IOS)
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+
+  set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
+endif()
+
+# Hierarchy of libraries looks like:
+#
+# OBJECT-1 ---> STATIC--\
+#                        |---> SHARED
+# OBJECT-2 -------------/
+
+add_library(object_lib_dependency1 OBJECT dummy.cpp)
+
+add_library(static_lib_dependency STATIC dummy.cpp $<TARGET_OBJECTS:object_lib_dependency1>)
+
+add_library(object_lib_dependency2 OBJECT dummy.cpp)
+target_link_libraries(object_lib_dependency2 PRIVATE static_lib_dependency)
+
+add_library(shared_lib SHARED dummy.cpp)
+target_link_libraries(shared_lib PRIVATE static_lib_dependency)
+target_sources(shared_lib PRIVATE $<TARGET_OBJECTS:object_lib_dependency2>)
diff --git a/Tests/RunCMake/XcodeProject/subproject_two_object_libs/dummy.cpp b/Tests/RunCMake/XcodeProject/subproject_two_object_libs/dummy.cpp
new file mode 100644 (file)
index 0000000..8082abc
--- /dev/null
@@ -0,0 +1,5 @@
+namespace {
+void foo()
+{
+}
+}
index b7ee23a..9324302 100644 (file)
@@ -1,5 +1,5 @@
 CMake Error at AppendNotOutput.cmake:1 \(add_custom_command\):
-  add_custom_command given APPEND option with output
+  Attempt to APPEND to custom command with output
 
     .*RunCMake/add_custom_command/AppendNotOutput-build/out
 
index 086e397..547fb1c 100644 (file)
@@ -1,36 +1,67 @@
 CMake Error at BadByproduct.cmake:2 \(add_custom_command\):
-  add_custom_command called with BYPRODUCTS containing a "#".  This character
-  is not allowed.
+  BYPRODUCTS containing a "#" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
 
 CMake Error at BadByproduct.cmake:3 \(add_custom_command\):
-  add_custom_command called with BYPRODUCTS containing a "<".  This character
-  is not allowed.
+  BYPRODUCTS containing a "<" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
 
 CMake Error at BadByproduct.cmake:4 \(add_custom_command\):
-  add_custom_command called with BYPRODUCTS containing a ">".  This character
-  is not allowed.
+  BYPRODUCTS containing a ">" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
-
+(
 CMake Error at BadByproduct.cmake:5 \(add_custom_command\):
-  add_custom_command called with BYPRODUCTS containing a "<".  This character
-  is not allowed.
+  BYPRODUCTS containing a "#" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
-
+)+
 CMake Error at BadByproduct.cmake:6 \(add_custom_command\):
-  add_custom_command attempted to have a file
+  BYPRODUCTS path
 
     .*RunCMake/add_custom_command/f
 
   in a source directory as an output of custom command.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
+
+(
+CMake Error at BadByproduct.cmake:7 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<TARGET_PROPERTY:prop>
+
+  \$<TARGET_PROPERTY:prop> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.  Specify the target
+  to read a property from using the \$<TARGET_PROPERTY:tgt,prop> signature
+  instead.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+(
+CMake Error at BadByproduct.cmake:8 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OUTPUT_CONFIG:h>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+(
+CMake Error at BadByproduct.cmake:9 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<COMMAND_CONFIG:i>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+
index 91bca52..cf00f5b 100644 (file)
@@ -4,3 +4,6 @@ add_custom_command(OUTPUT b BYPRODUCTS "a<")
 add_custom_command(OUTPUT c BYPRODUCTS "a>")
 add_custom_command(OUTPUT d BYPRODUCTS "$<CONFIG>/#")
 add_custom_command(OUTPUT e BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/f)
+add_custom_command(OUTPUT f BYPRODUCTS "$<TARGET_PROPERTY:prop>")
+add_custom_command(OUTPUT h BYPRODUCTS "$<OUTPUT_CONFIG:h>")
+add_custom_command(OUTPUT i BYPRODUCTS "$<COMMAND_CONFIG:i>")
diff --git a/Tests/RunCMake/add_custom_command/BadCommand-result.txt b/Tests/RunCMake/add_custom_command/BadCommand-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/add_custom_command/BadCommand-stderr.txt b/Tests/RunCMake/add_custom_command/BadCommand-stderr.txt
new file mode 100644 (file)
index 0000000..470afd6
--- /dev/null
@@ -0,0 +1,21 @@
+(CMake Error at BadCommand.cmake:1 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OUTPUT_CONFIG:a>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+)+(CMake Error at BadCommand.cmake:2 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<COMMAND_CONFIG:b>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+)+
diff --git a/Tests/RunCMake/add_custom_command/BadCommand.cmake b/Tests/RunCMake/add_custom_command/BadCommand.cmake
new file mode 100644 (file)
index 0000000..8c9c3f9
--- /dev/null
@@ -0,0 +1,3 @@
+add_custom_command(OUTPUT "a" COMMAND "$<1:$<OUTPUT_CONFIG:a>>")
+add_custom_command(OUTPUT "b" COMMAND "$<1:$<COMMAND_CONFIG:b>>")
+add_custom_target(drive DEPENDS "a" "b")
index 731e58d..2e43568 100644 (file)
@@ -1,36 +1,67 @@
 CMake Error at BadOutput.cmake:2 \(add_custom_command\):
-  add_custom_command called with OUTPUT containing a "#".  This character is
-  not allowed.
+  OUTPUT containing a "#" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
 
 CMake Error at BadOutput.cmake:3 \(add_custom_command\):
-  add_custom_command called with OUTPUT containing a "<".  This character is
-  not allowed.
+  OUTPUT containing a "<" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
 
 CMake Error at BadOutput.cmake:4 \(add_custom_command\):
-  add_custom_command called with OUTPUT containing a ">".  This character is
-  not allowed.
+  OUTPUT containing a ">" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
-
+(
 CMake Error at BadOutput.cmake:5 \(add_custom_command\):
-  add_custom_command called with OUTPUT containing a "<".  This character is
-  not allowed.
+  OUTPUT containing a "#" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
-
+)+
 CMake Error at BadOutput.cmake:6 \(add_custom_command\):
-  add_custom_command attempted to have a file
+  OUTPUT path
 
     .*RunCMake/add_custom_command/e
 
   in a source directory as an output of custom command.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
+
+(
+CMake Error at BadOutput.cmake:7 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<TARGET_PROPERTY:prop>
+
+  \$<TARGET_PROPERTY:prop> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.  Specify the target
+  to read a property from using the \$<TARGET_PROPERTY:tgt,prop> signature
+  instead.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+(
+CMake Error at BadOutput.cmake:8 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OUTPUT_CONFIG:h>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+(
+CMake Error at BadOutput.cmake:9 \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<COMMAND_CONFIG:i>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+
index 6875fe9..f04bdd1 100644 (file)
@@ -4,3 +4,6 @@ add_custom_command(OUTPUT "a<" COMMAND b)
 add_custom_command(OUTPUT "a>" COMMAND c)
 add_custom_command(OUTPUT "$<CONFIG>/#" COMMAND d)
 add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/e COMMAND f)
+add_custom_command(OUTPUT "$<TARGET_PROPERTY:prop>" COMMAND g)
+add_custom_command(OUTPUT "$<OUTPUT_CONFIG:h>" COMMAND h)
+add_custom_command(OUTPUT "$<COMMAND_CONFIG:i>" COMMAND i)
index aac085d..9c59b4b 100644 (file)
@@ -6,6 +6,7 @@ run_cmake(AppendNotOutput)
 run_cmake(BadArgument)
 run_cmake(BadByproduct)
 run_cmake(BadOutput)
+run_cmake(BadCommand)
 run_cmake(GeneratedProperty)
 run_cmake(LiteralQuotes)
 run_cmake(NoArguments)
index 0f58550..da9af49 100644 (file)
@@ -1,36 +1,67 @@
 CMake Error at BadByproduct.cmake:2 \(add_custom_target\):
-  add_custom_target called with BYPRODUCTS containing a "#".  This character
-  is not allowed.
+  BYPRODUCTS containing a "#" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
 
 CMake Error at BadByproduct.cmake:3 \(add_custom_target\):
-  add_custom_target called with BYPRODUCTS containing a "<".  This character
-  is not allowed.
+  BYPRODUCTS containing a "<" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
 
 CMake Error at BadByproduct.cmake:4 \(add_custom_target\):
-  add_custom_target called with BYPRODUCTS containing a ">".  This character
-  is not allowed.
+  BYPRODUCTS containing a ">" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
-
+(
 CMake Error at BadByproduct.cmake:5 \(add_custom_target\):
-  add_custom_target called with BYPRODUCTS containing a "<".  This character
-  is not allowed.
+  BYPRODUCTS containing a "#" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
-
+)+
 CMake Error at BadByproduct.cmake:6 \(add_custom_target\):
-  add_custom_target attempted to have a file
+  BYPRODUCTS path
 
     .*RunCMake/add_custom_target/j
 
   in a source directory as an output of custom command.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
+
+(
+CMake Error at BadByproduct.cmake:7 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<TARGET_PROPERTY:prop>
+
+  \$<TARGET_PROPERTY:prop> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.  Specify the target
+  to read a property from using the \$<TARGET_PROPERTY:tgt,prop> signature
+  instead.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+(
+CMake Error at BadByproduct.cmake:8 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<OUTPUT_CONFIG:n>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+(
+CMake Error at BadByproduct.cmake:9 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<COMMAND_CONFIG:p>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+)+
index 963d641..c317b83 100644 (file)
@@ -4,3 +4,6 @@ add_custom_target(c BYPRODUCTS "a<" COMMAND d)
 add_custom_target(e BYPRODUCTS "a>" COMMAND f)
 add_custom_target(g BYPRODUCTS "$<CONFIG>/#" COMMAND h)
 add_custom_target(i BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/j COMMAND k)
+add_custom_target(l BYPRODUCTS "$<TARGET_PROPERTY:prop>" COMMAND m)
+add_custom_target(n BYPRODUCTS "$<OUTPUT_CONFIG:n>" COMMAND o)
+add_custom_target(p BYPRODUCTS "$<COMMAND_CONFIG:p>" COMMAND q)
diff --git a/Tests/RunCMake/add_custom_target/BadCommand-result.txt b/Tests/RunCMake/add_custom_target/BadCommand-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/add_custom_target/BadCommand-stderr.txt b/Tests/RunCMake/add_custom_target/BadCommand-stderr.txt
new file mode 100644 (file)
index 0000000..dfdf8f8
--- /dev/null
@@ -0,0 +1,21 @@
+(CMake Error at BadCommand.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<OUTPUT_CONFIG:a>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+)+(CMake Error at BadCommand.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<COMMAND_CONFIG:b>
+
+  Expression did not evaluate to a known generator expression
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+)+
diff --git a/Tests/RunCMake/add_custom_target/BadCommand.cmake b/Tests/RunCMake/add_custom_target/BadCommand.cmake
new file mode 100644 (file)
index 0000000..dadf038
--- /dev/null
@@ -0,0 +1,4 @@
+add_custom_target(drive
+  COMMAND "$<1:$<OUTPUT_CONFIG:a>>"
+  COMMAND "$<1:$<COMMAND_CONFIG:b>>"
+  )
index f5d5dd2..22a9ed4 100644 (file)
@@ -1,6 +1,7 @@
 include(RunCMake)
 
 run_cmake(BadByproduct)
+run_cmake(BadCommand)
 run_cmake(BadTargetName)
 run_cmake(ByproductsNoCommand)
 run_cmake(CommandExpandsEmpty)
diff --git a/Tests/RunCMake/add_library/CMP0073-stderr.txt b/Tests/RunCMake/add_library/CMP0073-stderr.txt
new file mode 100644 (file)
index 0000000..7f43fd7
--- /dev/null
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0073.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0073 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-invalid-arg-result.txt b/Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-invalid-arg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-no-arg-result.txt b/Tests/RunCMake/cmake_path/APPEND_STRING-OUTPUT_VARIABLE-no-arg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/APPEND_STRING-wrong-path-result.txt b/Tests/RunCMake/cmake_path/APPEND_STRING-wrong-path-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
similarity index 73%
rename from Tests/RunCMake/cmake_path/CONCAT.cmake
rename to Tests/RunCMake/cmake_path/APPEND_STRING.cmake
index 62b5eb0..ea5f2dd 100644 (file)
@@ -3,13 +3,13 @@ include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
 unset (errors)
 
 set (path "/a/b")
-cmake_path (CONCAT path "cd")
+cmake_path (APPEND_STRING path "cd")
 if (NOT path STREQUAL "/a/bcd")
   list (APPEND errors "'${path}' instead of 'a/bcd'")
 endif()
 
 set (path "/a/b")
-cmake_path (CONCAT path "cd" "ef" OUTPUT_VARIABLE output)
+cmake_path (APPEND_STRING path "cd" "ef" OUTPUT_VARIABLE output)
 if (NOT path STREQUAL "/a/b")
   list (APPEND errors "input changed unexpectedly")
 endif()
@@ -17,4 +17,4 @@ if (NOT output STREQUAL "/a/bcdef")
   list (APPEND errors "'${output}' instead of 'a/bcdef'")
 endif()
 
-check_errors (CONCAT ${errors})
+check_errors (APPEND_STRING ${errors})
index bc6b9b4..ecf7c82 100644 (file)
@@ -2,19 +2,19 @@
 include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
 unset (errors)
 
-set (path "a///b/c")
-cmake_path(COMPARE path EQUAL "a/b/c" output)
+set(path "a///b/c")
+cmake_path(COMPARE "${path}" EQUAL "a/b/c" output)
 if (NOT output)
   list (APPEND errors "'${path}' not equal to 'a/b/c'")
 endif()
 
 set (path "a/b/d/../c")
-cmake_path(COMPARE path NOT_EQUAL "a/b/c" output)
+cmake_path(COMPARE "${path}" NOT_EQUAL "a/b/c" output)
 if (NOT output)
   list (APPEND errors "'${path}' equal to 'a/b/c'")
 endif()
 cmake_path(NORMAL_PATH path)
-cmake_path(COMPARE path EQUAL "a/b/c" output)
+cmake_path(COMPARE "${path}" EQUAL "a/b/c" output)
 if (NOT output)
   list (APPEND errors "'${path}' not equal to 'a/b/c'")
 endif()
diff --git a/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-invalid-output-result.txt b/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-invalid-output-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-missing-output-result.txt b/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-missing-output-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-unexpected-arg-result.txt b/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-unexpected-arg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-wrong-path-result.txt b/Tests/RunCMake/cmake_path/GET-RELATIVE_PART-wrong-path-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
index e68e654..463bc47 100644 (file)
@@ -61,9 +61,9 @@ if (NOT output STREQUAL "cc.ext1")
   list (APPEND errors "STEM LAST_ONLY returns bad data: ${output}")
 endif()
 
-cmake_path(GET path RELATIVE_PATH output)
+cmake_path(GET path RELATIVE_PART output)
 if (NOT output STREQUAL "aa/bb/cc.ext1.ext2")
-  list (APPEND errors "RELATIVE_PATH returns bad data: ${output}")
+  list (APPEND errors "RELATIVE_PART returns bad data: ${output}")
 endif()
 
 cmake_path(GET path PARENT_PATH output)
@@ -112,9 +112,9 @@ if (NOT output STREQUAL "")
   list (APPEND errors "STEM returns bad data: ${output}")
 endif()
 
-cmake_path(GET path RELATIVE_PATH output)
+cmake_path(GET path RELATIVE_PART output)
 if (NOT output STREQUAL path)
-  list (APPEND errors "RELATIVE_PATH returns bad data: ${output}")
+  list (APPEND errors "RELATIVE_PART returns bad data: ${output}")
 endif()
 
 cmake_path(GET path PARENT_PATH output)
@@ -173,9 +173,9 @@ if (NOT output STREQUAL "")
   list (APPEND errors "STEM returns bad data: ${output}")
 endif()
 
-cmake_path(GET path RELATIVE_PATH output)
+cmake_path(GET path RELATIVE_PART output)
 if (NOT output STREQUAL "")
-  list (APPEND errors "RELATIVE_PATH returns bad data: ${output}")
+  list (APPEND errors "RELATIVE_PART returns bad data: ${output}")
 endif()
 
 cmake_path(GET path PARENT_PATH output)
index dfcf2b2..eb04f7f 100644 (file)
@@ -14,11 +14,6 @@ set (path1 "a///b/c/../d")
 cmake_path(HASH path1 hash1)
 set (path2 "a/b////d")
 cmake_path(HASH path2 hash2)
-if (hash1 STREQUAL hash2)
-  list (APPEND errors "'hash values equal for '${path1}' and '${path2}'")
-endif()
-cmake_path(HASH path1 hash1 NORMALIZE)
-cmake_path(HASH path2 NORMALIZE hash2)
 if (NOT hash1 STREQUAL hash2)
   list (APPEND errors "'hash values not equal for '${path1}' and '${path2}'")
 endif()
index eb73bd5..e76776c 100644 (file)
@@ -96,14 +96,14 @@ if (output)
 endif()
 
 set (path "/a/b")
-cmake_path(HAS_RELATIVE_PATH path output)
+cmake_path(HAS_RELATIVE_PART path output)
 if (NOT output)
-  list (APPEND errors "RELATIVE_PATH: ${path} does not have relative path")
+  list (APPEND errors "RELATIVE_PART: ${path} does not have relative part")
 endif()
 set (path "/")
-cmake_path(HAS_RELATIVE_PATH path output)
+cmake_path(HAS_RELATIVE_PART path output)
 if (output)
-  list (APPEND errors "RELATIVE_PATH: ${path} has relative path")
+  list (APPEND errors "RELATIVE_PART: ${path} has relative part")
 endif()
 
 set (path "/a/b")
@@ -180,21 +180,21 @@ if (WIN32)
   endif()
 
   set (path "c:/a/b")
-  cmake_path(HAS_RELATIVE_PATH path output)
+  cmake_path(HAS_RELATIVE_PART path output)
   if (NOT output)
-    list (APPEND errors "RELATIVE_PATH: ${path} does not have relative path")
+    list (APPEND errors "RELATIVE_PART: ${path} does not have relative part")
   endif()
 
   set (path "c:a/b")
-  cmake_path(HAS_RELATIVE_PATH path output)
+  cmake_path(HAS_RELATIVE_PART path output)
   if (NOT output)
-    list (APPEND errors "RELATIVE_PATH: ${path} does not have relative path")
+    list (APPEND errors "RELATIVE_PART: ${path} does not have relative part")
   endif()
 
   set (path "//host/b")
-  cmake_path(HAS_RELATIVE_PATH path output)
+  cmake_path(HAS_RELATIVE_PART path output)
   if (NOT output)
-    list (APPEND errors "RELATIVE_PATH: ${path} does not have relative path")
+    list (APPEND errors "RELATIVE_PART: ${path} does not have relative part")
   endif()
 
   set (path "c:/a/b")
diff --git a/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-invalid-output-result.txt b/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-invalid-output-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-missing-output-result.txt b/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-missing-output-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-unexpected-arg-result.txt b/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-unexpected-arg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-wrong-path-result.txt b/Tests/RunCMake/cmake_path/HAS_RELATIVE_PART-wrong-path-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
index 53da93b..9160dab 100644 (file)
@@ -18,5 +18,10 @@ if (NOT output)
   list (APPEND errors "'${path} is not prefix of 'a/b/d/e'")
 endif()
 
+set(path "/a/b/..")
+cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE output)
+if (NOT output)
+  list (APPEND errors "'${path} is not prefix of '/a/c/../b'")
+endif()
 
 check_errors (IS_PREFIX ${errors})
diff --git a/Tests/RunCMake/cmake_path/PROXIMATE_PATH.cmake b/Tests/RunCMake/cmake_path/PROXIMATE_PATH.cmake
deleted file mode 100644 (file)
index ad23377..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-
-include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
-unset (errors)
-
-if (WIN32)
-  set (path "c:/a/d")
-  cmake_path(PROXIMATE_PATH path BASE_DIRECTORY "e/d/c")
-  if (NOT path STREQUAL "c:/a/d")
-    list (APPEND errors "'${path}' instead of 'c:/a/d'")
-  endif()
-else()
-  set (path "/a/d")
-  cmake_path(PROXIMATE_PATH path BASE_DIRECTORY "e/d/c")
-  if (NOT path STREQUAL "/a/d")
-    list (APPEND errors "'${path}' instead of '/a/d'")
-  endif()
-endif()
-
-set (path "/a/d")
-cmake_path(PROXIMATE_PATH path BASE_DIRECTORY "/a/b/c" OUTPUT_VARIABLE output)
-if (NOT path STREQUAL "/a/d")
-  list (APPEND errors "input changed unexpectedly")
-endif()
-if (NOT output STREQUAL "../../d")
-  list (APPEND errors "'${output}' instead of '../../d'")
-endif()
-
-set (path "${CMAKE_CURRENT_SOURCE_DIR}/a/d")
-cmake_path(PROXIMATE_PATH path)
-if (NOT path STREQUAL "a/d")
-  list (APPEND errors "'${path}' instead of 'a/d'")
-endif()
-
-set (path "a/b/c")
-cmake_path(PROXIMATE_PATH path)
-if (NOT path STREQUAL "a/b/c")
-  list (APPEND errors "'${path}' instead of 'a/b/c'")
-endif()
-
-
-check_errors (PROXIMATE_PATH ${errors})
index ca9cba6..991f46b 100644 (file)
@@ -7,25 +7,20 @@ set (RunCMake-stderr-file "wrong-path-stderr.txt")
 
 ### GET sub-command
 foreach (subcommand IN ITEMS ROOT_NAME ROOT_DIRECTORY ROOT_PATH FILENAME EXTENSION
-                             STEM RELATIVE_PATH PARENT_PATH)
+                             STEM RELATIVE_PART PARENT_PATH)
   run_cmake_command (GET-${subcommand}-wrong-path "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=GET wrong_path ${subcommand} output" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
-### COMPARE sub-command
-foreach (subcommand IN ITEMS EQUAL NOT_EQUAL)
-  run_cmake_command (COMPARE-${subcommand}-wrong-path "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=COMPARE wrong_path ${subcommand} path2 output" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
-endforeach()
-
-foreach (command IN ITEMS CONCAT REMOVE_FILENAME REPLACE_FILENAME
+foreach (command IN ITEMS APPEND_STRING REMOVE_FILENAME REPLACE_FILENAME
                           REMOVE_EXTENSION REPLACE_EXTENSION NORMAL_PATH
-                          RELATIVE_PATH PROXIMATE_PATH ABSOLUTE_PATH)
+                          RELATIVE_PATH ABSOLUTE_PATH)
   run_cmake_command (${command}-wrong-path "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=${command} wrong_path" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
 foreach (command IN ITEMS NATIVE_PATH
                           HAS_ROOT_NAME HAS_ROOT_DIRECTORY HAS_ROOT_PATH
                           HAS_FILENAME HAS_EXTENSION HAS_STEM
-                          HAS_RELATIVE_PATH HAS_PARENT_PATH
+                          HAS_RELATIVE_PART HAS_PARENT_PATH
                           IS_ABSOLUTE IS_RELATIVE IS_PREFIX HASH)
   if (command STREQUAL "IS_PREFIX")
     set (extra_args path2)
@@ -41,7 +36,7 @@ set (RunCMake-stderr-file "missing-output-stderr.txt")
 
 ### GET sub-command
 foreach (subcommand IN ITEMS ROOT_NAME ROOT_DIRECTORY ROOT_PATH FILENAME EXTENSION
-                             STEM RELATIVE_PATH PARENT_PATH)
+                             STEM RELATIVE_PART PARENT_PATH)
   run_cmake_command (GET-${subcommand}-missing-output "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=GET path ${subcommand}" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
@@ -55,10 +50,10 @@ foreach (subcommand IN ITEMS EQUAL NOT_EQUAL)
   run_cmake_command (COMPARE-${subcommand}-missing-output "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=COMPARE path ${subcommand} path2" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
-foreach (command IN ITEMS CMAKE_PATH NATIVE_PATH
+foreach (command IN ITEMS SET NATIVE_PATH
                           HAS_ROOT_NAME HAS_ROOT_DIRECTORY HAS_ROOT_PATH
                           HAS_FILENAME HAS_EXTENSION HAS_STEM
-                          HAS_RELATIVE_PATH HAS_PARENT_PATH
+                          HAS_RELATIVE_PART HAS_PARENT_PATH
                           IS_ABSOLUTE IS_RELATIVE IS_PREFIX HASH)
   if (command STREQUAL "IS_PREFIX")
     set (extra_args path2)
@@ -72,9 +67,9 @@ endforeach()
 ## OUTPUT_VARIABLE without argument
 set (RunCMake-stderr-file "OUTPUT_VARIABLE-no-arg-stderr.txt")
 
-foreach (command IN ITEMS APPEND CONCAT REMOVE_FILENAME REPLACE_FILENAME
+foreach (command IN ITEMS APPEND APPEND_STRING REMOVE_FILENAME REPLACE_FILENAME
                           REMOVE_EXTENSION REPLACE_EXTENSION NORMAL_PATH
-                          RELATIVE_PATH PROXIMATE_PATH ABSOLUTE_PATH)
+                          RELATIVE_PATH ABSOLUTE_PATH)
   run_cmake_command (${command}-OUTPUT_VARIABLE-no-arg "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=${command} path OUTPUT_VARIABLE" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
@@ -84,7 +79,7 @@ set (RunCMake-stderr-file "invalid-output-var-stderr.txt")
 
 ### GET sub-command
 foreach (subcommand IN ITEMS ROOT_NAME ROOT_DIRECTORY ROOT_PATH FILENAME EXTENSION
-                             STEM RELATIVE_PATH PARENT_PATH)
+                             STEM RELATIVE_PART PARENT_PATH)
   run_cmake_command (GET-${subcommand}-invalid-output "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=GET path ${subcommand}"  -DCHECK_INVALID_OUTPUT=ON -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
@@ -98,10 +93,10 @@ foreach (subcommand IN ITEMS EQUAL NOT_EQUAL)
   run_cmake_command (COMPARE-${subcommand}-invalid-output "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=COMPARE path ${subcommand} path2" -DCHECK_INVALID_OUTPUT=ON -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
-foreach (command IN ITEMS CMAKE_PATH NATIVE_PATH
+foreach (command IN ITEMS NATIVE_PATH
                           HAS_ROOT_NAME HAS_ROOT_DIRECTORY HAS_ROOT_PATH
                           HAS_FILENAME HAS_EXTENSION HAS_STEM
-                          HAS_RELATIVE_PATH HAS_PARENT_PATH
+                          HAS_RELATIVE_PART HAS_PARENT_PATH
                           IS_ABSOLUTE IS_RELATIVE IS_PREFIX HASH)
   if (command STREQUAL "IS_PREFIX")
     set (extra_args path2)
@@ -111,9 +106,9 @@ foreach (command IN ITEMS CMAKE_PATH NATIVE_PATH
   run_cmake_command (${command}-invalid-output "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=${command} path ${extra_args}" -DCHECK_INVALID_OUTPUT=ON -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
-foreach (command IN ITEMS APPEND CONCAT REMOVE_FILENAME REPLACE_FILENAME
+foreach (command IN ITEMS APPEND APPEND_STRING REMOVE_FILENAME REPLACE_FILENAME
                           REMOVE_EXTENSION REPLACE_EXTENSION NORMAL_PATH
-                          RELATIVE_PATH PROXIMATE_PATH ABSOLUTE_PATH)
+                          RELATIVE_PATH ABSOLUTE_PATH)
   run_cmake_command (${command}-OUTPUT_VARIABLE-invalid-arg "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=${command} path OUTPUT_VARIABLE" -DCHECK_INVALID_OUTPUT=ON -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
@@ -123,7 +118,7 @@ set (RunCMake-stderr-file "unexpected-arg-stderr.txt")
 
 ### GET sub-command
 foreach (subcommand IN ITEMS ROOT_NAME ROOT_DIRECTORY ROOT_PATH FILENAME EXTENSION
-                             STEM RELATIVE_PATH PARENT_PATH)
+                             STEM RELATIVE_PART PARENT_PATH)
   if (subcommand STREQUAL "EXTENSION" OR subcommand STREQUAL "STEM")
     set (extra_args LAST_ONLY)
   else()
@@ -139,7 +134,7 @@ endforeach()
 
 foreach (command IN ITEMS REMOVE_FILENAME REPLACE_FILENAME
                           REMOVE_EXTENSION REPLACE_EXTENSION NORMAL_PATH
-                          RELATIVE_PATH PROXIMATE_PATH ABSOLUTE_PATH)
+                          RELATIVE_PATH ABSOLUTE_PATH)
   if (command STREQUAL "REPLACE_FILENAME" OR command STREQUAL "REPLACE_EXTENSION")
     set (extra_args input)
   else()
@@ -148,10 +143,10 @@ foreach (command IN ITEMS REMOVE_FILENAME REPLACE_FILENAME
   run_cmake_command (${command}-unexpected-arg "${CMAKE_COMMAND}" "-DCMAKE_PATH_ARGUMENTS=${command} path ${extra_args} unexpected" -P "${RunCMake_SOURCE_DIR}/call-cmake_path.cmake")
 endforeach()
 
-foreach (command IN ITEMS CMAKE_PATH NATIVE_PATH
+foreach (command IN ITEMS SET NATIVE_PATH
                           HAS_ROOT_NAME HAS_ROOT_DIRECTORY HAS_ROOT_PATH
                           HAS_FILENAME HAS_EXTENSION HAS_STEM
-                          HAS_RELATIVE_PATH HAS_PARENT_PATH
+                          HAS_RELATIVE_PART HAS_PARENT_PATH
                           IS_ABSOLUTE IS_RELATIVE IS_PREFIX
                           HASH)
   if (command STREQUAL "IS_PREFIX")
@@ -170,17 +165,16 @@ run_cmake(COMPARE-wrong-operator)
 set (RunCMake_TEST_OPTIONS "-DRunCMake_SOURCE_DIR=${RunCMake_SOURCE_DIR}")
 
 run_cmake(GET)
+run_cmake(SET)
 run_cmake(APPEND)
-run_cmake(CONCAT)
+run_cmake(APPEND_STRING)
 run_cmake(REMOVE_FILENAME)
 run_cmake(REPLACE_FILENAME)
 run_cmake(REMOVE_EXTENSION)
 run_cmake(REPLACE_EXTENSION)
 run_cmake(NORMAL_PATH)
 run_cmake(RELATIVE_PATH)
-run_cmake(PROXIMATE_PATH)
 run_cmake(ABSOLUTE_PATH)
-run_cmake(CMAKE_PATH)
 run_cmake(NATIVE_PATH)
 run_cmake(CONVERT)
 run_cmake(COMPARE)
diff --git a/Tests/RunCMake/cmake_path/SET-missing-output-result.txt b/Tests/RunCMake/cmake_path/SET-missing-output-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_path/SET-unexpected-arg-result.txt b/Tests/RunCMake/cmake_path/SET-unexpected-arg-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
similarity index 65%
rename from Tests/RunCMake/cmake_path/CMAKE_PATH.cmake
rename to Tests/RunCMake/cmake_path/SET.cmake
index b9320f3..445783e 100644 (file)
@@ -2,42 +2,42 @@
 include ("${RunCMake_SOURCE_DIR}/check_errors.cmake")
 unset (errors)
 
-cmake_path(CMAKE_PATH path "/x/y/z/../../a/d")
+cmake_path(SET path "/x/y/z/../../a/d")
 if (NOT path STREQUAL "/x/y/z/../../a/d")
   list (APPEND errors "'${path}' instead of '/x/y/z/../../a/d'")
 endif()
-cmake_path(CMAKE_PATH path NORMALIZE "/x/y/z/../../a/d")
+cmake_path(SET path NORMALIZE "/x/y/z/../../a/d")
 if (NOT path STREQUAL "/x/a/d")
   list (APPEND errors "'${path}' instead of '/x/a/d'")
 endif()
 
 if (WIN32)
-  cmake_path(CMAKE_PATH path "/x\\y/z\\..\\../a/d")
+  cmake_path(SET path "/x\\y/z\\..\\../a/d")
   if (NOT path STREQUAL "/x/y/z/../../a/d")
     list (APPEND errors "'${path}' instead of '/x/y/z/../../a/d'")
   endif()
-  cmake_path(CMAKE_PATH path NORMALIZE "/x\\y/z\\..\\../a/d")
+  cmake_path(SET path NORMALIZE "/x\\y/z\\..\\../a/d")
   if (NOT path STREQUAL "/x/a/d")
     list (APPEND errors "'${path}' instead of '/x/a/d'")
   endif()
 
-  cmake_path(CMAKE_PATH path "//?/c:/x\\y/z\\..\\../a/d")
+  cmake_path(SET path "//?/c:/x\\y/z\\..\\../a/d")
   if (NOT path STREQUAL "c:/x/y/z/../../a/d")
     list (APPEND errors "'${path}' instead of 'c:/x/y/z/../../a/d'")
   endif()
-  cmake_path(CMAKE_PATH path NORMALIZE "//?/c:/x\\y/z\\..\\../a/d")
+  cmake_path(SET path NORMALIZE "//?/c:/x\\y/z\\..\\../a/d")
   if (NOT path STREQUAL "c:/x/a/d")
     list (APPEND errors "'${path}' instead of 'c:/x/a/d'")
   endif()
 
-  cmake_path(CMAKE_PATH path "\\\\?\\UNC/host/x\\y/z\\..\\../a/d")
+  cmake_path(SET path "\\\\?\\UNC/host/x\\y/z\\..\\../a/d")
   if (NOT path STREQUAL "//host/x/y/z/../../a/d")
     list (APPEND errors "'${path}' instead of '//host/x/y/z/../../a/d'")
   endif()
-  cmake_path(CMAKE_PATH path NORMALIZE "\\\\?\\UNC\\host/x\\y/z\\..\\../a/d")
+  cmake_path(SET path NORMALIZE "\\\\?\\UNC\\host/x\\y/z\\..\\../a/d")
   if (NOT path STREQUAL "//host/x/a/d")
     list (APPEND errors "'${path}' instead of '//host/x/a/d'")
   endif()
 endif()
 
-check_errors (CMAKE_PATH ${errors})
+check_errors (SET ${errors})
index 71694fb..0a2e3f9 100644 (file)
@@ -16,6 +16,13 @@ run_cmake(NewLineStyle-WrongArg)
 run_cmake(NewLineStyle-ValidArg)
 run_cmake(NewLineStyle-COPYONLY)
 run_cmake(NoSourcePermissions)
+run_cmake(SourcePermissionsInvalidArg-1)
+run_cmake(SourcePermissionsInvalidArg-2)
+run_cmake(SourcePermissionsInvalidArg-3)
+run_cmake(SourcePermissionsInvalidArg-4)
+run_cmake(SourcePermissionsInvalidArg-5)
+run_cmake(UseSourcePermissions)
+run_cmake(SourcePermissions)
 
 if(RunCMake_GENERATOR MATCHES "Make")
   # Use a single build tree for a few tests without cleaning.
diff --git a/Tests/RunCMake/configure_file/SourcePermissions-result.txt b/Tests/RunCMake/configure_file/SourcePermissions-result.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/configure_file/SourcePermissions-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissions-stderr.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tests/RunCMake/configure_file/SourcePermissions.cmake b/Tests/RunCMake/configure_file/SourcePermissions.cmake
new file mode 100644 (file)
index 0000000..50330fc
--- /dev/null
@@ -0,0 +1,34 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt
+    FILE_PERMISSIONS
+        OWNER_READ OWNER_EXECUTE
+        GROUP_READ GROUP_EXECUTE
+        WORLD_READ
+)
+
+if (UNIX)
+  find_program(STAT_EXECUTABLE NAMES stat)
+  if(NOT STAT_EXECUTABLE)
+    return()
+  endif()
+
+  if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt"
+      OUTPUT_VARIABLE output
+    )
+  elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt"
+      OUTPUT_VARIABLE output
+    )
+  else()
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt"
+      OUTPUT_VARIABLE output
+    )
+  endif()
+
+  if (NOT output EQUAL "554")
+    message(FATAL_ERROR "configure file has different permissions than "
+        "desired, generated permissions: ${output}")
+  endif()
+
+endif()
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt
new file mode 100644 (file)
index 0000000..d483d34
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissionsInvalidArg-1.cmake:1 \(configure_file\):
+  configure_file given both USE_SOURCE_PERMISSIONS and NO_SOURCE_PERMISSIONS.
+  Only one option allowed.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake
new file mode 100644 (file)
index 0000000..4969880
--- /dev/null
@@ -0,0 +1,5 @@
+configure_file(sourcefile.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+    NO_SOURCE_PERMISSIONS
+    USE_SOURCE_PERMISSIONS
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt
new file mode 100644 (file)
index 0000000..2fcfe58
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissionsInvalidArg-2.cmake:1 \(configure_file\):
+  configure_file given both FILE_PERMISSIONS and NO_SOURCE_PERMISSIONS.  Only
+  one option allowed.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake
new file mode 100644 (file)
index 0000000..8a3fb87
--- /dev/null
@@ -0,0 +1,5 @@
+configure_file(sourcefile.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+    NO_SOURCE_PERMISSIONS
+    FILE_PERMISSIONS OWNER_READ
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt
new file mode 100644 (file)
index 0000000..29fae1b
--- /dev/null
@@ -0,0 +1,5 @@
+CMake Error at SourcePermissionsInvalidArg-3.cmake:1 \(configure_file\):
+  configure_file given both FILE_PERMISSIONS and USE_SOURCE_PERMISSIONS.
+  Only one option allowed.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake
new file mode 100644 (file)
index 0000000..78ecb0f
--- /dev/null
@@ -0,0 +1,5 @@
+configure_file(sourcefile.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+    USE_SOURCE_PERMISSIONS
+    FILE_PERMISSIONS OWNER_READ
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt
new file mode 100644 (file)
index 0000000..7d477cb
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissionsInvalidArg-4.cmake:1 \(configure_file\):
+  configure_file given FILE_PERMISSIONS without any options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake
new file mode 100644 (file)
index 0000000..308b455
--- /dev/null
@@ -0,0 +1,4 @@
+configure_file(sourcefile.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/sourcefile.txt
+    FILE_PERMISSIONS
+)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt
new file mode 100644 (file)
index 0000000..7cab120
--- /dev/null
@@ -0,0 +1,4 @@
+CMake Error at SourcePermissionsInvalidArg-5.cmake:1 \(configure_file\):
+  configure_file given invalid permission "OWNER_RX","GROUP_RWX".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake b/Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake
new file mode 100644 (file)
index 0000000..15c6f9a
--- /dev/null
@@ -0,0 +1,6 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/sourcefile-source-permissions.txt
+    FILE_PERMISSIONS
+        OWNER_READ OWNER_RX
+        GROUP_RWX
+)
diff --git a/Tests/RunCMake/configure_file/UseSourcePermissions.cmake b/Tests/RunCMake/configure_file/UseSourcePermissions.cmake
new file mode 100644 (file)
index 0000000..f7aedd1
--- /dev/null
@@ -0,0 +1,40 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt
+    ${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt
+    USE_SOURCE_PERMISSIONS
+)
+
+if (UNIX)
+  find_program(STAT_EXECUTABLE NAMES stat)
+  if(NOT STAT_EXECUTABLE)
+    return()
+  endif()
+
+  if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt"
+      OUTPUT_VARIABLE output1
+    )
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %Lp "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt"
+      OUTPUT_VARIABLE output2
+    )
+  elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt"
+      OUTPUT_VARIABLE output1
+    )
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -f %A "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt"
+      OUTPUT_VARIABLE output2
+    )
+  else()
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${CMAKE_CURRENT_SOURCE_DIR}/sourcefile.txt"
+      OUTPUT_VARIABLE output1
+    )
+    execute_process(COMMAND "${STAT_EXECUTABLE}" -c %a "${CMAKE_CURRENT_BINARY_DIR}/sourcefile-use-source-permissions.txt"
+      OUTPUT_VARIABLE output2
+    )
+  endif()
+
+  if (NOT output1 EQUAL output2)
+    message(FATAL_ERROR "configure file has different permissions source "
+        "permissions: ${output1} generated permissions: ${output2}")
+  endif()
+
+endif()
diff --git a/Tests/RunCMake/configure_file/sourcefile.txt b/Tests/RunCMake/configure_file/sourcefile.txt
new file mode 100644 (file)
index 0000000..2296808
--- /dev/null
@@ -0,0 +1 @@
+an empty file
index 140e4be..c35397c 100644 (file)
@@ -3,3 +3,7 @@
 # so that any ctest_submit calls fail with an error message.
 set(CTEST_DROP_METHOD "@CASE_DROP_METHOD@")
 set(CTEST_DROP_SITE "@CASE_DROP_SITE@")
+
+# do not use proxy for lookup of invalid site (DNS failure by proxy looks
+# different than DNS failure without proxy)
+set(ENV{no_proxy} "$ENV{no_proxy},@CASE_DROP_SITE@")
similarity index 89%
rename from Tests/CMakeTests/ELFTest.cmake.in
rename to Tests/RunCMake/file-RPATH/Common.cmake
index 85c2360..cc1efb5 100644 (file)
@@ -1,15 +1,6 @@
-set(names
-  elf32lsb.bin
-  elf32msb.bin
-  elf64lsb.bin
-  elf64msb.bin
-  )
-
 # Prepare binaries on which to operate.
-set(in "@CMAKE_CURRENT_SOURCE_DIR@/ELF")
-set(out "@CMAKE_CURRENT_BINARY_DIR@/ELF-Out")
-file(REMOVE_RECURSE "${out}")
-file(MAKE_DIRECTORY "${out}")
+set(in "${CMAKE_CURRENT_LIST_DIR}/${format}")
+set(out "${CMAKE_CURRENT_BINARY_DIR}")
 foreach(f ${names})
   file(COPY ${in}/${f} DESTINATION ${out} NO_SOURCE_PERMISSIONS)
   list(APPEND files "${out}/${f}")
diff --git a/Tests/RunCMake/file-RPATH/ELF.cmake b/Tests/RunCMake/file-RPATH/ELF.cmake
new file mode 100644 (file)
index 0000000..558b2e2
--- /dev/null
@@ -0,0 +1,9 @@
+set(names
+  elf32lsb.bin
+  elf32msb.bin
+  elf64lsb.bin
+  elf64msb.bin
+  )
+set(format ELF)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
old mode 100644 (file)
new mode 100755 (executable)
similarity index 100%
rename from Tests/CMakeTests/ELF/elf32lsb.bin
rename to Tests/RunCMake/file-RPATH/ELF/elf32lsb.bin
old mode 100644 (file)
new mode 100755 (executable)
similarity index 100%
rename from Tests/CMakeTests/ELF/elf32msb.bin
rename to Tests/RunCMake/file-RPATH/ELF/elf32msb.bin
old mode 100644 (file)
new mode 100755 (executable)
similarity index 100%
rename from Tests/CMakeTests/ELF/elf64lsb.bin
rename to Tests/RunCMake/file-RPATH/ELF/elf64lsb.bin
old mode 100644 (file)
new mode 100755 (executable)
similarity index 100%
rename from Tests/CMakeTests/ELF/elf64msb.bin
rename to Tests/RunCMake/file-RPATH/ELF/elf64msb.bin
diff --git a/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake b/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake
new file mode 100644 (file)
index 0000000..eb7b497
--- /dev/null
@@ -0,0 +1,9 @@
+include(RunCMake)
+
+if(HAVE_ELF_H)
+  run_cmake_command(ELF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ELF.cmake)
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+  run_cmake_command(XCOFF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/XCOFF.cmake)
+endif()
diff --git a/Tests/RunCMake/file-RPATH/XCOFF.cmake b/Tests/RunCMake/file-RPATH/XCOFF.cmake
new file mode 100644 (file)
index 0000000..b570920
--- /dev/null
@@ -0,0 +1,7 @@
+set(names
+  xcoff32.bin
+  xcoff64.bin
+  )
+set(format XCOFF)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
diff --git a/Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin b/Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin
new file mode 100644 (file)
index 0000000..2d8d961
Binary files /dev/null and b/Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin differ
diff --git a/Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin b/Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin
new file mode 100644 (file)
index 0000000..bb5f5a7
Binary files /dev/null and b/Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin differ
index c4ee53d..2143fa2 100644 (file)
@@ -2,6 +2,9 @@ include(RunCMake)
 
 run_cmake(cache_properties)
 run_cmake(directory_properties)
+run_cmake(get_directory_property_empty)
+run_cmake(get_directory_property_missing)
+run_cmake(get_directory_property_missingWithDir)
 run_cmake(global_properties)
 run_cmake(install_properties)
 run_cmake(source_properties)
diff --git a/Tests/RunCMake/get_property/get_directory_property_empty-result.txt b/Tests/RunCMake/get_property/get_directory_property_empty-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/get_property/get_directory_property_empty-stderr.txt b/Tests/RunCMake/get_property/get_directory_property_empty-stderr.txt
new file mode 100644 (file)
index 0000000..baa73f3
--- /dev/null
@@ -0,0 +1,4 @@
+^CMake Error at get_directory_property_empty.cmake:1 \(get_directory_property\):
+  get_directory_property given empty string for the property name to get
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/get_property/get_directory_property_empty.cmake b/Tests/RunCMake/get_property/get_directory_property_empty.cmake
new file mode 100644 (file)
index 0000000..b49be1c
--- /dev/null
@@ -0,0 +1 @@
+get_directory_property(outVar "")
diff --git a/Tests/RunCMake/get_property/get_directory_property_missing-result.txt b/Tests/RunCMake/get_property/get_directory_property_missing-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/get_property/get_directory_property_missing-stderr.txt b/Tests/RunCMake/get_property/get_directory_property_missing-stderr.txt
new file mode 100644 (file)
index 0000000..e101c76
--- /dev/null
@@ -0,0 +1,4 @@
+^CMake Error at get_directory_property_missing.cmake:1 \(get_directory_property\):
+  get_directory_property called with incorrect number of arguments
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/get_property/get_directory_property_missing.cmake b/Tests/RunCMake/get_property/get_directory_property_missing.cmake
new file mode 100644 (file)
index 0000000..c28157e
--- /dev/null
@@ -0,0 +1 @@
+get_directory_property(outVar)
diff --git a/Tests/RunCMake/get_property/get_directory_property_missingWithDir-result.txt b/Tests/RunCMake/get_property/get_directory_property_missingWithDir-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/get_property/get_directory_property_missingWithDir-stderr.txt b/Tests/RunCMake/get_property/get_directory_property_missingWithDir-stderr.txt
new file mode 100644 (file)
index 0000000..66deabb
--- /dev/null
@@ -0,0 +1,4 @@
+^CMake Error at get_directory_property_missingWithDir.cmake:1 \(get_directory_property\):
+  get_directory_property called with incorrect number of arguments
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/get_property/get_directory_property_missingWithDir.cmake b/Tests/RunCMake/get_property/get_directory_property_missingWithDir.cmake
new file mode 100644 (file)
index 0000000..573e14a
--- /dev/null
@@ -0,0 +1 @@
+get_directory_property(outVar DIRECTORY .)
index ac2335c..ee886e0 100644 (file)
@@ -1,4 +1,4 @@
-CMake Error at duplicate-deep-else.cmake:[0-9]+ \(else\):
-  A duplicate ELSE command was found inside an IF block.
+CMake Error at duplicate-deep-else\.cmake:[0-9]+ \(else\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
index ba6765c..60c8484 100644 (file)
@@ -1,4 +1,4 @@
-CMake Error at duplicate-else-after-elseif.cmake:[0-9]+ \(else\):
-  A duplicate ELSE command was found inside an IF block.
+CMake Error at duplicate-else-after-elseif\.cmake:[0-9]+ \(else\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
index e0dd01f..518c43f 100644 (file)
@@ -1,4 +1,4 @@
-CMake Error at duplicate-else.cmake:[0-9]+ \(else\):
-  A duplicate ELSE command was found inside an IF block.
+CMake Error at duplicate-else\.cmake:[0-9]+ \(else\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
index c4b0266..5138f11 100644 (file)
@@ -1,4 +1,4 @@
-CMake Error at misplaced-elseif.cmake:[0-9]+ \(elseif\):
-  An ELSEIF command was found after an ELSE command.
+CMake Error at misplaced-elseif\.cmake:[0-9]+ \(elseif\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)
index 70d013c..6d5c02f 100644 (file)
@@ -1,5 +1,5 @@
 CMake Error at ExportExportInclude.cmake:6 \(include\):
-  include could not find load file:
+  include could not find requested file:
 
     .*/Tests/RunCMake/include/ExportExportInclude-build/theTargets.cmake
 Call Stack \(most recent call first\):
diff --git a/Tests/RunCMake/include/IncludeIsDirectory-result.txt b/Tests/RunCMake/include/IncludeIsDirectory-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt b/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt
new file mode 100644 (file)
index 0000000..5735c29
--- /dev/null
@@ -0,0 +1,6 @@
+CMake Error at IncludeIsDirectory.cmake:1 \(include\):
+  include requested file is a directory:
+
+    .*/Tests/RunCMake/include/IncludeIsDirectory-build
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/include/IncludeIsDirectory.cmake b/Tests/RunCMake/include/IncludeIsDirectory.cmake
new file mode 100644 (file)
index 0000000..74189e3
--- /dev/null
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_BINARY_DIR}")
diff --git a/Tests/RunCMake/include/IncludeMalformed-result.txt b/Tests/RunCMake/include/IncludeMalformed-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/include/IncludeMalformed-stderr.txt b/Tests/RunCMake/include/IncludeMalformed-stderr.txt
new file mode 100644 (file)
index 0000000..fc75549
--- /dev/null
@@ -0,0 +1,13 @@
+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\):
+  include could not load requested file:
+
+    malformedInclude.cmake
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/include/IncludeMalformed.cmake b/Tests/RunCMake/include/IncludeMalformed.cmake
new file mode 100644 (file)
index 0000000..9560142
--- /dev/null
@@ -0,0 +1 @@
+include("malformedInclude.cmake")
index bea7d5c..8fb7201 100644 (file)
@@ -5,3 +5,5 @@ run_cmake(EmptyStringOptional)
 run_cmake(CMP0024-WARN)
 run_cmake(CMP0024-NEW)
 run_cmake(ExportExportInclude)
+run_cmake(IncludeIsDirectory)
+run_cmake(IncludeMalformed)
diff --git a/Tests/RunCMake/include/malformedInclude.cmake b/Tests/RunCMake/include/malformedInclude.cmake
new file mode 100644 (file)
index 0000000..3cec3ad
--- /dev/null
@@ -0,0 +1 @@
+if(
diff --git a/Tests/RunCMake/install/FILES-RENAME-all-check.cmake b/Tests/RunCMake/install/FILES-RENAME-all-check.cmake
new file mode 100644 (file)
index 0000000..7e9b103
--- /dev/null
@@ -0,0 +1 @@
+check_installed([[^src;src/script_Debug\.ps]])
diff --git a/Tests/RunCMake/install/FILES-RENAME-bad-result.txt b/Tests/RunCMake/install/FILES-RENAME-bad-result.txt
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt b/Tests/RunCMake/install/FILES-RENAME-bad-stderr.txt
new file mode 100644 (file)
index 0000000..9844158
--- /dev/null
@@ -0,0 +1,6 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<NOTAGENEX>
+
+  Expression did not evaluate to a known generator expression
diff --git a/Tests/RunCMake/install/FILES-RENAME-bad.cmake b/Tests/RunCMake/install/FILES-RENAME-bad.cmake
new file mode 100644 (file)
index 0000000..5be0bb2
--- /dev/null
@@ -0,0 +1,4 @@
+install(FILES empty.c
+  DESTINATION mybin
+  RENAME $<NOTAGENEX>
+  )
diff --git a/Tests/RunCMake/install/FILES-RENAME.cmake b/Tests/RunCMake/install/FILES-RENAME.cmake
new file mode 100644 (file)
index 0000000..5896e64
--- /dev/null
@@ -0,0 +1,4 @@
+install(FILES script.bat
+  DESTINATION src
+  RENAME script_$<CONFIG>.ps
+  )
index d64d88b..efd03df 100644 (file)
@@ -48,14 +48,16 @@ in directory:
   endif()
 endfunction()
 
-# Wrapper for run_cmake() that skips platforms that are non-ELF or have no RPATH support
-function(run_cmake_ELFRPATH_only case)
-  if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+# Wrapper for run_cmake() that skips platforms on which we do not support editing the RPATH.
+function(run_cmake_EDIT_RPATH_only case)
+  if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT MATCHES "^(ELF|XCOFF)$")
     run_cmake(${case})
   else()
     # Sanity check against a platform known to be ELF-based
     if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
       message(FATAL_ERROR "Expected platform Linux to advertize itself as ELF-based, but it did not.")
+    elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+      message(FATAL_ERROR "Expected platform AIX to advertize itself as XCOFF-based, but it did not.")
     else()
       message(STATUS "${case} - SKIPPED (No ELF-based platform found)")
     endif()
@@ -63,7 +65,7 @@ function(run_cmake_ELFRPATH_only case)
 endfunction()
 
 run_cmake(TARGETS-FILE_RPATH_CHANGE-old_rpath)
-run_cmake_ELFRPATH_only(TARGETS-FILE_RPATH_CHANGE-new_rpath)
+run_cmake_EDIT_RPATH_only(TARGETS-FILE_RPATH_CHANGE-new_rpath)
 run_cmake(DIRECTORY-MESSAGE_NEVER)
 run_cmake(DIRECTORY-PATTERN-MESSAGE_NEVER)
 run_cmake(DIRECTORY-message)
@@ -74,6 +76,7 @@ run_cmake(SkipInstallRulesNoWarning2)
 run_cmake(DIRECTORY-DIRECTORY-bad)
 run_cmake(DIRECTORY-DESTINATION-bad)
 run_cmake(FILES-DESTINATION-bad)
+run_cmake(FILES-RENAME-bad)
 run_cmake(TARGETS-DESTINATION-bad)
 run_cmake(EXPORT-OldIFace)
 run_cmake(EXPORT-UnknownExport)
@@ -91,6 +94,10 @@ run_cmake(TARGETS-NAMELINK_COMPONENT-bad-exc)
 run_cmake(FILES-DESTINATION-TYPE)
 run_cmake(DIRECTORY-DESTINATION-TYPE)
 
+set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE:STRING=Debug")
+run_install_test(FILES-RENAME)
+unset(RunCMake_TEST_OPTIONS)
+
 if(APPLE)
   run_cmake(TARGETS-Apple-Defaults)
 endif()
index 673fdde..6b2faa3 100644 (file)
@@ -22,6 +22,8 @@ macro(skip_without_rpath_change_rule)
     # Sanity check against a platform known to generate a file(RPATH_CHANGE) rule
     if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
       message(FATAL_ERROR "Expected generated file(RPATH_CHANGE) rule on platform Linux.")
+    elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+      message(FATAL_ERROR "Expected generated file(RPATH_CHANGE) rule on platform AIX.")
     else()
       message(STATUS "${test} - All checks skipped. No file(RPATH_CHANGE) rule found on this platform.")
       return()
diff --git a/Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake b/Tests/RunCMake/list/REMOVE_ITEM-NoItemArg.cmake
new file mode 100644 (file)
index 0000000..f69c024
--- /dev/null
@@ -0,0 +1,5 @@
+set(ls "a" "b" "c")
+list(REMOVE_ITEM ls alpha)
+if (NOT ls STREQUAL "a;b;c")
+  message(FATAL_ERROR "list(REMOVE_ITEM) modified for empty item")
+endif ()
index b4a91bc..c11891c 100644 (file)
@@ -30,6 +30,7 @@ run_cmake(FILTER-NotList)
 run_cmake(REMOVE_AT-NotList)
 run_cmake(REMOVE_DUPLICATES-NotList)
 run_cmake(REMOVE_ITEM-NotList)
+run_cmake(REMOVE_ITEM-NoItemArg)
 run_cmake(REVERSE-NotList)
 run_cmake(SORT-NotList)
 
index 22226f2..da44726 100644 (file)
@@ -1,5 +1,5 @@
 ^CMake Error at MATH-InvalidExpression.cmake:1 \(math\):
-  math cannot parse the expression: "INVALID": syntax error, unexpected \$end
-  \(7\).
+  math cannot parse the expression: "INVALID": syntax error, unexpected end
+  of file \(7\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/pseudo_llvm-rc.c b/Tests/RunCMake/pseudo_llvm-rc.c
new file mode 100644 (file)
index 0000000..7acb2a3
--- /dev/null
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char* argv[])
+{
+  FILE* source;
+  FILE* target;
+  int i;
+  for (i = 1; i < argc; ++i) {
+    if (strcmp(argv[i], "-bad") == 0) {
+      fprintf(stdout, "stdout from bad command line arg '-bad'\n");
+      fprintf(stderr, "stderr from bad command line arg '-bad'\n");
+      return 1;
+    }
+  }
+  source = fopen(argv[argc - 1], "rb");
+  if (source == NULL) {
+    return 1;
+  }
+  target = fopen(argv[argc - 2], "wb");
+  if (target != NULL) {
+    char buffer[500];
+    size_t n = fread(buffer, 1, sizeof(buffer), source);
+    fwrite(buffer, 1, n, target);
+    fclose(source);
+    fclose(target);
+    return 0;
+  }
+  return 1;
+}
index 8325def..bdf5810 100644 (file)
@@ -7,7 +7,7 @@ endif()
 set (TEST_EXE_DIR "${CMAKE_CURRENT_BINARY_DIR}/TestExe")
 file(MAKE_DIRECTORY "${TEST_EXE_DIR}")
 file(COPY "${CMAKE_COMMAND}" DESTINATION "${TEST_EXE_DIR}")
-get_filename_component (cmake_exe "${CMAKE_COMMAND}" NAME)
+cmake_path (GET CMAKE_COMMAND FILENAME cmake_exe)
 
 set (ENV{PATH} "${TEST_EXE_DIR}")
 
index 07572ba..2826cc9 100644 (file)
@@ -7,7 +7,7 @@ endif()
 set (TEST_EXE_DIR "${CMAKE_CURRENT_BINARY_DIR}/TestExe")
 file(MAKE_DIRECTORY "${TEST_EXE_DIR}")
 file(COPY "${CMAKE_COMMAND}" DESTINATION "${TEST_EXE_DIR}")
-get_filename_component (cmake_exe "${CMAKE_COMMAND}" NAME)
+cmake_path (GET CMAKE_COMMAND FILENAME cmake_exe)
 
 set (ENV{PATH} "${TEST_EXE_DIR}")
 
index b67c598..48a750d 100644 (file)
@@ -1,3 +1,6 @@
 include(RunCMake)
 
 run_cmake(empty_keyword_args)
+run_cmake(include_before)
+run_cmake(include_after)
+run_cmake(include_default)
diff --git a/Tests/RunCMake/target_include_directories/include_after.cmake b/Tests/RunCMake/target_include_directories/include_after.cmake
new file mode 100644 (file)
index 0000000..68a08a7
--- /dev/null
@@ -0,0 +1,18 @@
+enable_language(C)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.c" "int main() { return 0;}")
+
+set(include_dir "${CMAKE_CURRENT_BINARY_DIR}/dir")
+set(after_include_dir "${CMAKE_CURRENT_BINARY_DIR}/dirAfter")
+file(MAKE_DIRECTORY "${include_dir}")
+file(MAKE_DIRECTORY "${after_include_dir}")
+
+add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.c")
+include_directories("${include_dir}")
+target_include_directories(main AFTER PRIVATE "${after_include_dir}")
+
+get_target_property(actual_include_dirs main INCLUDE_DIRECTORIES)
+set(desired_include_dirs "${include_dir}" "${after_include_dir}")
+
+if (NOT "${actual_include_dirs}" MATCHES "${desired_include_dirs}")
+    message(SEND_ERROR "include after does not work")
+endif()
diff --git a/Tests/RunCMake/target_include_directories/include_before.cmake b/Tests/RunCMake/target_include_directories/include_before.cmake
new file mode 100644 (file)
index 0000000..9bebecd
--- /dev/null
@@ -0,0 +1,18 @@
+enable_language(C)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.c" "int main() { return 0;}")
+
+set(include_dir "${CMAKE_CURRENT_BINARY_DIR}/dir")
+set(before_include_dir "${CMAKE_CURRENT_BINARY_DIR}/dirBefore")
+file(MAKE_DIRECTORY "${include_dir}")
+file(MAKE_DIRECTORY "${before_include_dir}")
+
+add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.c")
+include_directories("${include_dir}")
+target_include_directories(main BEFORE PRIVATE "${before_include_dir}")
+
+get_target_property(actual_include_dirs main INCLUDE_DIRECTORIES)
+set(desired_include_dirs "${before_include_dir}" "${include_dir}")
+
+if (NOT "${actual_include_dirs}" MATCHES "${desired_include_dirs}")
+    message(SEND_ERROR "include before does not work")
+endif()
diff --git a/Tests/RunCMake/target_include_directories/include_default.cmake b/Tests/RunCMake/target_include_directories/include_default.cmake
new file mode 100644 (file)
index 0000000..88b2502
--- /dev/null
@@ -0,0 +1,18 @@
+enable_language(C)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.c" "int main() { return 0;}")
+
+set(include_dir "${CMAKE_CURRENT_BINARY_DIR}/dir")
+set(default_include_dir "${CMAKE_CURRENT_BINARY_DIR}/dirDefault")
+file(MAKE_DIRECTORY "${include_dir}")
+file(MAKE_DIRECTORY "${default_include_dir}")
+
+add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.c")
+include_directories("${include_dir}")
+target_include_directories(main AFTER PRIVATE "${default_include_dir}")
+
+get_target_property(actual_include_dirs main INCLUDE_DIRECTORIES)
+set(desired_include_dirs "${include_dir}" "${default_include_dir}")
+
+if (NOT "${actual_include_dirs}" MATCHES "${desired_include_dirs}")
+    message(SEND_ERROR "include default does not work")
+endif()
index 0f0e5d8..f43a7c6 100644 (file)
@@ -34,6 +34,7 @@ if (RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Visual Studio|Xcode|Watcom WMake
   run_cmake_target(genex CXX_interface2 LinkLibraries_CXX_interface2 --config Release)
   run_cmake_target(genex C_static LinkLibraries_C_static --config Release)
   run_cmake_target(genex CXX_static LinkLibraries_CXX_static --config Release)
+  run_cmake_target(genex C_static_CXX LinkLibraries_C_static_CXX --config Release)
 
   unset(RunCMake_TEST_OPTIONS)
   unset(RunCMake_TEST_OUTPUT_MERGE)
index a12caca..ee6811c 100644 (file)
@@ -1,7 +1,18 @@
 
-#if defined(_WIN32)
-__declspec(dllexport)
+#if !defined(BUILD_STATIC) && defined(_WIN32)
+#  define EXPORT_SYMBOL __declspec(dllexport)
+#else
+#  define EXPORT_SYMBOL
 #endif
-  void func_cxx()
+
+EXPORT_SYMBOL
+void func_cxx()
 {
 }
+
+extern "C" {
+EXPORT_SYMBOL
+void func_c_cxx()
+{
+}
+}
index f3fe955..22d3df7 100644 (file)
@@ -7,6 +7,8 @@ enable_language(CXX)
 add_library(shared_C SHARED func.c)
 add_library(shared_CXX SHARED func.cxx)
 
+add_library(static_cxx STATIC func.cxx)
+target_compile_definitions(static_cxx PRIVATE BUILD_STATIC)
 
 add_library(static1_C STATIC empty.c)
 target_link_libraries (static1_C INTERFACE $<$<LINK_LANGUAGE:C>:shared_C>)
@@ -70,3 +72,10 @@ add_executable(LinkLibraries_C_static main.c)
 target_link_libraries (LinkLibraries_C_static PRIVATE static3)
 add_executable(LinkLibraries_CXX_static main.cxx)
 target_link_libraries (LinkLibraries_CXX_static PRIVATE static3)
+
+# $<LINK_LANGUAGE:> change, by default, link language from C to CXX
+# but because LINKER_LANGUAGE property is set, keep C as link language
+add_executable(LinkLibraries_C_static_CXX main.c)
+target_compile_definitions (LinkLibraries_C_static_CXX PRIVATE C_USE_CXX)
+target_link_libraries (LinkLibraries_C_static_CXX PRIVATE $<$<LINK_LANGUAGE:C>:static_cxx>)
+set_property(TARGET LinkLibraries_C_static_CXX PROPERTY LINKER_LANGUAGE C)
index a908dea..689dbd7 100644 (file)
@@ -1,12 +1,20 @@
 
-#if defined(_WIN32)
+#if defined(C_USE_CXX)
+void func_c_cxx();
+#else
+#  if defined(_WIN32)
 __declspec(dllimport)
-#endif
+#  endif
   void func_c();
+#endif
 
 int main()
 {
+#if defined(C_USE_CXX)
+  func_c_cxx();
+#else
   func_c();
+#endif
 
   return 0;
 }
index 3689562..fa30eb4 100644 (file)
@@ -8,3 +8,5 @@ if (CMAKE_SYSTEM_NAME MATCHES "^(Linux|Darwin|Windows)$" AND
   run_cmake(LinkOptions)
   unset (RunCMake_TEST_OPTIONS)
 endif()
+
+run_cmake(WorkingDirArg)
diff --git a/Tests/RunCMake/try_run/WorkingDirArg.cmake b/Tests/RunCMake/try_run/WorkingDirArg.cmake
new file mode 100644 (file)
index 0000000..b583823
--- /dev/null
@@ -0,0 +1,9 @@
+try_run(RUN_RESULT COMPILE_RESULT
+  ${CMAKE_CURRENT_BINARY_DIR}/CMakeTmp ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+  RUN_OUTPUT_VARIABLE OUTPUT_VARIABLE
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeTmp/workdir
+  )
+
+if(RUN_RESULT)
+  message(SEND_ERROR "try run failed with result: ${RUN_RESULT}")
+endif()
index 5fe6655..3195fa0 100644 (file)
@@ -1,5 +1,4 @@
-^CMake Error at EndAlone.cmake:1 \(endwhile\):
-  endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE
-  structure.  Or its arguments did not match the opening WHILE command.
+^CMake Error at EndAlone\.cmake:[0-9]+ \(endwhile\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
index a8c043d..1634e3b 100644 (file)
@@ -1,5 +1,4 @@
-^CMake Error at EndAloneArgs.cmake:1 \(endwhile\):
-  endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE
-  structure.  Or its arguments did not match the opening WHILE command.
+^CMake Error at EndAloneArgs\.cmake:[0-9]+ \(endwhile\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
index 964792f..1e3be4d 100644 (file)
@@ -1,8 +1,4 @@
-^CMake Error in EndMissing.cmake:
-  A logical block opening on the line
-
-    .*/Tests/RunCMake/while/EndMissing.cmake:1 \(while\)
-
-  is not closed.
+^CMake Error at EndMissing\.cmake:[0-9]+ \(while\):
+  Flow control statements are not properly nested\.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)$
index 7ff0971..59e8ee3 100644 (file)
@@ -1,4 +1,11 @@
-^CMake Error at MissingArgument.cmake:1 \(while\):
+^CMake Error at MissingArgument\.cmake:[0-9]+ \(while\):
   while called with incorrect number of arguments
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)$
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at MissingArgument\.cmake:[0-9]+ \(endwhile\):
+  endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE
+  structure\.  Or its arguments did not match the opening WHILE command\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/Server/CMakeLists.txt b/Tests/Server/CMakeLists.txt
deleted file mode 100644 (file)
index 8321edb..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-cmake_minimum_required(VERSION 3.4)
-project(Server CXX)
-
-find_package(Python REQUIRED)
-
-macro(do_test bsname file type)
-  execute_process(COMMAND ${Python_EXECUTABLE}
-    -B # no .pyc files
-    "${CMAKE_SOURCE_DIR}/${type}-test.py"
-    "${CMAKE_COMMAND}"
-    "${CMAKE_SOURCE_DIR}/${file}"
-    "${CMAKE_SOURCE_DIR}"
-    "${CMAKE_BINARY_DIR}"
-    "${CMAKE_GENERATOR}"
-    RESULT_VARIABLE test_result
-    )
-
-  if (NOT test_result EQUAL 0)
-    message(SEND_ERROR "TEST FAILED: ${test_result}")
-  endif()
-endmacro()
-
-do_test("test_cache" "tc_cache.json" "server")
-do_test("test_handshake" "tc_handshake.json" "server")
-do_test("test_globalSettings" "tc_globalSettings.json" "server")
-do_test("test_buildsystem1" "tc_buildsystem1.json" "server")
-
-add_executable(Server empty.cpp)
diff --git a/Tests/Server/buildsystem1/CMakeLists.txt b/Tests/Server/buildsystem1/CMakeLists.txt
deleted file mode 100644 (file)
index d690472..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-cmake_minimum_required(VERSION 3.4)
-
-project(buildsystem2)
-
-set(var1 123)
-
-set(var2 345)
-
-add_executable(main main.cpp)
-
-add_executable(m_other main.cpp)
-
-add_library(foo foo.cpp)
-
-function(f1)
-endfunction()
-
-set(var3 345)
-
-add_library(someImportedLib UNKNOWN IMPORTED)
-
-add_subdirectory(subdir)
diff --git a/Tests/Server/buildsystem1/subdir/CMakeLists.txt b/Tests/Server/buildsystem1/subdir/CMakeLists.txt
deleted file mode 100644 (file)
index 9157312..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-set(bar4 something)
-
-set(bar5 more)
-
-add_executable(ooo empty.cpp)
diff --git a/Tests/Server/cmakelib.py b/Tests/Server/cmakelib.py
deleted file mode 100644 (file)
index 546ae4c..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-from __future__ import print_function
-import sys, subprocess, json, os, select, shutil, time, socket
-
-termwidth = 150
-
-print_communication = True
-
-def ordered(obj):
-  if isinstance(obj, dict):
-    return sorted((k, ordered(v)) for k, v in obj.items())
-  if isinstance(obj, list):
-    return sorted(ordered(x) for x in obj)
-  else:
-    return obj
-
-def col_print(title, array):
-  print()
-  print()
-  print(title)
-
-  indentwidth = 4
-  indent = " " * indentwidth
-
-  if not array:
-    print(indent + "<None>")
-    return
-
-  padwidth = 2
-
-  maxitemwidth = len(max(array, key=len))
-
-  numCols = max(1, int((termwidth - indentwidth + padwidth) / (maxitemwidth + padwidth)))
-
-  numRows = len(array) // numCols + 1
-
-  pad = " " * padwidth
-
-  for index in range(numRows):
-    print(indent + pad.join(item.ljust(maxitemwidth) for item in array[index::numRows]))
-
-filterPacket = lambda x: x
-
-STDIN = 0
-PIPE = 1
-
-communicationMethods = [STDIN]
-
-if hasattr(socket, 'AF_UNIX'):
-  communicationMethods.append(PIPE)
-
-def defaultExitWithError(proc):
-  data = ""
-  try:
-    while select.select([proc.outPipe], [], [], 3.)[0]:
-      data = data + proc.outPipe.read(1)
-    if len(data):
-      print("Rest of raw buffer from server:")
-      printServer(data)
-  except:
-    pass
-  proc.outPipe.close()
-  proc.inPipe.close()
-  proc.kill()
-  sys.exit(1)
-
-exitWithError = lambda proc: defaultExitWithError(proc)
-
-serverTag = "SERVER"
-
-def printServer(*args):
-    print(serverTag + ">", *args)
-    print()
-    sys.stdout.flush()
-
-def printClient(*args):
-    print("CLIENT>", *args)
-    print()
-    sys.stdout.flush()
-
-def waitForRawMessage(cmakeCommand):
-  stdoutdata = ""
-  payload = ""
-  while not cmakeCommand.poll():
-    stdoutdataLine = cmakeCommand.outPipe.readline()
-    if stdoutdataLine:
-      stdoutdata += stdoutdataLine.decode('utf-8')
-    else:
-      break
-    begin = stdoutdata.find('[== "CMake Server" ==[\n')
-    end = stdoutdata.find(']== "CMake Server" ==]')
-
-    if begin != -1 and end != -1:
-      begin += len('[== "CMake Server" ==[\n')
-      payload = stdoutdata[begin:end]
-      jsonPayload = json.loads(payload)
-      filteredPayload = filterPacket(jsonPayload)
-      if print_communication and filteredPayload:
-        printServer(filteredPayload)
-      if filteredPayload is not None or jsonPayload is None:
-          return jsonPayload
-      stdoutdata = stdoutdata[(end+len(']== "CMake Server" ==]')):]
-
-# Python2 has no problem writing the output of encodes directly,
-# but Python3 returns only 'int's for encode and so must be turned
-# into bytes. We use the existence of 'to_bytes' on an int to
-# determine which behavior is appropriate. It might be more clear
-# to do this in the code which uses the flag, but introducing
-# this lookup cost at every byte sent isn't ideal.
-has_to_bytes = "to_bytes" in dir(10)
-
-def writeRawData(cmakeCommand, content):
-  writeRawData.counter += 1
-  payload = """
-[== "CMake Server" ==[
-%s
-]== "CMake Server" ==]
-""" % content
-
-  rn = ( writeRawData.counter % 2 ) == 0
-
-  if rn:
-    payload = payload.replace('\n', '\r\n')
-
-  if print_communication:
-    printClient(content, "(Use \\r\\n:", rn, ")")
-
-  # To stress test how cmake deals with fragmentation in the
-  # communication channel, we send only one byte at a time.
-  # Certain communication methods / platforms might still buffer
-  # it all into one message since its so close together, but in
-  # general this will catch places where we assume full buffers
-  # come in all at once.
-  encoded_payload = payload.encode('utf-8')
-
-  # Python version 3+ can't write ints directly; but 'to_bytes'
-  # for int was only added in python 3.2. If this is a 3+ version
-  # of python without that conversion function; just write the whole
-  # thing out at once.
-  if sys.version_info[0] > 2 and not has_to_bytes:
-    cmakeCommand.write(encoded_payload)
-  else:
-    for c in encoded_payload:
-      if has_to_bytes:
-        c = c.to_bytes(1, byteorder='big')
-      cmakeCommand.write(c)
-
-writeRawData.counter = 0
-
-def writePayload(cmakeCommand, obj):
-  writeRawData(cmakeCommand, json.dumps(obj))
-
-def getPipeName():
-  return "/tmp/server-test-socket"
-
-def attachPipe(cmakeCommand, pipeName):
-  time.sleep(1)
-  sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-  sock.connect(pipeName)
-  global serverTag
-  serverTag = "SERVER(PIPE)"
-  cmakeCommand.outPipe = sock.makefile()
-  cmakeCommand.inPipe = sock
-  cmakeCommand.write = cmakeCommand.inPipe.sendall
-
-def writeAndFlush(pipe, val):
-  pipe.write(val)
-  pipe.flush()
-
-def initServerProc(cmakeCommand, comm):
-  if comm == PIPE:
-    pipeName = getPipeName()
-    cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", "--experimental", "--pipe=" + pipeName])
-    attachPipe(cmakeCommand, pipeName)
-  else:
-    cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", "--experimental", "--debug"],
-                                    stdin=subprocess.PIPE,
-                                    stdout=subprocess.PIPE)
-    cmakeCommand.outPipe = cmakeCommand.stdout
-    cmakeCommand.inPipe = cmakeCommand.stdin
-    cmakeCommand.write = lambda val: writeAndFlush(cmakeCommand.inPipe, val)
-
-  packet = waitForRawMessage(cmakeCommand)
-  if packet == None:
-    print("Not in server mode")
-    sys.exit(2)
-
-  if packet['type'] != 'hello':
-    print("No hello message")
-    sys.exit(3)
-
-  return cmakeCommand
-
-def exitProc(cmakeCommand):
-  # Tell the server to exit.
-  cmakeCommand.stdin.close()
-  cmakeCommand.stdout.close()
-
-  # Wait for the server to exit.
-  # If this version of python supports it, terminate the server after a timeout.
-  try:
-    cmakeCommand.wait(timeout=5)
-  except TypeError:
-    cmakeCommand.wait()
-  except:
-    cmakeCommand.terminate()
-    raise
-
-def waitForMessage(cmakeCommand, expected):
-  data = ordered(expected)
-  packet = ordered(waitForRawMessage(cmakeCommand))
-
-  if packet != data:
-    print ("Received unexpected message; test failed")
-    exitWithError(cmakeCommand)
-  return packet
-
-def waitForReply(cmakeCommand, originalType, cookie, skipProgress):
-  gotResult = False
-  while True:
-    packet = waitForRawMessage(cmakeCommand)
-    t = packet['type']
-    if packet['cookie'] != cookie or packet['inReplyTo'] != originalType:
-      print("cookie or inReplyTo mismatch")
-      sys.exit(4)
-    if t == 'message' or t == 'progress':
-      if skipProgress:
-        continue
-    if t == 'reply':
-        break
-    print("Unrecognized message", packet)
-    sys.exit(5)
-
-  return packet
-
-def waitForError(cmakeCommand, originalType, cookie, message):
-  packet = waitForRawMessage(cmakeCommand)
-  if packet['cookie'] != cookie or packet['type'] != 'error' or packet['inReplyTo'] != originalType or packet['errorMessage'] != message:
-    sys.exit(6)
-
-def waitForProgress(cmakeCommand, originalType, cookie, current, message):
-  packet = waitForRawMessage(cmakeCommand)
-  if packet['cookie'] != cookie or packet['type'] != 'progress' or packet['inReplyTo'] != originalType or packet['progressCurrent'] != current or packet['progressMessage'] != message:
-    sys.exit(7)
-
-def handshake(cmakeCommand, major, minor, source, build, generator, extraGenerator):
-  version = { 'major': major }
-  if minor >= 0:
-    version['minor'] = minor
-
-  writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version,
-    'cookie': 'TEST_HANDSHAKE', 'sourceDirectory': source, 'buildDirectory': build,
-    'generator': generator, 'extraGenerator': extraGenerator })
-  waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE', False)
-
-def validateGlobalSettings(cmakeCommand, cmakeCommandPath, data):
-  packet = waitForReply(cmakeCommand, 'globalSettings', '', False)
-
-  capabilities = packet['capabilities']
-
-  # validate version:
-  cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--version" ], universal_newlines=True)
-  cmakeVersion = cmakeoutput.splitlines()[0][14:]
-
-  version = capabilities['version']
-  versionString = version['string']
-  vs = str(version['major']) + '.' + str(version['minor']) + '.' + str(version['patch'])
-  if (versionString != vs and not versionString.startswith(vs + '-')):
-    sys.exit(8)
-  if (versionString != cmakeVersion):
-    sys.exit(9)
-
-  # validate generators:
-  generatorObjects = capabilities['generators']
-
-  cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--help" ], universal_newlines=True)
-  index = cmakeoutput.index('\nGenerators\n\n')
-  cmakeGenerators = []
-  for line in cmakeoutput[index + 12:].splitlines():
-    if not line:
-      continue
-    if line[0] == '*': # default generator marker
-      line = ' ' + line[1:]
-    if not line.startswith('  '):
-      continue
-    if line.startswith('    '):
-      continue
-    equalPos = line.find('=')
-    tmp = ''
-    if (equalPos > 0):
-      tmp = line[2:equalPos].strip()
-    else:
-      tmp = line.strip()
-    if tmp.endswith(" [arch]"):
-      tmp = tmp[0:len(tmp) - 7]
-    if (len(tmp) > 0) and (" - " not in tmp):
-      cmakeGenerators.append(tmp)
-
-  generators = []
-  for genObj in generatorObjects:
-    generators.append(genObj['name'])
-
-  generators.sort()
-  cmakeGenerators.sort()
-
-  for gen in cmakeGenerators:
-    if (not gen in generators):
-        sys.exit(10)
-
-  gen = packet['generator']
-  if (gen != '' and not (gen in generators)):
-    sys.exit(11)
-
-  for i in data:
-    print("Validating", i)
-    if (packet[i] != data[i]):
-      sys.exit(12)
-
-def validateCache(cmakeCommand, data):
-  packet = waitForReply(cmakeCommand, 'cache', '', False)
-
-  cache = packet['cache']
-
-  if (data['isEmpty']):
-    if (cache != []):
-      print('Expected empty cache, but got data.\n')
-      sys.exit(1)
-    return;
-
-  if (cache == []):
-    print('Expected cache contents, but got none.\n')
-    sys.exit(1)
-
-  hadHomeDir = False
-  for value in cache:
-    if (value['key'] == 'CMAKE_HOME_DIRECTORY'):
-      hadHomeDir = True
-
-  if (not hadHomeDir):
-    print('No CMAKE_HOME_DIRECTORY found in cache.')
-    sys.exit(1)
-
-def handleBasicMessage(proc, obj, debug):
-  if 'sendRaw' in obj:
-    data = obj['sendRaw']
-    if debug: print("Sending raw:", data)
-    writeRawData(proc, data)
-    return True
-  elif 'send' in obj:
-    data = obj['send']
-    if debug: print("Sending:", json.dumps(data))
-    writePayload(proc, data)
-    return True
-  elif 'recv' in obj:
-    data = obj['recv']
-    if debug: print("Waiting for:", json.dumps(data))
-    waitForMessage(proc, data)
-    return True
-  elif 'message' in obj:
-    print("MESSAGE:", obj["message"])
-    sys.stdout.flush()
-    return True
-  return False
-
-def shutdownProc(proc):
-  # Tell the server to exit.
-  proc.inPipe.close()
-  proc.outPipe.close()
-
-  # Wait for the server to exit.
-  # If this version of python supports it, terminate the server after a timeout.
-  try:
-    proc.wait(timeout=5)
-  except TypeError:
-    proc.wait()
-  except:
-    proc.terminate()
-    raise
-
-  print('cmake-server exited: %d' % proc.returncode)
-  sys.exit(proc.returncode)
diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py
deleted file mode 100644 (file)
index 701c6e9..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-from __future__ import print_function
-import sys, cmakelib, json, os, shutil
-
-debug = True
-
-cmakeCommand = sys.argv[1]
-testFile = sys.argv[2]
-sourceDir = sys.argv[3]
-buildDir = sys.argv[4] + "/" + os.path.splitext(os.path.basename(testFile))[0]
-cmakeGenerator = sys.argv[5]
-
-print("Server Test:", testFile,
-      "\n-- SourceDir:", sourceDir,
-      "\n-- BuildDir:", buildDir,
-      "\n-- Generator:", cmakeGenerator)
-
-if os.path.exists(buildDir):
-    shutil.rmtree(buildDir)
-
-cmakelib.filterBase = sourceDir
-
-with open(testFile) as f:
-    testData = json.loads(f.read())
-
-for communicationMethod in cmakelib.communicationMethods:
-    proc = cmakelib.initServerProc(cmakeCommand, communicationMethod)
-    if proc is None:
-        continue
-
-    for obj in testData:
-        if cmakelib.handleBasicMessage(proc, obj, debug):
-            pass
-        elif 'reply' in obj:
-            data = obj['reply']
-            if debug: print("Waiting for reply:", json.dumps(data))
-            originalType = ""
-            cookie = ""
-            skipProgress = False;
-            if 'cookie' in data: cookie = data['cookie']
-            if 'type' in data: originalType = data['type']
-            if 'skipProgress' in data: skipProgress = data['skipProgress']
-            cmakelib.waitForReply(proc, originalType, cookie, skipProgress)
-        elif 'error' in obj:
-            data = obj['error']
-            if debug: print("Waiting for error:", json.dumps(data))
-            originalType = ""
-            cookie = ""
-            message = ""
-            if 'cookie' in data: cookie = data['cookie']
-            if 'type' in data: originalType = data['type']
-            if 'message' in data: message = data['message']
-            cmakelib.waitForError(proc, originalType, cookie, message)
-        elif 'progress' in obj:
-            data = obj['progress']
-            if debug: print("Waiting for progress:", json.dumps(data))
-            originalType = ''
-            cookie = ""
-            current = 0
-            message = ""
-            if 'cookie' in data: cookie = data['cookie']
-            if 'type' in data: originalType = data['type']
-            if 'current' in data: current = data['current']
-            if 'message' in data: message = data['message']
-            cmakelib.waitForProgress(proc, originalType, cookie, current, message)
-        elif 'handshake' in obj:
-            data = obj['handshake']
-            if debug: print("Doing handshake:", json.dumps(data))
-            major = -1
-            minor = -1
-            generator = cmakeGenerator
-            extraGenerator = ''
-            sourceDirectory = sourceDir
-            buildDirectory = buildDir
-            if 'major' in data: major = data['major']
-            if 'minor' in data: minor = data['minor']
-            if 'buildDirectory' in data: buildDirectory = data['buildDirectory']
-            if 'sourceDirectory' in data: sourceDirectory = data['sourceDirectory']
-            if 'generator' in data: generator = data['generator']
-            if 'extraGenerator' in data: extraGenerator = data['extraGenerator']
-
-            if not os.path.isabs(buildDirectory):
-                buildDirectory = buildDir + "/" + buildDirectory
-            if sourceDirectory != '' and not os.path.isabs(sourceDirectory):
-                sourceDirectory = sourceDir + "/" + sourceDirectory
-            cmakelib.handshake(proc, major, minor, sourceDirectory, buildDirectory,
-                               generator, extraGenerator)
-        elif 'validateGlobalSettings' in obj:
-            data = obj['validateGlobalSettings']
-            if not 'buildDirectory' in data: data['buildDirectory'] = buildDir
-            if not 'sourceDirectory' in data: data['sourceDirectory'] = sourceDir
-            if not 'generator' in data: data['generator'] = cmakeGenerator
-            if not 'extraGenerator' in data: data['extraGenerator'] = ''
-            cmakelib.validateGlobalSettings(proc, cmakeCommand, data)
-        elif 'validateCache' in obj:
-            data = obj['validateCache']
-            if not 'isEmpty' in data: data['isEmpty'] = false
-            cmakelib.validateCache(proc, data)
-        elif 'reconnect' in obj:
-            cmakelib.exitProc(proc)
-            proc = cmakelib.initServerProc(cmakeCommand, communicationMethod)
-        else:
-            print("Unknown command:", json.dumps(obj))
-            sys.exit(2)
-    cmakelib.shutdownProc(proc)
-    print("Completed")
diff --git a/Tests/Server/tc_buildsystem1.json b/Tests/Server/tc_buildsystem1.json
deleted file mode 100644 (file)
index 08831b7..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-[
-{ "message": "Testing globalSettings" },
-
-{ "handshake": {"major": 1, "sourceDirectory":"buildsystem1","buildDirectory":"buildsystem1"} },
-
-{ "message": "Configure:" },
-{ "send": { "type": "configure", "cookie":"CONFIG" } },
-{ "reply": { "type": "configure", "cookie":"CONFIG", "skipProgress":true } },
-
-{ "message": "Compute:" },
-{ "send": { "type": "compute", "cookie":"COMPUTE" } },
-{ "reply": { "type": "compute", "cookie":"COMPUTE", "skipProgress":true } },
-
-{ "message": "Codemodel:" },
-{ "send": { "type": "codemodel", "cookie":"CODEMODEL" } },
-{ "reply": { "type": "codemodel", "cookie":"CODEMODEL" } },
-
-{ "message": "CMake Inputs:"},
-{ "send": { "type": "cmakeInputs", "cookie":"INPUTS" } },
-{ "reply": { "type": "cmakeInputs", "cookie":"INPUTS" } },
-
-{ "message": "Cache:"},
-{ "send": { "type": "cache", "cookie":"CACHE" } },
-{ "reply": { "type": "cache", "cookie":"CACHE" } },
-
-{ "message": "Everything ok." }
-]
diff --git a/Tests/Server/tc_cache.json b/Tests/Server/tc_cache.json
deleted file mode 100644 (file)
index 74af6d9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-[
-{ "message": "Testing cache" },
-
-{ "message": "Cache after first handshake is empty:" },
-{ "handshake": {"major": 1, "sourceDirectory": "buildsystem1", "buildDirectory": "buildsystem1"} },
-{ "send": { "type": "cache" } },
-{ "validateCache": { "isEmpty": true } },
-
-{ "message": "Cache after configure is populated:" },
-{ "send": { "type": "configure" } },
-{ "reply": { "type": "configure", "skipProgress":true } },
-{ "send": { "type": "cache" } },
-{ "validateCache": { "isEmpty": false } },
-
-{ "message": "Handshake for existing cache requires buildDirectory only:" },
-{ "reconnect": {} },
-{ "handshake": {"major": 1, "sourceDirectory": "", "buildDirectory": "buildsystem1"} },
-
-{ "message": "Cache after reconnect is again populated:" },
-{ "send": { "type": "cache" } },
-{ "validateCache": { "isEmpty": false } },
-
-{ "message": "Everything ok." }
-]
diff --git a/Tests/Server/tc_globalSettings.json b/Tests/Server/tc_globalSettings.json
deleted file mode 100644 (file)
index d72fb41..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-[
-{ "message": "Testing globalSettings" },
-
-{ "handshake": {"major": 1} },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-
-
-{ "message": "Change settings:" },
-
-{ "send": { "type": "setGlobalSettings", "warnUnused": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnused": false } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "debugOutput": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": true, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "debugOutput": false } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "warnUninitialized": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": true, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "warnUninitialized": false } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "traceExpand": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": true, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "traceExpand": false } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-
-
-{ "send": { "type": "setGlobalSettings", "trace": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": true, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "trace": false } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnusedCli": false } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": false, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnusedCli": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "checkSystemVars": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": true } },
-
-{ "send": { "type": "setGlobalSettings", "checkSystemVars": false } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
-
-{ "message": "Ignore unknown/readonly" },
-
-{ "send": { "type": "setGlobalSettings", "unknownKey": "unknownValue", "extraGenerator": "XXX", "generator": "YYY", "sourceDirectory": "/tmp/source", "buildDirectory": "/tmp/build" } },
-{ "reply": { "type": "setGlobalSettings" } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
-
-{ "message": "Error paths:" },
-
-{ "send": { "type": "setGlobalSettings", "debugOutput": true, "warnUnused": 1 } },
-{ "error": { "type": "setGlobalSettings", "message": "\"warnUnused\" must be unset or a bool value." } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": 1 } },
-{ "error": { "type": "setGlobalSettings", "message": "\"debugOutput\" must be unset or a bool value." } },
-
-{ "send": { "type": "setGlobalSettings", "warnUninitialized": 1, "warnUnused": true, "debugOutput": true } },
-{ "error": { "type": "setGlobalSettings", "message": "\"warnUninitialized\" must be unset or a bool value." } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "traceExpand": 1 } },
-{ "error": { "type": "setGlobalSettings", "message": "\"traceExpand\" must be unset or a bool value." } },
-
-{ "send": { "type": "setGlobalSettings", "debugOutput": true, "trace": 1, "warnUnused": true } },
-{ "error": { "type": "setGlobalSettings", "message": "\"trace\" must be unset or a bool value." } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "warnUnusedCli": 1.0 } },
-{ "error": { "type": "setGlobalSettings", "message": "\"warnUnusedCli\" must be unset or a bool value." } },
-
-{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "checkSystemVars": "some string" } },
-{ "error": { "type": "setGlobalSettings", "message": "\"checkSystemVars\" must be unset or a bool value." } },
-
-{ "send": { "type": "globalSettings"} },
-{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
-
-{ "message": "Everything ok." }
-]
diff --git a/Tests/Server/tc_handshake.json b/Tests/Server/tc_handshake.json
deleted file mode 100644 (file)
index 4bb7fa7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-[
-{ "message": "Testing basic message handling:" },
-
-{ "sendRaw": "Sometext"},
-{ "recv": {"cookie":"","errorMessage":"Failed to parse JSON input.","inReplyTo":"","type":"error"} },
-
-{ "message": "Testing invalid json input"},
-{ "send": { "test": "sometext" } },
-{ "recv": {"cookie":"","errorMessage":"No type given in request.","inReplyTo":"","type":"error"} },
-
-{ "send": {"test": "sometext","cookie":"monster"} },
-{ "recv": {"cookie":"monster","errorMessage":"No type given in request.","inReplyTo":"","type":"error"} },
-
-{ "message": "Testing commands before handshake" },
-{ "send": {"type": "cache","cookie":"monster"} },
-{ "recv": {"cookie":"monster","errorMessage":"Waiting for type \"handshake\".","inReplyTo":"cache","type":"error"} },
-
-{ "message": "Testing handshake" },
-{ "send": {"type": "sometype","cookie":"monster2"} },
-{ "recv": {"cookie":"monster2","errorMessage":"Waiting for type \"handshake\".","inReplyTo":"sometype","type":"error"} },
-
-{ "send": {"type": "handshake"} },
-{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" is required for \"handshake\".","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","foo":"bar"} },
-{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" is required for \"handshake\".","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":"bar"} },
-{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" must be a JSON object.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":{}} },
-{ "recv": {"cookie":"","errorMessage":"\"major\" must be set and an integer.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":{"major":"foo"}} },
-{ "recv": {"cookie":"","errorMessage":"\"major\" must be set and an integer.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":{"major":1, "minor":"foo"}} },
-{ "recv": {"cookie":"","errorMessage":"\"minor\" must be unset or an integer.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":{"major":-1, "minor":-1}} },
-{ "recv": {"cookie":"","errorMessage":"\"major\" must be >= 0.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":{"major":10, "minor":-1}} },
-{ "recv": {"cookie":"","errorMessage":"\"minor\" must be >= 0 when set.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":{"major":10000}} },
-{ "recv": {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"type": "handshake","protocolVersion":{"major":1, "minor":10000}} },
-{ "recv": {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} },
-
-{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1}} },
-{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"buildDirectory\" is missing."} },
-
-{ "message": "Testing protocol version specific options (1.0):" },
-{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":"/tmp/src"} },
-{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"buildDirectory\" is missing."} },
-
-{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":"/tmp/src","buildDirectory":"/tmp/build"} },
-{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"sourceDirectory\" is not a directory."} },
-
-{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","extraGenerator":"CodeBlocks"} },
-{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"generator\" is unset but required."} },
-
-{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"XXXX","extraGenerator":"CodeBlocks"} },
-{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: Generator \"XXXX\" not supported."} },
-
-{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"Ninja","extraGenerator":"XXXX"} },
-{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: The combination of generator \"Ninja\" and extra generator \"XXXX\" is not supported."} },
-
-{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"Ninja","extraGenerator":"CodeBlocks"} },
-{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"} },
-
-{ "message": "Everything ok." }
-]
index 9de4fc6..3eb9185 100644 (file)
@@ -15,3 +15,11 @@ if(CMAKE_GENERATOR MATCHES "^Visual Studio" AND "x${CMAKE_C_COMPILER_ID}" STREQU
   add_library(stay stay_c.c stay_cxx.cxx)
   set_property(TARGET stay PROPERTY COMPILE_OPTIONS "-TP")
 endif()
+
+if((CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang|MSVC|Borland|Embarcadero|Intel|TI|XL)"))
+  cmake_policy(SET CMP0119 NEW)
+  add_library(zoom zoom.zzz)
+  set_source_files_properties(zoom.zzz PROPERTIES LANGUAGE CXX)
+  target_link_libraries(SetLang zoom)
+  target_compile_definitions(SetLang PRIVATE WITH_ZOOM)
+endif()
index b934356..515e8c2 100644 (file)
@@ -1,10 +1,22 @@
 #include <stdio.h>
 
 int foo();
+
+#ifdef WITH_ZOOM
+int zoom();
+#endif
+
 class A
 {
 public:
-  A() { this->i = foo(); }
+  A()
+  {
+    this->i = foo();
+#ifdef WITH_ZOOM
+    i += zoom();
+    i -= zoom();
+#endif
+  }
   int i;
 };
 
diff --git a/Tests/SetLang/zoom.zzz b/Tests/SetLang/zoom.zzz
new file mode 100644 (file)
index 0000000..a0c8899
--- /dev/null
@@ -0,0 +1,7 @@
+int zoom()
+{
+  int r = 10;
+  r++;
+  int ret = r + 10;
+  return ret;
+}
index cf02de7..671d529 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1...3.13)
+cmake_minimum_required(VERSION 3.1...3.20)
 
 project(TestBasicPerl CXX)
 
index 8bbd1cb..a1163a2 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1...3.13)
+cmake_minimum_required(VERSION 3.1...3.20)
 
 project(TestBasicPython CXX)
 
index e150223..d08c59c 100644 (file)
@@ -1,3 +1,5 @@
+find_package(SWIG QUIET)
+
 add_test(NAME UseSWIG.LegacyPython COMMAND
   ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
   --build-and-test
@@ -64,6 +66,28 @@ add_test(NAME UseSWIG.BasicPerl COMMAND
   --build-options ${build_options}
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
+if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2")
+  add_test(NAME UseSWIG.Depfile.BasicPython COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPython"
+    "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPython.Depfile"
+    ${build_generator_args}
+    --build-project TestBasicPython
+    --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME UseSWIG.Depfile.BasicPerl COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPerl"
+    "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPerl.Depfile"
+    ${build_generator_args}
+    --build-project TestBasicPerl
+    --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+endif()
 
 if (CMake_TEST_UseSWIG_Fortran)
   check_language(Fortran)
index f68e38e..abd0628 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(FortranHello Fortran C)
 
 # add a function to test for -lsunquad on sunpro sun systems.
@@ -33,7 +33,7 @@ FortranCInterface_HEADER(HelloWorldFCMangle.h
                          SYMBOLS hello world)
 add_library(hello SHARED hello.f)
 add_library(world SHARED world.f)
-target_link_libraries(hello world)
+target_link_libraries(hello PRIVATE world)
 if(CMAKE_Fortran_COMPILER_ID MATCHES SunPro)
   target_link_libraries(hello PRIVATE fsu)
   if(CMAKE_Fortran_PLATFORM_ID MATCHES SunOS)
index 3ff7c27..342b8fb 100644 (file)
@@ -12,7 +12,7 @@ endif()
 message(STATUS "CMAKE_BUILDNAME='${CMAKE_BUILDNAME}'")
 message(STATUS "THIS_TESTNAME='${THIS_TESTNAME}'")
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(${THIS_TESTNAME})
 
 include(ExternalProject)
index e745fdd..7e838b4 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
 project(VSMidl)
 
 include_directories("${CMAKE_CURRENT_BINARY_DIR}/\$(IntDir)")
index 56e4c1d..edd4330 100644 (file)
@@ -119,13 +119,13 @@ set_property(SOURCE ${RELEASE_CONTENT_FILES} PROPERTY
 set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_TYPE Pixel)
 set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_ENTRYPOINT mainPS)
 set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_MODEL 4.0_level_9_3)
-set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_FLAGS "/DFLAGS_ADDED")
+set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_FLAGS $<1:/DFLAGS_ADDED>)
 set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_OUTPUT_HEADER_FILE "$(OutDir)%(Filename).h")
 
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_TYPE Vertex)
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_ENTRYPOINT mainVS)
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_MODEL 4.0_level_9_3)
-set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_FLAGS "/DFLAGS_ADDED")
+set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_FLAGS $<1:/DFLAGS_ADDED>)
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_OUTPUT_HEADER_FILE "$(OutDir)%(Filename).h")
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SETTINGS "$<$<CONFIG:DEBUG>:SourceProperty1=SourceProperty1Value>")
 
index 5bf13f3..a880f7a 100644 (file)
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeDeveloperReference_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.1...3.15 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.1...3.18 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
index 6892683..5d8e318 100644 (file)
@@ -6,17 +6,6 @@ on ``cmake.org``.  See also the `CMake Source Code Guide`_.
 
 .. _`CMake Source Code Guide`: ../../Help/dev/source.rst
 
-File Table
-----------
-
-The set of package files distributed on ``cmake.org`` varies by CMake version.
-Clients providing automatic download functionality may query the set of
-package files available using a special file that lists them:
-
-* `File Table v1`_ Documentation
-
-.. _`File Table v1`: files-v1.rst
-
 Docker
 ------
 
@@ -50,7 +39,7 @@ Each ``<os>/<arch>/`` directory contains the following:
         -f cmake-src/Utilities/Release/linux/x86_64/Dockerfile cmake-src
     $ docker container create --name cmake-build cmake:build
     $ docker cp cmake-build:/out .
-    $ ls out/cmake-*-Linux-x86_64.*
+    $ ls out/cmake-*-linux-x86_64.*
 
   On Windows, the ``win/x86`` specifications support both the ``x86_64``
   and ``i386`` architectures selected via ``--build-arg ARCH=...``.
@@ -69,8 +58,8 @@ Each ``<os>/<arch>/`` directory contains the following:
 
     FROM cmake:test-base
     COPY cmake-src /opt/cmake/src/cmake
-    ADD out/cmake-<ver>-Linux-x86_64.tar.gz /opt/
-    ENV PATH=/opt/cmake-<ver>-Linux-x86_64/bin:$PATH
+    ADD out/cmake-<ver>-linux-x86_64.tar.gz /opt/
+    ENV PATH=/opt/cmake-<ver>-linux-x86_64/bin:$PATH
 
   Build the test image and run it to drive testing:
 
diff --git a/Utilities/Release/files-sign.bash b/Utilities/Release/files-sign.bash
deleted file mode 100755 (executable)
index 414859d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-gpg --armor --detach-sign cmake-*-SHA-256.txt
diff --git a/Utilities/Release/files-v1.json.in b/Utilities/Release/files-v1.json.in
deleted file mode 100644 (file)
index 6bafa69..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-{
-  "version": {
-    "major": @version_major@,
-    "minor": @version_minor@,
-    "patch": @version_patch@,
-    @maybe_version_suffix@
-    "string": "@version@"
-  },
-  "files": [
-    {
-      "os": ["linux", "Linux"],
-      "architecture": ["aarch64"],
-      "class": "installer",
-      "name": "cmake-@version@-Linux-aarch64.sh"
-    },
-    {
-      "os": ["linux", "Linux"],
-      "architecture": ["aarch64"],
-      "class": "archive",
-      "name": "cmake-@version@-Linux-aarch64.tar.gz"
-    },
-    {
-      "os": ["linux", "Linux"],
-      "architecture": ["x86_64"],
-      "class": "installer",
-      "name": "cmake-@version@-Linux-x86_64.sh"
-    },
-    {
-      "os": ["linux", "Linux"],
-      "architecture": ["x86_64"],
-      "class": "archive",
-      "name": "cmake-@version@-Linux-x86_64.tar.gz"
-    },
-    {
-      "os": ["macos", "macOS"],
-      "architecture": ["arm64", "x86_64"],
-      "class": "volume",
-      "name": "cmake-@version@-macos-universal.dmg",
-      "macOSmin": "10.13"
-    },
-    {
-      "os": ["macos", "macOS"],
-      "architecture": ["arm64", "x86_64"],
-      "class": "archive",
-      "name": "cmake-@version@-macos-universal.tar.gz",
-      "macOSmin": "10.13"
-    },
-    {
-      "os": ["macos10.10", "macOS10.10"],
-      "architecture": ["arm64", "x86_64"],
-      "class": "volume",
-      "name": "cmake-@version@-macos10.10-universal.dmg",
-      "macOSmin": "10.10"
-    },
-    {
-      "os": ["macos10.10", "macOS10.10"],
-      "architecture": ["arm64", "x86_64"],
-      "class": "archive",
-      "name": "cmake-@version@-macos10.10-universal.tar.gz",
-      "macOSmin": "10.10"
-    },
-    {
-      "os": ["windows", "Windows"],
-      "architecture": ["i386"],
-      "class": "installer",
-      "name": "cmake-@version@-win32-x86.msi"
-    },
-    {
-      "os": ["windows", "Windows"],
-      "architecture": ["i386"],
-      "class": "archive",
-      "name": "cmake-@version@-win32-x86.zip"
-    },
-    {
-      "os": ["windows", "Windows"],
-      "architecture": ["x86_64"],
-      "class": "installer",
-      "name": "cmake-@version@-win64-x64.msi"
-    },
-    {
-      "os": ["windows", "Windows"],
-      "architecture": ["x86_64"],
-      "class": "archive",
-      "name": "cmake-@version@-win64-x64.zip"
-    },
-    {
-      "os": ["source"],
-      "architecture": [],
-      "class": "archive",
-      "name": "cmake-@version@.tar.gz"
-    },
-    {
-      "os": ["source"],
-      "architecture": [],
-      "class": "archive",
-      "name": "cmake-@version@.zip"
-    }
-  ],
-  "hashFiles": [
-    {
-      "algorithm": ["sha256", "SHA-256"],
-      "name": "cmake-@version@-SHA-256.txt",
-      "signature": ["cmake-@version@-SHA-256.txt.asc"]
-    }
-  ]
-}
diff --git a/Utilities/Release/files-v1.rst b/Utilities/Release/files-v1.rst
deleted file mode 100644 (file)
index 3b916d4..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-File Table v1
-*************
-
-The set of package files distributed on ``cmake.org`` varies by CMake version.
-One file, named ``cmake-<ver>-files-v1.json``, contains a table of the package
-files available for a given version.  Clients may use this to find other files.
-
-Format
-------
-
-The format is a JSON object:
-
-.. code-block:: json
-
-  {
-    "version": {
-      "major": 3, "minor": 18, "patch": 6,
-      "string": "3.18.6"
-    },
-    "files": [
-      {
-        "os": ["...", "..."],
-        "architecture": ["...", "..."],
-        "class": "...",
-        "name": "..."
-      }
-    ],
-    "hashFiles": [
-      {
-        "algorithm": ["...", "..."],
-        "name": "cmake-<version>-<algo>.txt",
-        "signature": ["cmake-<version>-<algo>.txt.asc"]
-      }
-    ]
-  }
-
-The members are:
-
-``version``
-  A JSON object specifying the version of CMake with members:
-
-  ``major``, ``minor``, ``patch``
-    Integer values specifying the major, minor, and patch version components.
-
-  ``suffix``
-    A string specifying the version suffix, if any, e.g. ``rc1``.
-
-  ``string``
-    A string specifying the full version in the format
-    ``<major>.<minor>.<patch>[-<suffix>]``.
-
-``files``
-  A JSON array of entries corresponding to available package files.
-  Each entry is a JSON object containing members:
-
-  ``os``
-    A JSON array of strings naming the operating system for which the
-    package file is built, possibly using multiple alternative spellings.
-    Possible names include:
-
-    ``source``
-      Source packages.
-
-    ``Linux``, ``linux``
-      Linux packages.
-
-    ``macOS``, ``macos``
-      macOS packages.
-
-    ``Windows``, ``windows``
-      Windows packages.
-
-  ``architecture``
-    A JSON array of strings naming the architecture(s) for which the
-    package file is built, possibly using multiple alternative spellings.
-    Source packages have an empty list of architectures (``[]``).
-    Binary packages have a non-empty list of architectures, with at least
-    one name matching the output of ``uname -m`` on corresponding hosts.
-    On Windows, architecture names include ``x86_64`` and ``i386``.
-    On macOS, universal binary packages list all architectures,
-    e.g. ``["arm64","x86_64"]``.
-
-  ``class``
-    A JSON string naming the class of package.  The value is one of:
-
-    ``archive``
-      A tarball or zip archive.
-      The extension, such as ``.tar.gz`` or ``.zip``, indicates the format.
-      The rest of the file name matches the top-level directory in the archive.
-
-    ``installer``
-      An interactive installer.
-
-    ``volume``
-      A disk image (``.dmg`` on macOS).
-
-  ``name``
-    A JSON string specifying the name of the package file.
-
-  ``macOSmin``
-    Optional member that is present on package files for macOS.
-    The value is a JSON string specifying the minimum version of macOS
-    required to run the binary, e.g. ``"10.13"``.
-
-``hashFiles``
-  A JSON array of entries corresponding to files containing cryptographic
-  hashes of the package file contents.  Each entry is a JSON object
-  containing members:
-
-  ``algorithm``
-    A JSON array of strings naming a cryptographic hash algorithm, possibly
-    using multiple alternative spellings, e.g. ``["sha256", "SHA-256"]``.
-
-  ``name``
-    A JSON string specifying the name of the file containing hashes,
-    e.g. ``"cmake-<version>-SHA-256.txt"``.
-
-  ``signature``
-    A JSON array of strings naming files containing a cryptographic
-    signature of the hash file specified by ``name``, e.g.
-    ``["cmake-<version>-SHA-256.txt.asc"]``.
-
-The table and hash files are generated by `files.bash`_ from
-the `files-v1.json.in`_ template and the package files themselves.
-
-.. _`files.bash`: files.bash
-.. _`files-v1.json.in`: files-v1.json.in
-
-Queries
--------
-
-Clients may download the `File Table v1`_ file ``cmake-<ver>-files-v1.json``
-and query it to get the name(s) of specific package files adjacent to it.
-Make queries as specific as possible in order to account for additional
-alternative binaries in future CMake versions.
-
-For example, one may use ``jq`` queries:
-
-* To select a Windows binary archive supporting ``x86_64`` hosts::
-
-    .files[] | select((.os[] | . == "windows") and
-                      (.architecture[] | . == "x86_64") and
-                      (.class == "archive")) | .name
-
-* To select a Linux binary archive supporting ``aarch64`` hosts::
-
-    .files[] | select((.os[] | . == "linux") and
-                      (.architecture[] | . == "aarch64") and
-                      (.class == "archive")) | .name
-
-* To select a macOS binary archive supporting ``arm64`` hosts::
-
-    .files[] | select((.os[] | . == "macos") and
-                      (.architecture[] | . == "arm64") and
-                      (.class == "archive")) | .name
-
-* To select a macOS binary archive supporting macOS 10.12 on ``x86_64`` hosts::
-
-    .files[] | select((.os[] | contains("macOS")) and
-                      (.architecture[] | . == "x86_64") and
-                      ([.macOSmin] | inside(["10.10", "10.11", "10.12"]))
-                      ) | .name
-
-* To select a SHA-256 hash file::
-
-    .hashFiles[] | select(.algorithm[] | . == "SHA-256") | .name
diff --git a/Utilities/Release/files.bash b/Utilities/Release/files.bash
deleted file mode 100755 (executable)
index 28ca8f1..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-usage='usage: files.bash [<options>] [--]
-
-Options:
-
-    --version <ver>            CMake <major>.<minor> version number to push.
-                               Defaults to version of source tree.
-'
-
-die() {
-    echo "$@" 1>&2; exit 1
-}
-
-readonly cmake_source_dir="${BASH_SOURCE%/*}/../.."
-
-cmake_version_component()
-{
-  sed -n "
-/^set(CMake_VERSION_${1}/ {s/set(CMake_VERSION_${1} *\([0-9]*\))/\1/;p;}
-" "${cmake_source_dir}/Source/CMakeVersion.cmake"
-}
-
-
-version=''
-while test "$#" != 0; do
-    case "$1" in
-    --version) shift; version="$1" ;;
-    --) shift ; break ;;
-    -*) die "$usage" ;;
-    *) break ;;
-    esac
-    shift
-done
-test "$#" = 0 || die "$usage"
-
-if test -z "$version"; then
-    cmake_version_major="$(cmake_version_component MAJOR)"
-    cmake_version_minor="$(cmake_version_component MINOR)"
-    cmake_version_patch="$(cmake_version_component PATCH)"
-    cmake_version_rc="$(cmake_version_component RC)"
-    version="${cmake_version_major}.${cmake_version_minor}.${cmake_version_patch}"
-    if test -n "$cmake_version_rc"; then
-      version="$version-rc$cmake_version_rc"
-    fi
-fi
-readonly version
-
-IFS='.-' read version_major version_minor version_patch version_suffix <<< "$version"
-readonly version_major
-readonly version_minor
-readonly version_patch
-readonly version_suffix
-
-if test -n "$version_suffix"; then
-  maybe_version_suffix='"suffix": "'"$version_suffix"'",'
-else
-  maybe_version_suffix=''
-fi
-readonly maybe_version_suffix
-
-readonly files_v1_in="${BASH_SOURCE%/*}/files-v1.json.in"
-sed "
-  s/@version@/$version/g
-  s/@version_major@/$version_major/g
-  s/@version_minor@/$version_minor/g
-  s/@version_patch@/$version_patch/g
-  s/@maybe_version_suffix@/$maybe_version_suffix/g
-" "$files_v1_in" \
-  | jq . \
-  > "cmake-$version-files-v1.json"
-
-readonly algos='
-  256
-'
-for algo in $algos; do
-  shasum -a $algo \
-    "cmake-$version-files-v1.json" \
-    $(jq -r '.files[].name' "cmake-$version-files-v1.json") \
-  | LC_ALL=C sort -k 2 \
-  > "cmake-$version-SHA-$algo.txt"
-done
index 4077b79..9abae2a 100644 (file)
@@ -5,7 +5,7 @@
 # Build using the CMake source directory as the build context.
 # The resulting image will have an '/out' directory containing the package.
 
-# Keep this in sync with the `.gitlab-ci.yml` `release_linux` image.
+# Keep this in sync with the `.gitlab/os-linux.yml` `.linux_release_aarch64` image.
 ARG FROM_IMAGE_NAME=kitware/cmake:build-linux-aarch64-deps-2020-12-21
 ARG FROM_IMAGE_DIGEST=@sha256:0bd7dfe4e45593b04e39cd21e44011034610cfd376900558c5ef959bb1af15af
 ARG FROM_IMAGE=$FROM_IMAGE_NAME$FROM_IMAGE_DIGEST
@@ -31,5 +31,5 @@ RUN : \
  && bin/cpack -G STGZ \
  && set +x \
  && mkdir /out \
- && mv cmake-*-Linux-aarch64.* /out \
+ && mv cmake-*-linux-aarch64.* /out \
  && :
index 89050d1..0c2d995 100644 (file)
@@ -41,4 +41,4 @@ CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
 CMake_TEST_Qt5:BOOL=FALSE
 
 # CPack package file name component for this platform.
-CPACK_SYSTEM_NAME:STRING=Linux-aarch64
+CPACK_SYSTEM_NAME:STRING=linux-aarch64
index 972913e..8c98d3e 100644 (file)
@@ -5,7 +5,7 @@
 # Build using the CMake source directory as the build context.
 # The resulting image will have an '/out' directory containing the package.
 
-# Keep this in sync with the `.gitlab-ci.yml` `release_linux` image.
+# Keep this in sync with the `.gitlab/os-linux.yml` `.linux_release_x86_64` image.
 ARG FROM_IMAGE_NAME=kitware/cmake:build-linux-x86_64-deps-2020-04-02
 ARG FROM_IMAGE_DIGEST=@sha256:77e9ab183f34680990db9da5945473e288f0d6556bce79ecc1589670d656e157
 ARG FROM_IMAGE=$FROM_IMAGE_NAME$FROM_IMAGE_DIGEST
@@ -32,5 +32,5 @@ RUN : \
  && bin/cpack -G STGZ \
  && set +x \
  && mkdir /out \
- && mv cmake-*-Linux-x86_64.* /out \
+ && mv cmake-*-linux-x86_64.* /out \
  && :
index a2864e9..e1f9fe3 100644 (file)
@@ -41,4 +41,4 @@ CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
 CMake_TEST_Qt5:BOOL=FALSE
 
 # CPack package file name component for this platform.
-CPACK_SYSTEM_NAME:STRING=Linux-x86_64
+CPACK_SYSTEM_NAME:STRING=linux-x86_64
index 3c0ecc7..54a45d8 100644 (file)
@@ -42,4 +42,4 @@ CMAKE_Swift_COMPILER:FILEPATH=FALSE
 CMake_TEST_Qt5:BOOL=FALSE
 
 # CPack package file name component for this platform.
-CPACK_SYSTEM_NAME:STRING=win32-x86
+CPACK_SYSTEM_NAME:STRING=windows-i386
index 2ccf93b..0b78c72 100644 (file)
@@ -42,4 +42,4 @@ CMAKE_Swift_COMPILER:FILEPATH=FALSE
 CMake_TEST_Qt5:BOOL=FALSE
 
 # CPack package file name component for this platform.
-CPACK_SYSTEM_NAME:STRING=win64-x64
+CPACK_SYSTEM_NAME:STRING=windows-x86_64
index 6fb35c0..33b59f7 100755 (executable)
@@ -22,12 +22,7 @@ do
 
     if [[ (${in_file} -nt ${cxx_file}) || (${in_file} -nt ${h_file}) || (${forced} -gt 0) ]]; then
         echo "Generating Parser ${parser}"
-          bison --yacc --name-prefix=${prefix} --defines=${h_file} -o${cxx_file}  ${in_file}
-          sed -i '/\/\* Else will try to reuse/ i\
-#if 0
-/^yyerrlab1:/ a\
-#endif
-' ${cxx_file}
+          bison --name-prefix=${prefix} --defines=${h_file} -o${cxx_file}  ${in_file}
     else
         echo "Skipped generating Parser ${parser}"
     fi
index 94a42e9..16cdd65 100755 (executable)
@@ -8,7 +8,7 @@ readonly name="curl"
 readonly ownership="Curl Upstream <curl-library@cool.haxx.se>"
 readonly subtree="Utilities/cmcurl"
 readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-7_72_0"
+readonly tag="curl-7_75_0"
 readonly shortlog=false
 readonly paths="
   CMake/*
index e5be43a..f989907 100644 (file)
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeHelp_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.1...3.15 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.1...3.18 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
index e175d0d..ece4bf5 100644 (file)
@@ -191,6 +191,7 @@ _cmake_index_objs = {
     'cpack_gen':  _cmake_index_entry('cpack generator'),
     'envvar':     _cmake_index_entry('envvar'),
     'generator':  _cmake_index_entry('generator'),
+    'genex':      _cmake_index_entry('genex'),
     'guide':      _cmake_index_entry('guide'),
     'manual':     _cmake_index_entry('manual'),
     'module':     _cmake_index_entry('module'),
@@ -224,7 +225,7 @@ class CMakeTransform(Transform):
         self.titles = {}
 
     def parse_title(self, docname):
-        """Parse a document title as the first line starting in [A-Za-z0-9<]
+        """Parse a document title as the first line starting in [A-Za-z0-9<$]
            or fall back to the document basename if no such line exists.
            The cmake --help-*-list commands also depend on this convention.
            Return the title or False if the document file does not exist.
@@ -239,7 +240,7 @@ class CMakeTransform(Transform):
                 title = False
             else:
                 for line in f:
-                    if len(line) > 0 and (line[0].isalnum() or line[0] == '<'):
+                    if len(line) > 0 and (line[0].isalnum() or line[0] == '<' or line[0] == '$'):
                         title = line.rstrip()
                         break
                 f.close()
@@ -260,6 +261,10 @@ class CMakeTransform(Transform):
             if objtype == 'command':
                 targetname = title.lower()
             else:
+                if objtype == 'genex':
+                    m = CMakeXRefRole._re_genex.match(title)
+                    if m:
+                        title = m.group(1)
                 targetname = title
             targetid = '%s:%s' % (objtype, targetname)
             targetnode = nodes.target('', '', ids=[targetid])
@@ -277,6 +282,10 @@ class CMakeObject(ObjectDescription):
     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):
@@ -302,6 +311,7 @@ class CMakeXRefRole(XRefRole):
     # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.
     _re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL)
     _re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL)
+    _re_genex = re.compile(r'^\$<([^<>:]+)(:[^<>]+)?>$', re.DOTALL)
 
     def __call__(self, typ, rawtext, text, *args, **keys):
         # Translate CMake command cross-references of the form:
@@ -312,6 +322,10 @@ class CMakeXRefRole(XRefRole):
             m = CMakeXRefRole._re_sub.match(text)
             if m:
                 text = '%s <%s>' % (text, m.group(1))
+        elif typ == 'cmake:genex':
+            m = CMakeXRefRole._re_genex.match(text)
+            if m:
+                text = '%s <%s>' % (text, m.group(1))
         # CMake cross-reference targets frequently contain '<' so escape
         # any explicit `<target>` with '<' not preceded by whitespace.
         while True:
@@ -374,6 +388,7 @@ class CMakeDomain(Domain):
         'cpack_gen':  ObjType('cpack_gen',  'cpack_gen'),
         'envvar':     ObjType('envvar',     'envvar'),
         'generator':  ObjType('generator',  'generator'),
+        'genex':      ObjType('genex',      'genex'),
         'guide':      ObjType('guide',      'guide'),
         'variable':   ObjType('variable',   'variable'),
         'module':     ObjType('module',     'module'),
@@ -390,6 +405,7 @@ class CMakeDomain(Domain):
     directives = {
         'command':    CMakeObject,
         'envvar':     CMakeObject,
+        'genex':      CMakeObject,
         'variable':   CMakeObject,
         # Other object types cannot be created except by the CMakeTransform
         # 'generator':  CMakeObject,
@@ -409,6 +425,7 @@ class CMakeDomain(Domain):
         'cpack_gen':  CMakeXRefRole(),
         'envvar':     CMakeXRefRole(),
         'generator':  CMakeXRefRole(),
+        'genex':      CMakeXRefRole(),
         'guide':      CMakeXRefRole(),
         'variable':   CMakeXRefRole(),
         'module':     CMakeXRefRole(),
index 42b0951..5def681 100644 (file)
@@ -29,6 +29,7 @@ extensions = ['cmake']
 templates_path = ['@conf_path@/templates']
 
 nitpicky = True
+smartquotes = False
 
 cmake_manuals = sorted(glob.glob(r'@conf_docs@/manual/*.rst'))
 cmake_manual_description = re.compile('^\.\. cmake-manual-description:(.*)$')
index e35f127..0ff39a0 100755 (executable)
@@ -25,6 +25,7 @@ for line in lines:
              ("envvar", "envvar"),
              ("variable", "variable"),
              ("generator", "generator"),
+             ("genex", "genex"),
              ("guide", "guide"),
              ("target property", "prop_tgt"),
              ("test property", "prop_test"),
index b082ede..029eb1b 100644 (file)
@@ -16,3 +16,9 @@ div.sphinxsidebarwrapper {
 .literal-block a.reference.internal {
   background-color: #dfdfdf;
 }
+
+/* Remove unwanted margin in case list item contains a div-wrapping
+   directive like `.. versionadded` or `.. deprecated`. */
+dd > :first-child > p {
+  margin-top: 0px;
+}
index cb4a038..9b53b0f 100644 (file)
@@ -2,7 +2,7 @@ project(bzip2)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 2bafe2c..8ccd016 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index aaac9fe..e99ea6f 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
@@ -27,7 +27,7 @@ mark_as_advanced(CURL_HIDDEN_SYMBOLS)
 if(CURL_HIDDEN_SYMBOLS)
   set(SUPPORTS_SYMBOL_HIDING FALSE)
 
-  if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+  if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC)
     set(SUPPORTS_SYMBOL_HIDING TRUE)
     set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
     set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
index 3ef35f0..949910d 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index a8f72c9..9455f4b 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index c43172b..0ed0855 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 9160ae5..7180682 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 02111a2..4e4747d 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 4cdf3e3..ce46a40 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 2ebe721..1746093 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index e1eba05..8614492 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 73ce9e1..643b600 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index a1ed8cd..5757009 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 5fdb2b7..899c6b0 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 01d1758..0247364 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 54df1a8..42256b3 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 44c741a..eaba397 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 65a41e4..d57dd6a 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
@@ -107,3 +107,14 @@ macro(curl_nroff_check)
     message(WARNING "Found no *nroff program")
   endif()
 endmacro()
+
+macro(optional_dependency DEPENDENCY)
+  set(CURL_${DEPENDENCY} AUTO CACHE STRING "Build curl with ${DEPENDENCY} support (AUTO, ON or OFF)")
+  set_property(CACHE CURL_${DEPENDENCY} PROPERTY STRINGS AUTO ON OFF)
+
+  if(CURL_${DEPENDENCY} STREQUAL AUTO)
+    find_package(${DEPENDENCY})
+  elseif(CURL_${DEPENDENCY})
+    find_package(${DEPENDENCY} REQUIRED)
+  endif()
+endmacro()
index 8c9a491..bbd4632 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 7c020bd..9307381 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 59b17d0..8f9b861 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 74e56a2..d9d9c4e 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index ae8cc30..957148e 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
index 4821656..4fb9361 100644 (file)
@@ -8,6 +8,7 @@ set(CMAKE_USE_LIBSSH2 OFF CACHE INTERNAL "Disable curl libssh2")
 set(CMAKE_USE_LIBSSH OFF)
 set(CMAKE_USE_OPENLDAP OFF CACHE INTERNAL "No curl OpenLDAP")
 set(CURL_BROTLI OFF)
+set(CURL_DISABLE_ALTSVC ON)
 set(CURL_DISABLE_COOKIES OFF CACHE INTERNAL "Do not disable curl cookie support")
 set(CURL_DISABLE_CRYPTO_AUTH OFF CACHE INTERNAL "Do not disable curl crypto auth")
 set(CURL_DISABLE_DICT ON CACHE INTERNAL "Disable curl dict protocol?")
@@ -18,6 +19,8 @@ set(CURL_DISABLE_HTTP OFF CACHE INTERNAL "Disable curl http protocol?")
 set(CURL_DISABLE_IMAP ON CACHE INTERNAL "Disable curl imap protocol?")
 set(CURL_DISABLE_LDAP ON CACHE INTERNAL "Disable curl ldap protocol?")
 set(CURL_DISABLE_LDAPS ON CACHE INTERNAL "Disable curl ldaps protocol?")
+set(CURL_DISABLE_MQTT ON)
+set(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG OFF)
 set(CURL_DISABLE_POP3 ON CACHE INTERNAL "Disable curl pop3 protocol?")
 set(CURL_DISABLE_PROXY OFF CACHE INTERNAL "Do not disable curl proxy")
 set(CURL_DISABLE_RTSP ON CACHE INTERNAL "Disable curl rtsp protocol?")
@@ -25,7 +28,6 @@ set(CURL_DISABLE_SMTP ON CACHE INTERNAL "Disable curl smtp protocol?")
 set(CURL_DISABLE_TELNET ON CACHE INTERNAL "Disable curl telnet protocol?")
 set(CURL_DISABLE_TFTP ON CACHE INTERNAL "Disable curl tftp protocol?")
 set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity")
-set(CURL_ENABLE_MQTT OFF)
 set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols")
 set(CURL_LTO OFF CACHE INTERNAL "Turn on compiler Link Time Optimizations")
 set(CURL_STATIC_CRT OFF CACHE INTERNAL "Set to ON to build libcurl with static CRT on Windows (/MT).")
@@ -40,9 +42,11 @@ set(ENABLE_INET_PTON OFF CACHE INTERNAL "Set to OFF to prevent usage of inet_pto
 set(ENABLE_IPV6 ON CACHE INTERNAL "Enable curl IPv6 support detection")
 set(ENABLE_MANUAL OFF CACHE INTERNAL "No curl built-in manual")
 set(ENABLE_THREADED_RESOLVER OFF CACHE INTERNAL "No curl POSIX threaded DNS lookup")
+set(ENABLE_UNICODE OFF)
 set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
 set(HTTP_ONLY OFF CACHE INTERNAL "Curl is not http-only")
 set(PICKY_COMPILER OFF CACHE INTERNAL "Enable picky compiler options")
+set(USE_LIBIDN2 ON)
 set(USE_NGHTTP2 ON)
 set(USE_NGTCP2 OFF)
 set(USE_QUICHE OFF)
@@ -93,7 +97,7 @@ endif(APPLE)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -106,11 +110,11 @@ endif()
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+# 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
@@ -146,10 +150,6 @@ include(CheckCCompilerFlag)
 
 project(CURL C)
 
-if(0) # This code not needed for building within CMake.
-message(WARNING "the curl cmake build system is poorly maintained. Be aware")
-endif()
-
 file(STRINGS ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS REGEX "#define LIBCURL_VERSION( |_NUM )")
 string(REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*"
   CURL_VERSION ${CURL_VERSION_H_CONTENTS})
@@ -168,7 +168,7 @@ endif()
 # SET(PACKAGE_NAME "curl")
 # SET(PACKAGE_VERSION "-")
 # SET(PACKAGE_STRING "curl-")
-# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/")
+# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.se/mail/")
 set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
 set(OS "\"${CMAKE_SYSTEM_NAME}\"")
 
@@ -182,6 +182,7 @@ option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
 if(WIN32)
   option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF)
   option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON)
+  option(ENABLE_UNICODE "Set to ON to use the Unicode version of the Windows API functions" OFF)
   if(0) # This code not needed for building within CMake.
   set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string")
   if(CURL_TARGET_WINDOWS_VERSION)
@@ -197,6 +198,12 @@ if(WIN32)
     set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=0x0501")
   endif()
   endif()
+  if(ENABLE_UNICODE)
+    add_definitions(-DUNICODE -D_UNICODE)
+    if(MINGW)
+      add_compile_options(-municode)
+    endif()
+  endif()
 endif()
 option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF)
 
@@ -294,28 +301,30 @@ option(CURL_DISABLE_SMTP "to disable SMTP" OFF)
 mark_as_advanced(CURL_DISABLE_SMTP)
 option(CURL_DISABLE_GOPHER "to disable Gopher" OFF)
 mark_as_advanced(CURL_DISABLE_GOPHER)
-option(CURL_ENABLE_MQTT "to enable MQTT" OFF)
-mark_as_advanced(CURL_ENABLE_MQTT)
+option(CURL_DISABLE_MQTT "to disable MQTT" OFF)
+mark_as_advanced(CURL_DISABLE_MQTT)
 
 if(HTTP_ONLY)
+  set(CURL_DISABLE_DICT ON)
+  set(CURL_DISABLE_FILE ON)
   set(CURL_DISABLE_FTP ON)
+  set(CURL_DISABLE_GOPHER ON)
+  set(CURL_DISABLE_IMAP ON)
   set(CURL_DISABLE_LDAP ON)
   set(CURL_DISABLE_LDAPS ON)
-  set(CURL_DISABLE_TELNET ON)
-  set(CURL_DISABLE_DICT ON)
-  set(CURL_DISABLE_FILE ON)
-  set(CURL_DISABLE_TFTP ON)
-  set(CURL_DISABLE_RTSP ON)
+  set(CURL_DISABLE_MQTT ON)
   set(CURL_DISABLE_POP3 ON)
-  set(CURL_DISABLE_IMAP ON)
+  set(CURL_DISABLE_RTSP ON)
   set(CURL_DISABLE_SMB ON)
   set(CURL_DISABLE_SMTP ON)
-  set(CURL_DISABLE_GOPHER ON)
+  set(CURL_DISABLE_TELNET ON)
+  set(CURL_DISABLE_TFTP ON)
 endif()
 
+option(CURL_DISABLE_ALTSVC "to disable alt-svc support" OFF)
+mark_as_advanced(CURL_DISABLE_ALTSVC)
 option(CURL_DISABLE_COOKIES "to disable cookies support" OFF)
 mark_as_advanced(CURL_DISABLE_COOKIES)
-
 option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF)
 mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
 option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF)
@@ -352,10 +361,6 @@ if(ENABLE_MANUAL)
 endif()
 endif()
 
-# We need ansi c-flags, especially on HP
-set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
-set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
-
 if(CURL_STATIC_CRT)
   set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
   set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
@@ -454,6 +459,7 @@ set(openssl_default ON)
 if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_SCHANNEL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS OR CMAKE_USE_WOLFSSL)
   set(openssl_default OFF)
 endif()
+option(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG "Disable automatic loading of OpenSSL configuration" OFF)
 
 count_true(enabled_ssl_options_count
   CMAKE_USE_SCHANNEL
@@ -741,34 +747,35 @@ if(NOT CURL_DISABLE_LDAPS)
 endif()
 
 # Check for idn
-check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
+option(USE_LIBIDN2 "Use libidn2 for IDN support" ON)
+set(HAVE_LIBIDN2 OFF)
+if(USE_LIBIDN2)
+  check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
+endif()
 
 # Check for symbol dlopen (same as HAVE_LIBDL)
 check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
 
 if(0) # This code not needed for building within CMake.
-option(CURL_ZLIB "Set to ON to enable building curl with zlib support." ON)
 set(HAVE_LIBZ OFF)
 set(HAVE_ZLIB_H OFF)
 set(USE_ZLIB OFF)
-if(CURL_ZLIB)
-  find_package(ZLIB QUIET)
-  if(ZLIB_FOUND)
-    set(HAVE_ZLIB_H ON)
-    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})
-    endif()
-    list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
+optional_dependency(ZLIB)
+if(ZLIB_FOUND)
+  set(HAVE_ZLIB_H ON)
+  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})
   endif()
+  list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
 endif()
 endif()
 
@@ -911,6 +918,7 @@ if(CMAKE_USE_GSSAPI)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
+    set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
     list(APPEND CURL_LIBS ${GSS_LIBRARIES})
 
   else()
@@ -926,8 +934,6 @@ else()
   unset(USE_UNIX_SOCKETS CACHE)
 endif()
 
-option(ENABLE_ALT_SVC "Enable alt-svc support" OFF)
-set(USE_ALTSVC ${ENABLE_ALT_SVC})
 
 if(0) # This code not needed for building within CMake.
 #
@@ -1055,6 +1061,7 @@ check_include_file_concat("net/if.h"         HAVE_NET_IF_H)
 check_include_file_concat("netdb.h"          HAVE_NETDB_H)
 check_include_file_concat("netinet/in.h"     HAVE_NETINET_IN_H)
 check_include_file_concat("netinet/tcp.h"    HAVE_NETINET_TCP_H)
+check_include_file("linux/tcp.h"      HAVE_LINUX_TCP_H)
 
 check_include_file_concat("pem.h"            HAVE_PEM_H)
 check_include_file_concat("poll.h"           HAVE_POLL_H)
@@ -1465,16 +1472,16 @@ install(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmcurl)
 #-----------------------------------------------------------------------------
 
 if(0) # This code not needed for building within CMake.
-option(BUILD_TESTING "Build tests" "${PERL_FOUND}")
-if(NOT PERL_FOUND)
-  message(STATUS "Perl not found, testing disabled.")
-elseif(BUILD_TESTING)
+cmake_dependent_option(BUILD_TESTING "Build tests"
+  ON "PERL_FOUND;NOT CURL_DISABLE_TESTS"
+  OFF)
+if(BUILD_TESTING)
   add_subdirectory(tests)
 endif()
 
 # NTLM support requires crypto function adaptions from various SSL libs
 # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
-if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_DARWINSSL OR USE_MBEDTLS OR USE_WIN32_CRYPTO))
+if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_DARWINSSL OR USE_MBEDTLS OR USE_WIN32_CRYPTO))
   set(use_ntlm ON)
 else()
   set(use_ntlm OFF)
@@ -1493,7 +1500,7 @@ endmacro()
 set(_items)
 _add_if("SSL"           SSL_ENABLED)
 _add_if("IPv6"          ENABLE_IPV6)
-_add_if("unix-sockets"  USE_UNIX_SOCKETS)
+_add_if("unixsockets"   USE_UNIX_SOCKETS)
 _add_if("libz"          HAVE_LIBZ)
 _add_if("brotli"        HAVE_BROTLI)
 _add_if("zstd"          HAVE_ZSTD)
@@ -1504,7 +1511,7 @@ _add_if("Largefile"     (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND
 # TODO SSP1 (Schannel) check is missing
 _add_if("SSPI"          USE_WINDOWS_SSPI)
 _add_if("GSS-API"       HAVE_GSSAPI)
-_add_if("alt-svc"       ENABLE_ALT_SVC)
+_add_if("alt-svc"       NOT CURL_DISABLE_ALTSVC)
 # TODO SSP1 missing for SPNEGO
 _add_if("SPNEGO"        NOT CURL_DISABLE_CRYPTO_AUTH AND
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
@@ -1512,7 +1519,7 @@ _add_if("Kerberos"      NOT CURL_DISABLE_CRYPTO_AUTH AND
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
 # NTLM support requires crypto function adaptions from various SSL libs
 # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
-_add_if("NTLM"        use_ntlm)
+_add_if("NTLM"        use_ntlm OR USE_WINDOWS_SSPI)
 # TODO missing option (autoconf: --enable-ntlm-wb)
 _add_if("NTLM_WB"     use_ntlm AND NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
 # TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP
@@ -1522,6 +1529,7 @@ _add_if("HTTP2"         USE_NGHTTP2)
 _add_if("HTTP3"         USE_NGTCP2 OR USE_QUICHE)
 _add_if("MultiSSL"      CURL_WITH_MULTI_SSL)
 _add_if("HTTPS-proxy"   SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS))
+_add_if("unicode"       ENABLE_UNICODE)
 string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
 message(STATUS "Enabled features: ${SUPPORT_FEATURES}")
 
@@ -1542,6 +1550,7 @@ _add_if("LDAPS"         NOT CURL_DISABLE_LDAPS AND
 _add_if("DICT"          NOT CURL_DISABLE_DICT)
 _add_if("TFTP"          NOT CURL_DISABLE_TFTP)
 _add_if("GOPHER"        NOT CURL_DISABLE_GOPHER)
+_add_if("GOPHERS"       NOT CURL_DISABLE_GOPHER AND SSL_ENABLED)
 _add_if("POP3"          NOT CURL_DISABLE_POP3)
 _add_if("POP3S"         NOT CURL_DISABLE_POP3 AND SSL_ENABLED)
 _add_if("IMAP"          NOT CURL_DISABLE_IMAP)
@@ -1554,7 +1563,7 @@ _add_if("SCP"           USE_LIBSSH2 OR USE_LIBSSH)
 _add_if("SFTP"          USE_LIBSSH2 OR USE_LIBSSH)
 _add_if("RTSP"          NOT CURL_DISABLE_RTSP)
 _add_if("RTMP"          USE_LIBRTMP)
-_add_if("MQTT"          CURL_ENABLE_MQTT)
+_add_if("MQTT"          NOT CURL_DISABLE_MQTT)
 if(_items)
   list(SORT _items)
 endif()
index 9d9e4af..48f1447 100644 (file)
@@ -1,6 +1,6 @@
 COPYRIGHT AND PERMISSION NOTICE
 
-Copyright (c) 1996 - 2020, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2021, Daniel Stenberg, <daniel@haxx.se>, and many
 contributors, see the THANKS file.
 
 All rights reserved.
index e8e3ed1..676dce3 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -24,7 +24,7 @@
 
 /*
  * If you have libcurl problems, all docs and details are found here:
- *   https://curl.haxx.se/libcurl/
+ *   https://curl.se/libcurl/
  *
  * curl-library mailing list subscription and unsubscription web interface:
  *   https://cool.haxx.se/mailman/listinfo/curl-library/
@@ -74,7 +74,7 @@
 #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
     defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
-    defined(__CYGWIN__) || \
+    defined(__CYGWIN__) || defined(AMIGA) || \
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
 #include <sys/select.h>
 #endif
@@ -610,6 +610,7 @@ typedef enum {
                                     error */
   CURLE_HTTP3,                   /* 95 - An HTTP/3 layer problem */
   CURLE_QUIC_CONNECT_ERROR,      /* 96 - QUIC connection error */
+  CURLE_PROXY,                   /* 97 - proxy handshake error */
   CURL_LAST /* never use! */
 } CURLcode;
 
@@ -689,6 +690,48 @@ typedef enum {
 
 #endif /*!CURL_NO_OLDIES*/
 
+/*
+ * Proxy error codes. Returned in CURLINFO_PROXY_ERROR if CURLE_PROXY was
+ * return for the transfers.
+ */
+typedef enum {
+  CURLPX_OK,
+  CURLPX_BAD_ADDRESS_TYPE,
+  CURLPX_BAD_VERSION,
+  CURLPX_CLOSED,
+  CURLPX_GSSAPI,
+  CURLPX_GSSAPI_PERMSG,
+  CURLPX_GSSAPI_PROTECTION,
+  CURLPX_IDENTD,
+  CURLPX_IDENTD_DIFFER,
+  CURLPX_LONG_HOSTNAME,
+  CURLPX_LONG_PASSWD,
+  CURLPX_LONG_USER,
+  CURLPX_NO_AUTH,
+  CURLPX_RECV_ADDRESS,
+  CURLPX_RECV_AUTH,
+  CURLPX_RECV_CONNECT,
+  CURLPX_RECV_REQACK,
+  CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
+  CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
+  CURLPX_REPLY_CONNECTION_REFUSED,
+  CURLPX_REPLY_GENERAL_SERVER_FAILURE,
+  CURLPX_REPLY_HOST_UNREACHABLE,
+  CURLPX_REPLY_NETWORK_UNREACHABLE,
+  CURLPX_REPLY_NOT_ALLOWED,
+  CURLPX_REPLY_TTL_EXPIRED,
+  CURLPX_REPLY_UNASSIGNED,
+  CURLPX_REQUEST_FAILED,
+  CURLPX_RESOLVE_HOST,
+  CURLPX_SEND_AUTH,
+  CURLPX_SEND_CONNECT,
+  CURLPX_SEND_REQUEST,
+  CURLPX_UNKNOWN_FAIL,
+  CURLPX_UNKNOWN_MODE,
+  CURLPX_USER_REJECTED,
+  CURLPX_LAST /* never use */
+} CURLproxycode;
+
 /* This prototype applies to all conversion callbacks */
 typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
 
@@ -744,6 +787,7 @@ typedef enum {
 #define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
 #define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
 #define CURLAUTH_BEARER       (((unsigned long)1)<<6)
+#define CURLAUTH_AWS_SIGV4    (((unsigned long)1)<<7)
 #define CURLAUTH_ONLY         (((unsigned long)1)<<31)
 #define CURLAUTH_ANY          (~CURLAUTH_DIGEST_IE)
 #define CURLAUTH_ANYSAFE      (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
@@ -789,6 +833,7 @@ enum curl_khstat {
   CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now so
                         this causes a CURLE_DEFER error but otherwise the
                         connection will be left intact etc */
+  CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key*/
   CURLKHSTAT_LAST    /* not for use, only a marker for last-in-list */
 };
 
@@ -905,13 +950,42 @@ typedef enum {
 #define CURLHEADER_SEPARATE (1<<0)
 
 /* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */
-#define CURLALTSVC_IMMEDIATELY  (1<<0)
-
 #define CURLALTSVC_READONLYFILE (1<<2)
 #define CURLALTSVC_H1           (1<<3)
 #define CURLALTSVC_H2           (1<<4)
 #define CURLALTSVC_H3           (1<<5)
 
+
+struct curl_hstsentry {
+  char *name;
+  size_t namelen;
+  unsigned int includeSubDomains:1;
+  char expire[18]; /* YYYYMMDD HH:MM:SS [null-terminated] */
+};
+
+struct curl_index {
+  size_t index; /* the provided entry's "index" or count */
+  size_t total; /* total number of entries to save */
+};
+
+typedef enum {
+  CURLSTS_OK,
+  CURLSTS_DONE,
+  CURLSTS_FAIL
+} CURLSTScode;
+
+typedef CURLSTScode (*curl_hstsread_callback)(CURL *easy,
+                                              struct curl_hstsentry *e,
+                                              void *userp);
+typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
+                                               struct curl_hstsentry *e,
+                                               struct curl_index *i,
+                                               void *userp);
+
+/* CURLHSTS_* are bits for the CURLOPT_HSTS option */
+#define CURLHSTS_ENABLE       (long)(1<<0)
+#define CURLHSTS_READONLYFILE (long)(1<<1)
+
 /* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
 #define CURLPROTO_HTTP   (1<<0)
 #define CURLPROTO_HTTPS  (1<<1)
@@ -942,6 +1016,7 @@ typedef enum {
 #define CURLPROTO_SMB    (1<<26)
 #define CURLPROTO_SMBS   (1<<27)
 #define CURLPROTO_MQTT   (1<<28)
+#define CURLPROTO_GOPHERS (1<<29)
 #define CURLPROTO_ALL    (~0) /* enable everything */
 
 /* long may be 32 or 64 bits, but we should never depend on anything else
@@ -958,17 +1033,27 @@ typedef enum {
 
 #define CURLOPT(na,t,nu) na = t + nu
 
-/* handy aliases that make no run-time difference */
-#define CURLOPTTYPE_STRINGPOINT  CURLOPTTYPE_OBJECTPOINT
+/* CURLOPT aliases that make no run-time difference */
+
+/* 'char *' argument to a string with a trailing zero */
+#define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT
+
+/* 'struct curl_slist *' argument */
 #define CURLOPTTYPE_SLISTPOINT  CURLOPTTYPE_OBJECTPOINT
 
+/* 'void *' argument passed untouched to callback */
+#define CURLOPTTYPE_CBPOINT     CURLOPTTYPE_OBJECTPOINT
+
+/* 'long' argument with a set of values/bitmask */
+#define CURLOPTTYPE_VALUES      CURLOPTTYPE_LONG
+
 /*
  * All CURLOPT_* values.
  */
 
 typedef enum {
   /* This is the FILE * or void * the regular output should be written to. */
-  CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_OBJECTPOINT, 1),
+  CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_CBPOINT, 1),
 
   /* The full URL to get/put */
   CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2),
@@ -991,7 +1076,7 @@ typedef enum {
   /* not used */
 
   /* Specified file stream to upload from (use as input): */
-  CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_OBJECTPOINT, 9),
+  CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_CBPOINT, 9),
 
   /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
    * bytes big. */
@@ -1076,7 +1161,7 @@ typedef enum {
 
   /* send FILE * or void * to store headers to, if you use a callback it
      is simply passed to the callback unmodified */
-  CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_OBJECTPOINT, 29),
+  CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_CBPOINT, 29),
 
   /* point to a file to read the initial cookies from, also enables
      "cookie awareness" */
@@ -1084,10 +1169,10 @@ typedef enum {
 
   /* What version to specifically try to use.
      See CURL_SSLVERSION defines below. */
-  CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_LONG, 32),
+  CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_VALUES, 32),
 
   /* What kind of HTTP time condition to use, see defines */
-  CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_LONG, 33),
+  CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_VALUES, 33),
 
   /* Time to use with the above condition. Specified in number of seconds
      since 1 Jan 1970 */
@@ -1141,7 +1226,7 @@ typedef enum {
 
   /* Specify whether to read the user+password from the .netrc or the URL.
    * This must be one of the CURL_NETRC_* enums below. */
-  CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_LONG, 51),
+  CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_VALUES, 51),
 
   /* use Location: Luke! */
   CURLOPT(CURLOPT_FOLLOWLOCATION, CURLOPTTYPE_LONG, 52),
@@ -1162,8 +1247,8 @@ typedef enum {
 
   /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
      callbacks */
-  CURLOPT(CURLOPT_PROGRESSDATA, CURLOPTTYPE_OBJECTPOINT, 57),
-#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA
+  CURLOPT(CURLOPT_XFERINFODATA, CURLOPTTYPE_CBPOINT, 57),
+#define CURLOPT_PROGRESSDATA CURLOPT_XFERINFODATA
 
   /* We want the referrer field set automatically when following locations */
   CURLOPT(CURLOPT_AUTOREFERER, CURLOPTTYPE_LONG, 58),
@@ -1258,7 +1343,7 @@ typedef enum {
 
   /* Specify which HTTP version to use! This must be set to one of the
      CURL_HTTP_VERSION* enums set below. */
-  CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_LONG, 84),
+  CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_VALUES, 84),
 
   /* Specifically switch on or off the FTP engine's use of the EPSV command. By
      default, that one will always be attempted before the more traditional
@@ -1296,7 +1381,7 @@ typedef enum {
   CURLOPT(CURLOPT_DEBUGFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 94),
 
   /* set the data for the debug function */
-  CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_OBJECTPOINT, 95),
+  CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_CBPOINT, 95),
 
   /* mark this as start of a cookie session */
   CURLOPT(CURLOPT_COOKIESESSION, CURLOPTTYPE_LONG, 96),
@@ -1319,7 +1404,7 @@ typedef enum {
   /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
      CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and
      CURLPROXY_SOCKS5. */
-  CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_LONG, 101),
+  CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_VALUES, 101),
 
   /* Set the Accept-Encoding string. Use this to tell a server you would like
      the response to be compressed. Before 7.21.6, this was known as
@@ -1345,7 +1430,7 @@ typedef enum {
   /* Set this to a bitmask value to enable the particular authentications
      methods you like. Use this in combination with CURLOPT_USERPWD.
      Note that setting multiple bits may cause extra network round-trips. */
-  CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_LONG, 107),
+  CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107),
 
   /* Set the ssl context callback function, currently only for OpenSSL or
      WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
@@ -1354,7 +1439,7 @@ typedef enum {
 
   /* Set the userdata for the ssl context callback function's third
      argument */
-  CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_OBJECTPOINT, 109),
+  CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_CBPOINT, 109),
 
   /* FTP Option that causes missing dirs to be created on the remote server.
      In 7.19.4 we introduced the convenience enums for this option using the
@@ -1365,7 +1450,7 @@ typedef enum {
   /* Set this to a bitmask value to enable the particular authentications
      methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
      Note that setting multiple bits may cause extra network round-trips. */
-  CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_LONG, 111),
+  CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111),
 
   /* FTP option that changes the timeout, in seconds, associated with
      getting a response.  This is different from transfer timeout time and
@@ -1377,7 +1462,7 @@ typedef enum {
   /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
      tell libcurl to resolve names to those IP versions only. This only has
      affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
-  CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_LONG, 113),
+  CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),
 
   /* Set this option to limit the size of a file that will be downloaded from
      an HTTP or FTP server.
@@ -1412,7 +1497,7 @@ typedef enum {
      CURLUSESSL_CONTROL - SSL for the control connection or fail
      CURLUSESSL_ALL     - SSL for all communication or fail
   */
-  CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_LONG, 119),
+  CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_VALUES, 119),
 
   /* The _LARGE version of the standard POSTFIELDSIZE option */
   CURLOPT(CURLOPT_POSTFIELDSIZE_LARGE, CURLOPTTYPE_OFF_T, 120),
@@ -1438,10 +1523,10 @@ typedef enum {
      CURLFTPAUTH_SSL     - try "AUTH SSL" first, then TLS
      CURLFTPAUTH_TLS     - try "AUTH TLS" first, then SSL
   */
-  CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_LONG, 129),
+  CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_VALUES, 129),
 
   CURLOPT(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130),
-  CURLOPT(CURLOPT_IOCTLDATA, CURLOPTTYPE_OBJECTPOINT, 131),
+  CURLOPT(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131),
 
   /* 132 OBSOLETE. Gone in 7.16.0 */
   /* 133 OBSOLETE. Gone in 7.16.0 */
@@ -1464,7 +1549,7 @@ typedef enum {
 
   /* Select "file method" to use when doing FTP, see the curl_ftpmethod
      above. */
-  CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_LONG, 138),
+  CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_VALUES, 138),
 
   /* Local port number to bind the socket to */
   CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139),
@@ -1501,14 +1586,14 @@ typedef enum {
 
   /* callback function for setting socket options */
   CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148),
-  CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_OBJECTPOINT, 149),
+  CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_CBPOINT, 149),
 
   /* set to 0 to disable session ID re-use for this transfer, default is
      enabled (== 1) */
   CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150),
 
   /* allowed SSH authentication methods */
-  CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_LONG, 151),
+  CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_VALUES, 151),
 
   /* Used by scp/sftp to do public/private key authentication */
   CURLOPT(CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPTTYPE_STRINGPOINT, 152),
@@ -1531,9 +1616,9 @@ typedef enum {
   CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159),
   CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160),
 
-  /* Set the behaviour of POST when redirecting. Values must be set to one
+  /* Set the behavior of POST when redirecting. Values must be set to one
      of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
-  CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_LONG, 161),
+  CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161),
 
   /* used by scp/sftp to verify the host's public key */
   CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162),
@@ -1543,7 +1628,7 @@ typedef enum {
      CURL_SOCKET_BAD.  The callback should have type
      curl_opensocket_callback */
   CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163),
-  CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 164),
+  CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164),
 
   /* POST volatile input fields. */
   CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165),
@@ -1553,7 +1638,7 @@ typedef enum {
 
   /* Callback function for seeking in the input stream */
   CURLOPT(CURLOPT_SEEKFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 167),
-  CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_OBJECTPOINT, 168),
+  CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_CBPOINT, 168),
 
   /* CRL file */
   CURLOPT(CURLOPT_CRLFILE, CURLOPTTYPE_STRINGPOINT, 169),
@@ -1614,7 +1699,7 @@ typedef enum {
   CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184),
 
   /* set the SSH host key callback custom pointer */
-  CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_OBJECTPOINT, 185),
+  CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_CBPOINT, 185),
 
   /* set the SMTP mail originator */
   CURLOPT(CURLOPT_MAIL_FROM, CURLOPTTYPE_STRINGPOINT, 186),
@@ -1626,7 +1711,7 @@ typedef enum {
   CURLOPT(CURLOPT_FTP_USE_PRET, CURLOPTTYPE_LONG, 188),
 
   /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
-  CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_LONG, 189),
+  CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_VALUES, 189),
 
   /* The RTSP session identifier */
   CURLOPT(CURLOPT_RTSP_SESSION_ID, CURLOPTTYPE_STRINGPOINT, 190),
@@ -1644,7 +1729,7 @@ typedef enum {
   CURLOPT(CURLOPT_RTSP_SERVER_CSEQ, CURLOPTTYPE_LONG, 194),
 
   /* The stream to pass to INTERLEAVEFUNCTION. */
-  CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_OBJECTPOINT, 195),
+  CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_CBPOINT, 195),
 
   /* Let the application define a custom write method for RTP data */
   CURLOPT(CURLOPT_INTERLEAVEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 196),
@@ -1664,10 +1749,10 @@ typedef enum {
   CURLOPT(CURLOPT_FNMATCH_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 200),
 
   /* Let the application define custom chunk data pointer */
-  CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_OBJECTPOINT, 201),
+  CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_CBPOINT, 201),
 
   /* FNMATCH_FUNCTION user pointer */
-  CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_OBJECTPOINT, 202),
+  CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_CBPOINT, 202),
 
   /* send linked-list of name:port:address sets */
   CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203),
@@ -1696,10 +1781,10 @@ typedef enum {
   /* Callback function for closing socket (instead of close(2)). The callback
      should have type curl_closesocket_callback */
   CURLOPT(CURLOPT_CLOSESOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 208),
-  CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 209),
+  CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_CBPOINT, 209),
 
   /* allow GSSAPI credential delegation */
-  CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_LONG, 210),
+  CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_VALUES, 210),
 
   /* Set the name servers to use for DNS resolution */
   CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211),
@@ -1716,7 +1801,7 @@ typedef enum {
   CURLOPT(CURLOPT_TCP_KEEPINTVL, CURLOPTTYPE_LONG, 215),
 
   /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
-  CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_LONG, 216),
+  CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_VALUES, 216),
 
   /* Set the SMTP auth originator */
   CURLOPT(CURLOPT_MAIL_AUTH, CURLOPTTYPE_STRINGPOINT, 217),
@@ -1763,7 +1848,7 @@ typedef enum {
   CURLOPT(CURLOPT_PROXYHEADER, CURLOPTTYPE_SLISTPOINT, 228),
 
   /* Pass in a bitmask of "header options" */
-  CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_LONG, 229),
+  CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_VALUES, 229),
 
   /* The public key in DER form used to validate the peer public key
      this option is used only if SSL_VERIFYPEER is true */
@@ -1835,7 +1920,7 @@ typedef enum {
 
   /* What version to specifically try to use for proxy.
      See CURL_SSLVERSION defines below. */
-  CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_LONG, 250),
+  CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_VALUES, 250),
 
   /* Set a username for authenticated TLS for proxy */
   CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251),
@@ -1909,7 +1994,7 @@ typedef enum {
   CURLOPT(CURLOPT_RESOLVER_START_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 272),
 
   /* User data to pass to the resolver start callback. */
-  CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_OBJECTPOINT, 273),
+  CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_CBPOINT, 273),
 
   /* send HAProxy PROXY protocol header? */
   CURLOPT(CURLOPT_HAPROXYPROTOCOL, CURLOPTTYPE_LONG, 274),
@@ -1940,7 +2025,7 @@ typedef enum {
   CURLOPT(CURLOPT_TRAILERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 283),
 
   /* pointer to be passed to HTTP_TRAILER_FUNCTION */
-  CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_OBJECTPOINT, 284),
+  CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_CBPOINT, 284),
 
   /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
   CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285),
@@ -1971,6 +2056,28 @@ typedef enum {
   CURLOPT(CURLOPT_PROXY_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 296),
   CURLOPT(CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 297),
 
+  /* the EC curves requested by the TLS client (RFC 8422, 5.1);
+   * OpenSSL support via 'set_groups'/'set_curves':
+   * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
+   */
+  CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298),
+
+  /* HSTS bitmask */
+  CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299),
+  /* HSTS file name */
+  CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300),
+
+  /* HSTS read callback */
+  CURLOPT(CURLOPT_HSTSREADFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 301),
+  CURLOPT(CURLOPT_HSTSREADDATA, CURLOPTTYPE_CBPOINT, 302),
+
+  /* HSTS write callback */
+  CURLOPT(CURLOPT_HSTSWRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 303),
+  CURLOPT(CURLOPT_HSTSWRITEDATA, CURLOPTTYPE_CBPOINT, 304),
+
+  /* Parameters for V4 signature */
+  CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -2643,8 +2750,9 @@ typedef enum {
   CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56,
   CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
   CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58,
+  CURLINFO_PROXY_ERROR      = CURLINFO_LONG + 59,
 
-  CURLINFO_LASTONE          = 58
+  CURLINFO_LASTONE          = 59
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -2746,6 +2854,7 @@ typedef enum {
   CURLVERSION_SIXTH,
   CURLVERSION_SEVENTH,
   CURLVERSION_EIGHTH,
+  CURLVERSION_NINTH,
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 
@@ -2754,7 +2863,7 @@ typedef enum {
    meant to be a built-in version number for what kind of struct the caller
    expects. If the struct ever changes, we redefine the NOW to another enum
    from above. */
-#define CURLVERSION_NOW CURLVERSION_EIGHTH
+#define CURLVERSION_NOW CURLVERSION_NINTH
 
 struct curl_version_info_data {
   CURLversion age;          /* age of the returned struct */
@@ -2805,6 +2914,8 @@ struct curl_version_info_data {
                                   (MAJOR << 24) | (MINOR << 12) | PATCH */
   const char *zstd_version; /* human readable string. */
 
+  /* These fields were added in CURLVERSION_NINTH */
+  const char *hyper_version; /* human readable string. */
 };
 typedef struct curl_version_info_data curl_version_info_data;
 
@@ -2841,6 +2952,7 @@ typedef struct curl_version_info_data curl_version_info_data;
 #define CURL_VERSION_HTTP3        (1<<25) /* HTTP3 support built-in */
 #define CURL_VERSION_ZSTD         (1<<26) /* zstd features are present */
 #define CURL_VERSION_UNICODE      (1<<27) /* Unicode support on Windows */
+#define CURL_VERSION_HSTS         (1<<28) /* HSTS is supported */
 
  /*
  * NAME curl_version_info()
@@ -2903,6 +3015,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #include "easy.h" /* nothing in curl is fun without the easy stuff */
 #include "multi.h"
 #include "urlapi.h"
+#include "options.h"
 
 /* the typechecker doesn't work in C++ (yet) */
 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
index a881bb7..71a6450 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.72.0"
+#define LIBCURL_VERSION "7.75.0"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 72
+#define LIBCURL_VERSION_MINOR 75
 #define LIBCURL_VERSION_PATCH 0
 
 /* This is the numeric version of the libcurl version number, meant for easier
@@ -57,7 +57,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 0x074800
+#define LIBCURL_VERSION_NUM 0x074b00
 
 /*
  * This is the date and time when the full source package was created. The
index 9aef133..2dbfb26 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index f615ed7..3549552 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index b911ba9..37f9829 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
diff --git a/Utilities/cmcurl/include/curl/options.h b/Utilities/cmcurl/include/curl/options.h
new file mode 100644 (file)
index 0000000..14373b5
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef CURLINC_OPTIONS_H
+#define CURLINC_OPTIONS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2018 - 2020, 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.
+ *
+ ***************************************************************************/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  CURLOT_LONG,    /* long (a range of values) */
+  CURLOT_VALUES,  /*      (a defined set or bitmask) */
+  CURLOT_OFF_T,   /* curl_off_t (a range of values) */
+  CURLOT_OBJECT,  /* pointer (void *) */
+  CURLOT_STRING,  /*         (char * to zero terminated buffer) */
+  CURLOT_SLIST,   /*         (struct curl_slist *) */
+  CURLOT_CBPTR,   /*         (void * passed as-is to a callback) */
+  CURLOT_BLOB,    /* blob (struct curl_blob *) */
+  CURLOT_FUNCTION /* function pointer */
+} curl_easytype;
+
+/* Flag bits */
+
+/* "alias" means it is provided for old programs to remain functional,
+   we prefer another name */
+#define CURLOT_FLAG_ALIAS (1<<0)
+
+/* The CURLOPTTYPE_* id ranges can still be used to figure out what type/size
+   to use for curl_easy_setopt() for the given id */
+struct curl_easyoption {
+  const char *name;
+  CURLoption id;
+  curl_easytype type;
+  unsigned int flags;
+};
+
+CURL_EXTERN const struct curl_easyoption *
+curl_easy_option_by_name(const char *name);
+
+CURL_EXTERN const struct curl_easyoption *
+curl_easy_option_by_id (CURLoption id);
+
+CURL_EXTERN const struct curl_easyoption *
+curl_easy_option_next(const struct curl_easyoption *prev);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+#endif /* CURLINC_OPTIONS_H */
index a6bdc1a..60596c7 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 867af61..faf8fcf 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index f8cb921..230f4c1 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -273,6 +273,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_FTPPORT ||                                             \
    (option) == CURLOPT_FTP_ACCOUNT ||                                         \
    (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
+   (option) == CURLOPT_HSTS ||                                                \
    (option) == CURLOPT_INTERFACE ||                                           \
    (option) == CURLOPT_ISSUERCERT ||                                          \
    (option) == CURLOPT_KEYPASSWD ||                                           \
@@ -292,6 +293,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_PROXY_CAINFO ||                                        \
    (option) == CURLOPT_PROXY_CAPATH ||                                        \
    (option) == CURLOPT_PROXY_CRLFILE ||                                       \
+   (option) == CURLOPT_PROXY_ISSUERCERT ||                                    \
    (option) == CURLOPT_PROXY_KEYPASSWD ||                                     \
    (option) == CURLOPT_PROXY_PINNEDPUBLICKEY ||                               \
    (option) == CURLOPT_PROXY_SERVICE_NAME ||                                  \
@@ -332,8 +334,10 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_URL ||                                                 \
    (option) == CURLOPT_USERAGENT ||                                           \
    (option) == CURLOPT_USERNAME ||                                            \
+   (option) == CURLOPT_AWS_SIGV4 ||                                           \
    (option) == CURLOPT_USERPWD ||                                             \
    (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
+   (option) == CURLOPT_SSL_EC_CURVES ||                                       \
    0)
 
 /* evaluates to true if option takes a curl_write_callback argument */
@@ -354,10 +358,11 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_DEBUGDATA ||                                           \
    (option) == CURLOPT_FNMATCH_DATA ||                                        \
    (option) == CURLOPT_HEADERDATA ||                                          \
+   (option) == CURLOPT_HSTSREADDATA ||                                        \
+   (option) == CURLOPT_HSTSWRITEDATA ||                                       \
    (option) == CURLOPT_INTERLEAVEDATA ||                                      \
    (option) == CURLOPT_IOCTLDATA ||                                           \
    (option) == CURLOPT_OPENSOCKETDATA ||                                      \
-   (option) == CURLOPT_PRIVATE ||                                             \
    (option) == CURLOPT_PROGRESSDATA ||                                        \
    (option) == CURLOPT_READDATA ||                                            \
    (option) == CURLOPT_SEEKDATA ||                                            \
index f2d0677..7343cb6 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 32bea68..703d0ad 100644 (file)
@@ -9,7 +9,7 @@
 #
 # 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.haxx.se/docs/copyright.html.
+# 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
@@ -39,7 +39,7 @@ list(APPEND HHEADERS
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
   )
 
-if(MSVC AND NOT CURL_STATICLIB)
+if(WIN32 AND NOT CURL_STATICLIB)
   list(APPEND CSOURCES libcurl.rc)
 endif()
 
@@ -50,15 +50,6 @@ endif()
 # # strtoofft.c - specify later
 # )
 
-# # if we have Kerberos 4, right now this is never on
-# #OPTION(CURL_KRB4 "Use Kerberos 4" OFF)
-# IF(CURL_KRB4)
-# SET(CSOURCES ${CSOURCES}
-# krb4.c
-# security.c
-# )
-# ENDIF(CURL_KRB4)
-
 # #OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
 # MARK_AS_ADVANCED(CURL_MALLOC_DEBUG)
 # IF(CURL_MALLOC_DEBUG)
index ae3f961..e8d2259 100644 (file)
@@ -5,11 +5,11 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+# 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
 #
 ###########################################################################
 
-LIB_VAUTH_CFILES = vauth/cleartext.c vauth/cram.c vauth/digest.c             \
-  vauth/digest_sspi.c vauth/krb5_gssapi.c vauth/krb5_sspi.c vauth/ntlm.c     \
-  vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \
+LIB_VAUTH_CFILES =      \
+  vauth/cleartext.c     \
+  vauth/cram.c          \
+  vauth/digest.c        \
+  vauth/digest_sspi.c   \
+  vauth/krb5_gssapi.c   \
+  vauth/krb5_sspi.c     \
+  vauth/ntlm.c          \
+  vauth/ntlm_sspi.c     \
+  vauth/oauth2.c        \
+  vauth/spnego_gssapi.c \
+  vauth/spnego_sspi.c   \
   vauth/vauth.c
 
-LIB_VAUTH_HFILES = vauth/digest.h vauth/ntlm.h vauth/vauth.h
+LIB_VAUTH_HFILES =      \
+  vauth/digest.h        \
+  vauth/ntlm.h          \
+  vauth/vauth.h
 
-LIB_VTLS_CFILES = vtls/bearssl.c vtls/gskit.c vtls/gtls.c vtls/keylog.c  \
-  vtls/mbedtls.c vtls/mbedtls_threadlock.c vtls/mesalink.c vtls/nss.c    \
-  vtls/openssl.c vtls/schannel.c vtls/schannel_verify.c vtls/sectransp.c \
-  vtls/vtls.c vtls/wolfssl.c
+LIB_VTLS_CFILES =           \
+  vtls/bearssl.c            \
+  vtls/gskit.c              \
+  vtls/gtls.c               \
+  vtls/keylog.c             \
+  vtls/mbedtls.c            \
+  vtls/mbedtls_threadlock.c \
+  vtls/mesalink.c           \
+  vtls/nss.c                \
+  vtls/openssl.c            \
+  vtls/schannel.c           \
+  vtls/schannel_verify.c    \
+  vtls/sectransp.c          \
+  vtls/vtls.c               \
+  vtls/wolfssl.c
 
-LIB_VTLS_HFILES = vtls/bearssl.h vtls/gskit.h vtls/gtls.h vtls/keylog.h      \
-  vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/mesalink.h vtls/nssg.h       \
-  vtls/openssl.h vtls/schannel.h vtls/sectransp.h vtls/vtls.h vtls/wolfssl.h
+LIB_VTLS_HFILES =           \
+  vtls/bearssl.h            \
+  vtls/gskit.h              \
+  vtls/gtls.h               \
+  vtls/keylog.h             \
+  vtls/mbedtls.h            \
+  vtls/mbedtls_threadlock.h \
+  vtls/mesalink.h           \
+  vtls/nssg.h               \
+  vtls/openssl.h            \
+  vtls/schannel.h           \
+  vtls/sectransp.h          \
+  vtls/vtls.h               \
+  vtls/wolfssl.h
 
-LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c vquic/vquic.c
+LIB_VQUIC_CFILES = \
+  vquic/ngtcp2.c   \
+  vquic/quiche.c   \
+  vquic/vquic.c
 
-LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h vquic/vquic.h
+LIB_VQUIC_HFILES = \
+  vquic/ngtcp2.h   \
+  vquic/quiche.h   \
+  vquic/vquic.h
 
-LIB_VSSH_CFILES = vssh/libssh.c vssh/libssh2.c vssh/wolfssh.c
+LIB_VSSH_CFILES =  \
+  vssh/libssh.c    \
+  vssh/libssh2.c   \
+  vssh/wolfssh.c
 
-LIB_VSSH_HFILES = vssh/ssh.h
+LIB_VSSH_HFILES =  \
+  vssh/ssh.h
 
-LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c            \
-  conncache.c connect.c content_encoding.c cookie.c curl_addrinfo.c           \
-  curl_ctype.c curl_des.c curl_endian.c curl_fnmatch.c curl_get_line.c        \
-  curl_gethostname.c curl_gssapi.c curl_memrchr.c curl_multibyte.c            \
-  curl_ntlm_core.c curl_ntlm_wb.c curl_path.c curl_range.c curl_rtmp.c        \
-  curl_sasl.c curl_sspi.c curl_threads.c dict.c dotdot.c easy.c escape.c      \
-  file.c fileinfo.c formdata.c ftp.c url.c ftplistparser.c getenv.c getinfo.c \
-  gopher.c hash.c hmac.c hostasyn.c hostcheck.c hostip.c hostip4.c hostip6.c  \
-  hostsyn.c http.c http2.c http_chunks.c http_digest.c http_negotiate.c       \
-  http_ntlm.c http_proxy.c idn_win32.c if2ip.c imap.c inet_ntop.c inet_pton.c \
-  krb5.c ldap.c llist.c md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c        \
-  multi.c netrc.c non-ascii.c nonblock.c openldap.c parsedate.c pingpong.c    \
-  pop3.c progress.c psl.c doh.c rand.c rename.c rtsp.c security.c select.c    \
-  sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \
-  socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c         \
-  strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c    \
-  transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c     \
-  version_win32.c
+LIB_CFILES =         \
+  altsvc.c           \
+  amigaos.c          \
+  asyn-ares.c        \
+  asyn-thread.c      \
+  base64.c           \
+  c-hyper.c          \
+  conncache.c        \
+  connect.c          \
+  content_encoding.c \
+  cookie.c           \
+  curl_addrinfo.c    \
+  curl_ctype.c       \
+  curl_des.c         \
+  curl_endian.c      \
+  curl_fnmatch.c     \
+  curl_get_line.c    \
+  curl_gethostname.c \
+  curl_gssapi.c      \
+  curl_memrchr.c     \
+  curl_multibyte.c   \
+  curl_ntlm_core.c   \
+  curl_ntlm_wb.c     \
+  curl_path.c        \
+  curl_range.c       \
+  curl_rtmp.c        \
+  curl_sasl.c        \
+  curl_sspi.c        \
+  curl_threads.c     \
+  dict.c             \
+  doh.c              \
+  dotdot.c           \
+  dynbuf.c           \
+  easy.c             \
+  easygetopt.c       \
+  easyoptions.c      \
+  escape.c           \
+  file.c             \
+  fileinfo.c         \
+  formdata.c         \
+  ftp.c              \
+  ftplistparser.c    \
+  getenv.c           \
+  getinfo.c          \
+  gopher.c           \
+  hash.c             \
+  hmac.c             \
+  hostasyn.c         \
+  hostcheck.c        \
+  hostip.c           \
+  hostip4.c          \
+  hostip6.c          \
+  hostsyn.c          \
+  hsts.c             \
+  http.c             \
+  http2.c            \
+  http_chunks.c      \
+  http_digest.c      \
+  http_negotiate.c   \
+  http_ntlm.c        \
+  http_proxy.c       \
+  http_aws_sigv4.c   \
+  idn_win32.c        \
+  if2ip.c            \
+  imap.c             \
+  inet_ntop.c        \
+  inet_pton.c        \
+  krb5.c             \
+  ldap.c             \
+  llist.c            \
+  md4.c              \
+  md5.c              \
+  memdebug.c         \
+  mime.c             \
+  mprintf.c          \
+  mqtt.c             \
+  multi.c            \
+  netrc.c            \
+  non-ascii.c        \
+  nonblock.c         \
+  openldap.c         \
+  parsedate.c        \
+  pingpong.c         \
+  pop3.c             \
+  progress.c         \
+  psl.c              \
+  rand.c             \
+  rename.c           \
+  rtsp.c             \
+  select.c           \
+  sendf.c            \
+  setopt.c           \
+  sha256.c           \
+  share.c            \
+  slist.c            \
+  smb.c              \
+  smtp.c             \
+  socketpair.c       \
+  socks.c            \
+  socks_gssapi.c     \
+  socks_sspi.c       \
+  speedcheck.c       \
+  splay.c            \
+  strcase.c          \
+  strdup.c           \
+  strerror.c         \
+  strtok.c           \
+  strtoofft.c        \
+  system_win32.c     \
+  telnet.c           \
+  tftp.c             \
+  timeval.c          \
+  transfer.c         \
+  url.c              \
+  urlapi.c           \
+  version.c          \
+  version_win32.c    \
+  warnless.c         \
+  wildcard.c         \
+  x509asn1.c
 
-LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h    \
-  content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h      \
-  curl_des.h curl_endian.h curl_fnmatch.h curl_get_line.h curl_gethostname.h  \
-  curl_gssapi.h curl_hmac.h curl_ldap.h curl_md4.h curl_md5.h curl_memory.h   \
-  curl_memrchr.h curl_multibyte.h curl_ntlm_core.h curl_ntlm_wb.h curl_path.h \
-  curl_printf.h curl_range.h curl_rtmp.h curl_sasl.h curl_sec.h curl_setup.h  \
-  curl_setup_once.h curl_sha256.h curl_sspi.h curl_threads.h curlx.h dict.h   \
-  dotdot.h easyif.h escape.h file.h fileinfo.h formdata.h ftp.h url.h         \
-  ftplistparser.h getinfo.h gopher.h hash.h hostcheck.h hostip.h http.h       \
-  http2.h http_chunks.h http_digest.h http_negotiate.h http_ntlm.h            \
-  http_proxy.h if2ip.h imap.h inet_ntop.h inet_pton.h llist.h memdebug.h      \
-  mime.h mqtt.h multihandle.h multiif.h netrc.h non-ascii.h nonblock.h        \
-  parsedate.h pingpong.h pop3.h progress.h psl.h doh.h quic.h rand.h rename.h \
-  rtsp.h select.h sendf.h setopt.h setup-vms.h share.h sigpipe.h slist.h      \
-  smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \
-  strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h     \
-  timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h           \
-  x509asn1.h dynbuf.h version_win32.h
+LIB_HFILES =         \
+  altsvc.h           \
+  amigaos.h          \
+  arpa_telnet.h      \
+  asyn.h             \
+  c-hyper.h          \
+  conncache.h        \
+  connect.h          \
+  content_encoding.h \
+  cookie.h           \
+  curl_addrinfo.h    \
+  curl_base64.h      \
+  curl_ctype.h       \
+  curl_des.h         \
+  curl_endian.h      \
+  curl_fnmatch.h     \
+  curl_get_line.h    \
+  curl_gethostname.h \
+  curl_gssapi.h      \
+  curl_hmac.h        \
+  curl_krb5.h        \
+  curl_ldap.h        \
+  curl_md4.h         \
+  curl_md5.h         \
+  curl_memory.h      \
+  curl_memrchr.h     \
+  curl_multibyte.h   \
+  curl_ntlm_core.h   \
+  curl_ntlm_wb.h     \
+  curl_path.h        \
+  curl_printf.h      \
+  curl_range.h       \
+  curl_rtmp.h        \
+  curl_sasl.h        \
+  curl_setup.h       \
+  curl_setup_once.h  \
+  curl_sha256.h      \
+  curl_sspi.h        \
+  curl_threads.h     \
+  curlx.h            \
+  dict.h             \
+  doh.h              \
+  dotdot.h           \
+  dynbuf.h           \
+  easyif.h           \
+  easyoptions.h      \
+  escape.h           \
+  file.h             \
+  fileinfo.h         \
+  formdata.h         \
+  ftp.h              \
+  ftplistparser.h    \
+  getinfo.h          \
+  gopher.h           \
+  hash.h             \
+  hostcheck.h        \
+  hostip.h           \
+  hsts.h             \
+  http.h             \
+  http2.h            \
+  http_chunks.h      \
+  http_digest.h      \
+  http_negotiate.h   \
+  http_ntlm.h        \
+  http_proxy.h       \
+  http_aws_sigv4.h   \
+  if2ip.h            \
+  imap.h             \
+  inet_ntop.h        \
+  inet_pton.h        \
+  llist.h            \
+  memdebug.h         \
+  mime.h             \
+  mqtt.h             \
+  multihandle.h      \
+  multiif.h          \
+  netrc.h            \
+  non-ascii.h        \
+  nonblock.h         \
+  parsedate.h        \
+  pingpong.h         \
+  pop3.h             \
+  progress.h         \
+  psl.h              \
+  quic.h             \
+  rand.h             \
+  rename.h           \
+  rtsp.h             \
+  select.h           \
+  sendf.h            \
+  setopt.h           \
+  setup-vms.h        \
+  share.h            \
+  sigpipe.h          \
+  slist.h            \
+  smb.h              \
+  smtp.h             \
+  sockaddr.h         \
+  socketpair.h       \
+  socks.h            \
+  speedcheck.h       \
+  splay.h            \
+  strcase.h          \
+  strdup.h           \
+  strerror.h         \
+  strtok.h           \
+  strtoofft.h        \
+  system_win32.h     \
+  telnet.h           \
+  tftp.h             \
+  timeval.h          \
+  transfer.h         \
+  url.h              \
+  urlapi-int.h       \
+  urldata.h          \
+  version_win32.h    \
+  warnless.h         \
+  wildcard.h         \
+  x509asn1.h
 
 LIB_RCFILES = libcurl.rc
 
index c2ec489..4ab77fd 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -25,7 +25,7 @@
  */
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
 #include <curl/curl.h>
 #include "urldata.h"
 #include "altsvc.h"
@@ -302,11 +302,12 @@ CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
  * Curl_altsvc_cleanup() frees an altsvc cache instance and all associated
  * resources.
  */
-void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
+void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
 {
-  struct curl_llist_element *e;
-  struct curl_llist_element *n;
-  if(altsvc) {
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+  if(*altsvcp) {
+    struct altsvcinfo *altsvc = *altsvcp;
     for(e = altsvc->list.head; e; e = n) {
       struct altsvc *as = e->ptr;
       n = e->next;
@@ -314,6 +315,7 @@ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
     }
     free(altsvc->filename);
     free(altsvc);
+    *altsvcp = NULL; /* clear the pointer */
   }
 }
 
@@ -323,8 +325,8 @@ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
 CURLcode Curl_altsvc_save(struct Curl_easy *data,
                           struct altsvcinfo *altsvc, const char *file)
 {
-  struct curl_llist_element *e;
-  struct curl_llist_element *n;
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
   CURLcode result = CURLE_OK;
   FILE *out;
   char *tempstore;
@@ -353,7 +355,7 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
   if(!out)
     result = CURLE_WRITE_ERROR;
   else {
-    fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n"
+    fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
           "# This file was generated by libcurl! Edit at your own risk.\n",
           out);
     for(e = altsvc->list.head; e; e = n) {
@@ -399,8 +401,8 @@ static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
 static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
                          const char *srchost, unsigned short srcport)
 {
-  struct curl_llist_element *e;
-  struct curl_llist_element *n;
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
   for(e = asi->list.head; e; e = n) {
     struct altsvc *as = e->ptr;
     n = e->next;
@@ -449,12 +451,14 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
 {
   const char *p = value;
   size_t len;
-  enum alpnid dstalpnid = srcalpnid; /* the same by default */
   char namebuf[MAX_ALTSVC_HOSTLEN] = "";
   char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
   struct altsvc *as;
   unsigned short dstport = srcport; /* the same by default */
   CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
   if(result) {
     infof(data, "Excessive alt-svc header, ignoring...\n");
     return CURLE_OK;
@@ -473,7 +477,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
   do {
     if(*p == '=') {
       /* [protocol]="[host][:port]" */
-      dstalpnid = alpn2alpnid(alpnbuf);
+      enum alpnid dstalpnid = alpn2alpnid(alpnbuf); /* the same by default */
       p++;
       if(*p == '\"') {
         const char *dsthost = "";
@@ -612,8 +616,8 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
                         struct altsvc **dstentry,
                         const int versions) /* one or more bits */
 {
-  struct curl_llist_element *e;
-  struct curl_llist_element *n;
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
   time_t now = time(NULL);
   DEBUGASSERT(asi);
   DEBUGASSERT(srchost);
@@ -640,4 +644,4 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
   return FALSE;
 }
 
-#endif /* CURL_DISABLE_HTTP || USE_ALTSVC */
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
index 578a4fb..2ab89e7 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -23,7 +23,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_ALTSVC)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
 #include <curl/curl.h>
 #include "llist.h"
 
@@ -46,12 +46,12 @@ struct altsvc {
   time_t expires;
   bool persist;
   int prio;
-  struct curl_llist_element node;
+  struct Curl_llist_element node;
 };
 
 struct altsvcinfo {
   char *filename;
-  struct curl_llist list; /* list of entries */
+  struct Curl_llist list; /* list of entries */
   long flags; /* the publicly set bitmask */
 };
 
@@ -61,7 +61,7 @@ CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file);
 CURLcode Curl_altsvc_save(struct Curl_easy *data,
                           struct altsvcinfo *asi, const char *file);
 CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl);
-void Curl_altsvc_cleanup(struct altsvcinfo *altsvc);
+void Curl_altsvc_cleanup(struct altsvcinfo **altsvc);
 CURLcode Curl_altsvc_parse(struct Curl_easy *data,
                            struct altsvcinfo *altsvc, const char *value,
                            enum alpnid srcalpn, const char *srchost,
@@ -74,5 +74,6 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
 #else
 /* disabled */
 #define Curl_altsvc_save(a,b,c)
-#endif /* CURL_DISABLE_HTTP || USE_ALTSVC */
+#define Curl_altsvc_cleanup(x)
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
 #endif /* HEADER_CURL_ALTSVC_H */
index cf44bdc..d3b00d9 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index c776c9c..02e5bb5 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 232680e..cbe31de 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index e651507..2484a7b 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -67,8 +67,8 @@
 #include "select.h"
 #include "progress.h"
 
-#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
-     (defined(WIN32) || defined(__SYMBIAN32__))
+#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
+  defined(WIN32)
 #    define CARES_STATICLIB
 #  endif
 #  include <ares.h>
@@ -85,7 +85,7 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-struct ResolverResults {
+struct thread_data {
   int num_pending; /* number of ares_gethostbyname() requests */
   struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
                                     parts */
@@ -133,8 +133,8 @@ void Curl_resolver_global_cleanup(void)
 }
 
 
-static void Curl_ares_sock_state_cb(void *data, ares_socket_t socket_fd,
-                                    int readable, int writable)
+static void sock_state_cb(void *data, ares_socket_t socket_fd,
+                          int readable, int writable)
 {
   struct Curl_easy *easy = data;
   if(!readable && !writable) {
@@ -155,7 +155,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
   int status;
   struct ares_options options;
   int optmask = ARES_OPT_SOCK_STATE_CB;
-  options.sock_state_cb = Curl_ares_sock_state_cb;
+  options.sock_state_cb = sock_state_cb;
   options.sock_state_cb_data = easy;
   status = ares_init_options((ares_channel*)resolver, &options, optmask);
   if(status != ARES_SUCCESS) {
@@ -204,22 +204,22 @@ static void destroy_async_data(struct Curl_async *async);
 /*
  * Cancel all possibly still on-going resolves for this connection.
  */
-void Curl_resolver_cancel(struct connectdata *conn)
+void Curl_resolver_cancel(struct Curl_easy *data)
 {
-  if(conn->data && conn->data->state.resolver)
-    ares_cancel((ares_channel)conn->data->state.resolver);
-  destroy_async_data(&conn->async);
+  if(data && data->state.async.resolver)
+    ares_cancel((ares_channel)data->state.async.resolver);
+  destroy_async_data(&data->state.async);
 }
 
 /*
  * We're equivalent to Curl_resolver_cancel() for the c-ares resolver.  We
  * never block.
  */
-void Curl_resolver_kill(struct connectdata *conn)
+void Curl_resolver_kill(struct Curl_easy *data)
 {
   /* We don't need to check the resolver state because we can be called safely
      at any time and we always do the same thing. */
-  Curl_resolver_cancel(conn);
+  Curl_resolver_cancel(data);
 }
 
 /*
@@ -229,8 +229,8 @@ static void destroy_async_data(struct Curl_async *async)
 {
   free(async->hostname);
 
-  if(async->os_specific) {
-    struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
+  if(async->tdata) {
+    struct thread_data *res = async->tdata;
     if(res) {
       if(res->temp_ai) {
         Curl_freeaddrinfo(res->temp_ai);
@@ -238,7 +238,7 @@ static void destroy_async_data(struct Curl_async *async)
       }
       free(res);
     }
-    async->os_specific = NULL;
+    async->tdata = NULL;
   }
 
   async->hostname = NULL;
@@ -253,25 +253,25 @@ static void destroy_async_data(struct Curl_async *async)
  * Returns: sockets-in-use-bitmap
  */
 
-int Curl_resolver_getsock(struct connectdata *conn,
+int Curl_resolver_getsock(struct Curl_easy *data,
                           curl_socket_t *socks)
 {
   struct timeval maxtime;
   struct timeval timebuf;
   struct timeval *timeout;
   long milli;
-  int max = ares_getsock((ares_channel)conn->data->state.resolver,
+  int max = ares_getsock((ares_channel)data->state.async.resolver,
                          (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
 
   maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
   maxtime.tv_usec = 0;
 
-  timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
+  timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
                          &timebuf);
   milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
   if(milli == 0)
     milli += 10;
-  Curl_expire(conn->data, milli, EXPIRE_ASYNC_NAME);
+  Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
 
   return max;
 }
@@ -286,9 +286,8 @@ int Curl_resolver_getsock(struct connectdata *conn,
  * return number of sockets it worked on
  */
 
-static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
+static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
 {
-  struct Curl_easy *data = conn->data;
   int nfds;
   int bitmask;
   ares_socket_t socks[ARES_GETSOCK_MAXNUM];
@@ -296,7 +295,7 @@ static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
   int i;
   int num = 0;
 
-  bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
+  bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
                          ARES_GETSOCK_MAXNUM);
 
   for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
@@ -324,12 +323,12 @@ static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
   if(!nfds)
     /* Call ares_process() unconditonally here, even if we simply timed out
        above, as otherwise the ares name resolve won't timeout! */
-    ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
+    ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
                     ARES_SOCKET_BAD);
   else {
     /* move through the descriptors and ask for processing on them */
     for(i = 0; i < num; i++)
-      ares_process_fd((ares_channel)data->state.resolver,
+      ares_process_fd((ares_channel)data->state.async.resolver,
                       (pfd[i].revents & (POLLRDNORM|POLLIN))?
                       pfd[i].fd:ARES_SOCKET_BAD,
                       (pfd[i].revents & (POLLWRNORM|POLLOUT))?
@@ -345,18 +344,16 @@ static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
  *
  * Returns normal CURLcode errors.
  */
-CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **dns)
 {
-  struct Curl_easy *data = conn->data;
-  struct ResolverResults *res = (struct ResolverResults *)
-    conn->async.os_specific;
+  struct thread_data *res = data->state.async.tdata;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(dns);
   *dns = NULL;
 
-  waitperform(conn, 0);
+  waitperform(data, 0);
 
   /* Now that we've checked for any last minute results above, see if there are
      any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
@@ -377,26 +374,27 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
        ARES_ECANCELLED synchronously for all pending responses.  This will
        leave us with res->num_pending == 0, which is perfect for the next
        block. */
-    ares_cancel((ares_channel)data->state.resolver);
+    ares_cancel((ares_channel)data->state.async.resolver);
     DEBUGASSERT(res->num_pending == 0);
   }
 
   if(res && !res->num_pending) {
-    (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
+    (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
     /* temp_ai ownership is moved to the connection, so we need not free-up
        them */
     res->temp_ai = NULL;
 
-    if(!conn->async.dns) {
+    if(!data->state.async.dns) {
       failf(data, "Could not resolve: %s (%s)",
-            conn->async.hostname, ares_strerror(conn->async.status));
-      result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
+            data->state.async.hostname,
+            ares_strerror(data->state.async.status));
+      result = data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
         CURLE_COULDNT_RESOLVE_HOST;
     }
     else
-      *dns = conn->async.dns;
+      *dns = data->state.async.dns;
 
-    destroy_async_data(&conn->async);
+    destroy_async_data(&data->state.async);
   }
 
   return result;
@@ -413,11 +411,10 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
  */
-CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   timediff_t timeout;
   struct curltime now = Curl_now();
 
@@ -427,7 +424,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
   timeout = Curl_timeleft(data, &now, TRUE);
   if(timeout < 0) {
     /* already expired! */
-    connclose(conn, "Timed out before name resolve started");
+    connclose(data->conn, "Timed out before name resolve started");
     return CURLE_OPERATION_TIMEDOUT;
   }
   if(!timeout)
@@ -448,7 +445,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
     store.tv_sec = itimeout/1000;
     store.tv_usec = (itimeout%1000)*1000;
 
-    tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
+    tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
 
     /* use the timeout period ares returned to us above if less than one
        second is left, otherwise just use 1000ms to make sure the progress
@@ -458,13 +455,13 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
     else
       timeout_ms = 1000;
 
-    waitperform(conn, timeout_ms);
-    result = Curl_resolver_is_resolved(conn, entry);
+    waitperform(data, timeout_ms);
+    result = Curl_resolver_is_resolved(data, entry);
 
-    if(result || conn->async.done)
+    if(result || data->state.async.done)
       break;
 
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else {
       struct curltime now2 = Curl_now();
@@ -482,23 +479,23 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
   }
   if(result)
     /* failure, so we cancel the ares operation */
-    ares_cancel((ares_channel)data->state.resolver);
+    ares_cancel((ares_channel)data->state.async.resolver);
 
   /* Operation complete, if the lookup was successful we now have the entry
      in the cache. */
   if(entry)
-    *entry = conn->async.dns;
+    *entry = data->state.async.dns;
 
   if(result)
     /* close the connection, since we can't return failure here without
        cleaning up this connection properly. */
-    connclose(conn, "c-ares resolve failed");
+    connclose(data->conn, "c-ares resolve failed");
 
   return result;
 }
 
 /* Connects results to the list */
-static void compound_results(struct ResolverResults *res,
+static void compound_results(struct thread_data *res,
                              struct Curl_addrinfo *ai)
 {
   struct Curl_addrinfo *ai_tail;
@@ -526,8 +523,8 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
 #endif
                                struct hostent *hostent)
 {
-  struct connectdata *conn = (struct connectdata *)arg;
-  struct ResolverResults *res;
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct thread_data *res;
 
 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
   (void)timeouts; /* ignored */
@@ -538,12 +535,12 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
        be valid so only defer it when we know the 'status' says its fine! */
     return;
 
-  res = (struct ResolverResults *)conn->async.os_specific;
+  res = data->state.async.tdata;
   if(res) {
     res->num_pending--;
 
     if(CURL_ASYNC_SUCCESS == status) {
-      struct Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
+      struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
       if(ai) {
         compound_results(res, ai);
       }
@@ -608,8 +605,8 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
          c-ares retry cycle each request is.
       */
       res->happy_eyeballs_dns_time = Curl_now();
-      Curl_expire(
-        conn->data, HAPPY_EYEBALLS_DNS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS_DNS);
+      Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
+                  EXPIRE_HAPPY_EYEBALLS_DNS);
     }
   }
 }
@@ -622,19 +619,18 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
  * memory we need to free after use. That memory *MUST* be freed with
  * Curl_freeaddrinfo(), nothing else.
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp)
 {
   char *bufp;
-  struct Curl_easy *data = conn->data;
   int family = PF_INET;
 
   *waitp = 0; /* default to synchronous response */
 
 #ifdef ENABLE_IPV6
-  switch(conn->ip_version) {
+  switch(data->set.ipver) {
   default:
 #if ARES_VERSION >= 0x010601
     family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
@@ -653,40 +649,40 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 
   bufp = strdup(hostname);
   if(bufp) {
-    struct ResolverResults *res = NULL;
-    free(conn->async.hostname);
-    conn->async.hostname = bufp;
-    conn->async.port = port;
-    conn->async.done = FALSE;   /* not done */
-    conn->async.status = 0;     /* clear */
-    conn->async.dns = NULL;     /* clear */
-    res = calloc(sizeof(struct ResolverResults), 1);
+    struct thread_data *res = NULL;
+    free(data->state.async.hostname);
+    data->state.async.hostname = bufp;
+    data->state.async.port = port;
+    data->state.async.done = FALSE;   /* not done */
+    data->state.async.status = 0;     /* clear */
+    data->state.async.dns = NULL;     /* clear */
+    res = calloc(sizeof(struct thread_data), 1);
     if(!res) {
-      free(conn->async.hostname);
-      conn->async.hostname = NULL;
+      free(data->state.async.hostname);
+      data->state.async.hostname = NULL;
       return NULL;
     }
-    conn->async.os_specific = res;
+    data->state.async.tdata = res;
 
     /* initial status - failed */
     res->last_status = ARES_ENOTFOUND;
 #ifdef ENABLE_IPV6
     if(family == PF_UNSPEC) {
-      if(Curl_ipv6works(conn)) {
+      if(Curl_ipv6works(data)) {
         res->num_pending = 2;
 
         /* areschannel is already setup in the Curl_open() function */
-        ares_gethostbyname((ares_channel)data->state.resolver, hostname,
-                            PF_INET, query_completed_cb, conn);
-        ares_gethostbyname((ares_channel)data->state.resolver, hostname,
-                            PF_INET6, query_completed_cb, conn);
+        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                            PF_INET, query_completed_cb, data);
+        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                            PF_INET6, query_completed_cb, data);
       }
       else {
         res->num_pending = 1;
 
         /* areschannel is already setup in the Curl_open() function */
-        ares_gethostbyname((ares_channel)data->state.resolver, hostname,
-                            PF_INET, query_completed_cb, conn);
+        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                            PF_INET, query_completed_cb, data);
       }
     }
     else
@@ -695,8 +691,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
       res->num_pending = 1;
 
       /* areschannel is already setup in the Curl_open() function */
-      ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
-                         query_completed_cb, conn);
+      ares_gethostbyname((ares_channel)data->state.async.resolver,
+                         hostname, family,
+                         query_completed_cb, data);
     }
 
     *waitp = 1; /* expect asynchronous response */
@@ -721,9 +718,10 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
 
 #if (ARES_VERSION >= 0x010704)
 #if (ARES_VERSION >= 0x010b00)
-  ares_result = ares_set_servers_ports_csv(data->state.resolver, servers);
+  ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
+                                           servers);
 #else
-  ares_result = ares_set_servers_csv(data->state.resolver, servers);
+  ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
 #endif
   switch(ares_result) {
   case ARES_SUCCESS:
@@ -753,7 +751,7 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
   if(!interf)
     interf = "";
 
-  ares_set_local_dev((ares_channel)data->state.resolver, interf);
+  ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
 
   return CURLE_OK;
 #else /* c-ares version too old! */
@@ -778,7 +776,8 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
     }
   }
 
-  ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr));
+  ares_set_local_ip4((ares_channel)data->state.async.resolver,
+                     ntohl(a4.s_addr));
 
   return CURLE_OK;
 #else /* c-ares version too old! */
@@ -804,7 +803,7 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
     }
   }
 
-  ares_set_local_ip6((ares_channel)data->state.resolver, a6);
+  ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
 
   return CURLE_OK;
 #else /* c-ares version too old! */
index a60f4f0..9fcbc3c 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -145,13 +145,13 @@ static void destroy_async_data(struct Curl_async *);
 /*
  * Cancel all possibly still on-going resolves for this connection.
  */
-void Curl_resolver_cancel(struct connectdata *conn)
+void Curl_resolver_cancel(struct Curl_easy *data)
 {
-  destroy_async_data(&conn->async);
+  destroy_async_data(&data->state.async);
 }
 
 /* This function is used to init a threaded resolve */
-static bool init_resolve_thread(struct connectdata *conn,
+static bool init_resolve_thread(struct Curl_easy *data,
                                 const char *hostname, int port,
                                 const struct addrinfo *hints);
 
@@ -160,12 +160,11 @@ static bool init_resolve_thread(struct connectdata *conn,
 struct thread_sync_data {
   curl_mutex_t *mtx;
   int done;
-
+  int port;
   char *hostname;        /* hostname to resolve, Curl_async.hostname
                             duplicate */
-  int port;
 #ifdef USE_SOCKETPAIR
-  struct connectdata *conn;
+  struct Curl_easy *data;
   curl_socket_t sock_pair[2]; /* socket pair */
 #endif
   int sock_error;
@@ -183,9 +182,9 @@ struct thread_data {
   struct thread_sync_data tsd;
 };
 
-static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
+static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
 {
-  return &(((struct thread_data *)conn->async.os_specific)->tsd);
+  return &(data->state.async.tdata->tsd);
 }
 
 /* Destroy resolver thread synchronization data */
@@ -269,12 +268,12 @@ int init_thread_sync_data(struct thread_data *td,
   return 0;
 }
 
-static int getaddrinfo_complete(struct connectdata *conn)
+static int getaddrinfo_complete(struct Curl_easy *data)
 {
-  struct thread_sync_data *tsd = conn_thread_sync_data(conn);
+  struct thread_sync_data *tsd = conn_thread_sync_data(data);
   int rc;
 
-  rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
+  rc = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
   /* The tsd->res structure has been copied to async.dns and perhaps the DNS
      cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
   */
@@ -294,7 +293,7 @@ static int getaddrinfo_complete(struct connectdata *conn)
  */
 static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
 {
-  struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
+  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
   struct thread_data *td = tsd->td;
   char service[12];
   int rc;
@@ -380,12 +379,12 @@ static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
  */
 static void destroy_async_data(struct Curl_async *async)
 {
-  if(async->os_specific) {
-    struct thread_data *td = (struct thread_data*) async->os_specific;
+  if(async->tdata) {
+    struct thread_data *td = async->tdata;
     int done;
 #ifdef USE_SOCKETPAIR
     curl_socket_t sock_rd = td->tsd.sock_pair[0];
-    struct connectdata *conn = td->tsd.conn;
+    struct Curl_easy *data = td->tsd.data;
 #endif
 
     /*
@@ -406,19 +405,18 @@ static void destroy_async_data(struct Curl_async *async)
 
       destroy_thread_sync_data(&td->tsd);
 
-      free(async->os_specific);
+      free(async->tdata);
     }
 #ifdef USE_SOCKETPAIR
     /*
      * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
      * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
      */
-    if(conn)
-      Curl_multi_closed(conn->data, sock_rd);
+    Curl_multi_closed(data, sock_rd);
     sclose(sock_rd);
 #endif
   }
-  async->os_specific = NULL;
+  async->tdata = NULL;
 
   free(async->hostname);
   async->hostname = NULL;
@@ -430,32 +428,33 @@ static void destroy_async_data(struct Curl_async *async)
  *
  * Returns FALSE in case of failure, otherwise TRUE.
  */
-static bool init_resolve_thread(struct connectdata *conn,
+static bool init_resolve_thread(struct Curl_easy *data,
                                 const char *hostname, int port,
                                 const struct addrinfo *hints)
 {
   struct thread_data *td = calloc(1, sizeof(struct thread_data));
   int err = ENOMEM;
+  struct Curl_async *asp = &data->state.async;
 
-  conn->async.os_specific = (void *)td;
+  data->state.async.tdata = td;
   if(!td)
     goto errno_exit;
 
-  conn->async.port = port;
-  conn->async.done = FALSE;
-  conn->async.status = 0;
-  conn->async.dns = NULL;
+  asp->port = port;
+  asp->done = FALSE;
+  asp->status = 0;
+  asp->dns = NULL;
   td->thread_hnd = curl_thread_t_null;
 
   if(!init_thread_sync_data(td, hostname, port, hints)) {
-    conn->async.os_specific = NULL;
+    asp->tdata = NULL;
     free(td);
     goto errno_exit;
   }
 
-  free(conn->async.hostname);
-  conn->async.hostname = strdup(hostname);
-  if(!conn->async.hostname)
+  free(asp->hostname);
+  asp->hostname = strdup(hostname);
+  if(!asp->hostname)
     goto err_exit;
 
   /* The thread will set this to 1 when complete. */
@@ -477,7 +476,7 @@ static bool init_resolve_thread(struct connectdata *conn,
   return TRUE;
 
  err_exit:
-  destroy_async_data(&conn->async);
+  destroy_async_data(asp);
 
  errno_exit:
   errno = err;
@@ -489,12 +488,13 @@ static bool init_resolve_thread(struct connectdata *conn,
  * error
  */
 
-static CURLcode resolver_error(struct connectdata *conn)
+static CURLcode resolver_error(struct Curl_easy *data)
 {
   const char *host_or_proxy;
   CURLcode result;
 
 #ifndef CURL_DISABLE_PROXY
+  struct connectdata *conn = data->conn;
   if(conn->bits.httpproxy) {
     host_or_proxy = "proxy";
     result = CURLE_COULDNT_RESOLVE_PROXY;
@@ -506,8 +506,8 @@ static CURLcode resolver_error(struct connectdata *conn)
     result = CURLE_COULDNT_RESOLVE_HOST;
   }
 
-  failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
-        conn->async.hostname);
+  failf(data, "Could not resolve %s: %s", host_or_proxy,
+        data->state.async.hostname);
 
   return result;
 }
@@ -515,37 +515,39 @@ static CURLcode resolver_error(struct connectdata *conn)
 /*
  * 'entry' may be NULL and then no data is returned
  */
-static CURLcode thread_wait_resolv(struct connectdata *conn,
+static CURLcode thread_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry,
                                    bool report)
 {
-  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
+  struct thread_data *td;
   CURLcode result = CURLE_OK;
 
-  DEBUGASSERT(conn && td);
+  DEBUGASSERT(data);
+  td = data->state.async.tdata;
+  DEBUGASSERT(td);
   DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
 
   /* wait for the thread to resolve the name */
   if(Curl_thread_join(&td->thread_hnd)) {
     if(entry)
-      result = getaddrinfo_complete(conn);
+      result = getaddrinfo_complete(data);
   }
   else
     DEBUGASSERT(0);
 
-  conn->async.done = TRUE;
+  data->state.async.done = TRUE;
 
   if(entry)
-    *entry = conn->async.dns;
+    *entry = data->state.async.dns;
 
-  if(!conn->async.dns && report)
+  if(!data->state.async.dns && report)
     /* a name was not resolved, report error */
-    result = resolver_error(conn);
+    result = resolver_error(data);
 
-  destroy_async_data(&conn->async);
+  destroy_async_data(&data->state.async);
 
-  if(!conn->async.dns && report)
-    connclose(conn, "asynch resolve failed");
+  if(!data->state.async.dns && report)
+    connclose(data->conn, "asynch resolve failed");
 
   return result;
 }
@@ -555,17 +557,17 @@ static CURLcode thread_wait_resolv(struct connectdata *conn,
  * Until we gain a way to signal the resolver threads to stop early, we must
  * simply wait for them and ignore their results.
  */
-void Curl_resolver_kill(struct connectdata *conn)
+void Curl_resolver_kill(struct Curl_easy *data)
 {
-  struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+  struct thread_data *td = data->state.async.tdata;
 
   /* If we're still resolving, we must wait for the threads to fully clean up,
      unfortunately.  Otherwise, we can simply cancel to clean up any resolver
      data. */
   if(td && td->thread_hnd != curl_thread_t_null)
-    (void)thread_wait_resolv(conn, NULL, FALSE);
+    (void)thread_wait_resolv(data, NULL, FALSE);
   else
-    Curl_resolver_cancel(conn);
+    Curl_resolver_cancel(data);
 }
 
 /*
@@ -581,10 +583,10 @@ void Curl_resolver_kill(struct connectdata *conn)
  *
  * This is the version for resolves-in-a-thread.
  */
-CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
 {
-  return thread_wait_resolv(conn, entry, TRUE);
+  return thread_wait_resolv(data, entry, TRUE);
 }
 
 /*
@@ -592,11 +594,10 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
  * name resolve request has completed. It should also make sure to time-out if
  * the operation seems to take too long.
  */
-CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
 {
-  struct Curl_easy *data = conn->data;
-  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
+  struct thread_data *td = data->state.async.tdata;
   int done = 0;
 
   DEBUGASSERT(entry);
@@ -612,15 +613,15 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
   Curl_mutex_release(td->tsd.mtx);
 
   if(done) {
-    getaddrinfo_complete(conn);
+    getaddrinfo_complete(data);
 
-    if(!conn->async.dns) {
-      CURLcode result = resolver_error(conn);
-      destroy_async_data(&conn->async);
+    if(!data->state.async.dns) {
+      CURLcode result = resolver_error(data);
+      destroy_async_data(&data->state.async);
       return result;
     }
-    destroy_async_data(&conn->async);
-    *entry = conn->async.dns;
+    destroy_async_data(&data->state.async);
+    *entry = data->state.async.dns;
   }
   else {
     /* poll for name lookup done with exponential backoff up to 250ms */
@@ -641,22 +642,20 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
       td->poll_interval = 250;
 
     td->interval_end = elapsed + td->poll_interval;
-    Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME);
+    Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
   }
 
   return CURLE_OK;
 }
 
-int Curl_resolver_getsock(struct connectdata *conn,
-                          curl_socket_t *socks)
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
 {
   int ret_val = 0;
   timediff_t milli;
   timediff_t ms;
-  struct Curl_easy *data = conn->data;
-  struct resdata *reslv = (struct resdata *)data->state.resolver;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
 #ifdef USE_SOCKETPAIR
-  struct thread_data *td = (struct thread_data*)conn->async.os_specific;
+  struct thread_data *td = data->state.async.tdata;
 #else
   (void)socks;
 #endif
@@ -665,8 +664,7 @@ int Curl_resolver_getsock(struct connectdata *conn,
   if(td) {
     /* return read fd to client for polling the DNS resolution status */
     socks[0] = td->tsd.sock_pair[0];
-    DEBUGASSERT(td->tsd.conn == conn || !td->tsd.conn);
-    td->tsd.conn = conn;
+    td->tsd.data = data;
     ret_val = GETSOCK_READSOCK(0);
   }
   else {
@@ -693,25 +691,24 @@ int Curl_resolver_getsock(struct connectdata *conn,
 /*
  * Curl_getaddrinfo() - for platforms without getaddrinfo
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp)
 {
-  struct Curl_easy *data = conn->data;
-  struct resdata *reslv = (struct resdata *)data->state.resolver;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
 
   *waitp = 0; /* default to synchronous response */
 
   reslv->start = Curl_now();
 
   /* fire up a new resolver thread! */
-  if(init_resolve_thread(conn, hostname, port, NULL)) {
+  if(init_resolve_thread(data, hostname, port, NULL)) {
     *waitp = 1; /* expect asynchronous response */
     return NULL;
   }
 
-  failf(conn->data, "getaddrinfo() thread failed\n");
+  failf(data, "getaddrinfo() thread failed");
 
   return NULL;
 }
@@ -721,15 +718,14 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 /*
  * Curl_resolver_getaddrinfo() - for getaddrinfo
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp)
 {
   struct addrinfo hints;
   int pf = PF_INET;
-  struct Curl_easy *data = conn->data;
-  struct resdata *reslv = (struct resdata *)data->state.resolver;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
 
   *waitp = 0; /* default to synchronous response */
 
@@ -737,7 +733,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
   /*
    * Check if a limited name resolve has been requested.
    */
-  switch(conn->ip_version) {
+  switch(data->set.ipver) {
   case CURL_IPRESOLVE_V4:
     pf = PF_INET;
     break;
@@ -749,24 +745,24 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
     break;
   }
 
-  if((pf != PF_INET) && !Curl_ipv6works(conn))
+  if((pf != PF_INET) && !Curl_ipv6works(data))
     /* The stack seems to be a non-IPv6 one */
     pf = PF_INET;
 #endif /* CURLRES_IPV6 */
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (conn->transport == TRNSPRT_TCP)?
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
     SOCK_STREAM : SOCK_DGRAM;
 
   reslv->start = Curl_now();
   /* fire up a new resolver thread! */
-  if(init_resolve_thread(conn, hostname, port, &hints)) {
+  if(init_resolve_thread(data, hostname, port, &hints)) {
     *waitp = 1; /* expect asynchronous response */
     return NULL;
   }
 
-  failf(data, "getaddrinfo() thread failed to start\n");
+  failf(data, "getaddrinfo() thread failed to start");
   return NULL;
 
 }
index bd3c3c1..3130395 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -91,7 +91,7 @@ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
  *
  * It is safe to call this when conn is in any state.
  */
-void Curl_resolver_cancel(struct connectdata *conn);
+void Curl_resolver_cancel(struct Curl_easy *data);
 
 /*
  * Curl_resolver_kill().
@@ -104,7 +104,7 @@ void Curl_resolver_cancel(struct connectdata *conn);
  *
  * It is safe to call this when conn is in any state.
  */
-void Curl_resolver_kill(struct connectdata *conn);
+void Curl_resolver_kill(struct Curl_easy *data);
 
 /* Curl_resolver_getsock()
  *
@@ -114,7 +114,7 @@ void Curl_resolver_kill(struct connectdata *conn);
  * return bitmask indicating what file descriptors (referring to array indexes
  * in the 'sock' array) to wait for, read/write.
  */
-int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock);
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *sock);
 
 /*
  * Curl_resolver_is_resolved()
@@ -125,7 +125,7 @@ int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock);
  *
  * Returns normal CURLcode errors.
  */
-CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **dns);
 
 /*
@@ -139,7 +139,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
  */
-CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **dnsentry);
 
 /*
@@ -153,7 +153,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
  * Each resolver backend must of course make sure to return data in the
  * correct format to comply with this.
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp);
index 643cef6..be6f163 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -26,6 +26,9 @@
 
 #if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
   !defined(CURL_DISABLE_LDAP) || \
+  !defined(CURL_DISABLE_SMTP) || \
+  !defined(CURL_DISABLE_POP3) || \
+  !defined(CURL_DISABLE_IMAP) || \
   !defined(CURL_DISABLE_DOH) || defined(USE_SSL)
 
 #include "urldata.h" /* for the Curl_easy definition */
diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c
new file mode 100644 (file)
index 0000000..10bd7ef
--- /dev/null
@@ -0,0 +1,908 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2021, 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.haxx.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.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include <hyper.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "transfer.h"
+#include "multiif.h"
+#include "progress.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
+                       uint8_t *buf, size_t buflen)
+{
+  struct Curl_easy *data = userp;
+  struct connectdata *conn = data->conn;
+  CURLcode result;
+  ssize_t nread;
+  DEBUGASSERT(conn);
+  (void)ctx;
+
+  result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
+  if(result == CURLE_AGAIN) {
+    /* would block, register interest */
+    if(data->hyp.read_waker)
+      hyper_waker_free(data->hyp.read_waker);
+    data->hyp.read_waker = hyper_context_waker(ctx);
+    if(!data->hyp.read_waker) {
+      failf(data, "Couldn't make the read hyper_context_waker");
+      return HYPER_IO_ERROR;
+    }
+    return HYPER_IO_PENDING;
+  }
+  else if(result) {
+    failf(data, "Curl_read failed");
+    return HYPER_IO_ERROR;
+  }
+  return (size_t)nread;
+}
+
+size_t Curl_hyper_send(void *userp, hyper_context *ctx,
+                       const uint8_t *buf, size_t buflen)
+{
+  struct Curl_easy *data = userp;
+  struct connectdata *conn = data->conn;
+  CURLcode result;
+  ssize_t nwrote;
+
+  result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
+  if(result == CURLE_AGAIN) {
+    /* would block, register interest */
+    if(data->hyp.write_waker)
+      hyper_waker_free(data->hyp.write_waker);
+    data->hyp.write_waker = hyper_context_waker(ctx);
+    if(!data->hyp.write_waker) {
+      failf(data, "Couldn't make the write hyper_context_waker");
+      return HYPER_IO_ERROR;
+    }
+    return HYPER_IO_PENDING;
+  }
+  else if(result) {
+    failf(data, "Curl_write failed");
+    return HYPER_IO_ERROR;
+  }
+  return (size_t)nwrote;
+}
+
+static int hyper_each_header(void *userdata,
+                             const uint8_t *name,
+                             size_t name_len,
+                             const uint8_t *value,
+                             size_t value_len)
+{
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  size_t len;
+  char *headp;
+  CURLcode result;
+  Curl_dyn_reset(&data->state.headerb);
+  if(name_len) {
+    if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
+                     (int) name_len, name, (int) value_len, value))
+      return HYPER_ITER_BREAK;
+  }
+  else {
+    if(Curl_dyn_add(&data->state.headerb, "\r\n"))
+      return HYPER_ITER_BREAK;
+  }
+  len = Curl_dyn_len(&data->state.headerb);
+  headp = Curl_dyn_ptr(&data->state.headerb);
+
+  result = Curl_http_header(data, data->conn, headp);
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
+
+  Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
+
+  result = Curl_client_write(data, CLIENTWRITE_HEADER, headp, len);
+  if(result) {
+    data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+    return HYPER_ITER_BREAK;
+  }
+
+  data->info.header_size += (long)len;
+  data->req.headerbytecount += (long)len;
+  return HYPER_ITER_CONTINUE;
+}
+
+static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
+{
+  char *buf = (char *)hyper_buf_bytes(chunk);
+  size_t len = hyper_buf_len(chunk);
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  struct SingleRequest *k = &data->req;
+  CURLcode result;
+
+  if(0 == k->bodywrites++) {
+    bool done = FALSE;
+    result = Curl_http_firstwrite(data, data->conn, &done);
+    if(result || done) {
+      infof(data, "Return early from hyper_body_chunk\n");
+      data->state.hresult = result;
+      return HYPER_ITER_BREAK;
+    }
+  }
+  if(k->ignorebody)
+    return HYPER_ITER_CONTINUE;
+  Curl_debug(data, CURLINFO_DATA_IN, buf, len);
+  result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
+
+  data->req.bytecount += len;
+  Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
+  return HYPER_ITER_CONTINUE;
+}
+
+/*
+ * Hyper does not consider the status line, the first line in a HTTP/1
+ * response, to be a header. The libcurl API does. This function sends the
+ * status line in the header callback. */
+static CURLcode status_line(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            uint16_t http_status,
+                            int http_version,
+                            const uint8_t *reason, size_t rlen)
+{
+  CURLcode result;
+  size_t wrote;
+  size_t len;
+  const char *vstr;
+  curl_write_callback writeheader =
+    data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
+  vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
+    (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
+  conn->httpversion =
+    http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
+    (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
+  data->req.httpcode = http_status;
+
+  result = Curl_http_statusline(data, conn);
+  if(result)
+    return result;
+
+  Curl_dyn_reset(&data->state.headerb);
+
+  result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
+                         vstr,
+                         (int)http_status,
+                         (int)rlen, reason);
+  if(result)
+    return result;
+  len = Curl_dyn_len(&data->state.headerb);
+  Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
+             len);
+  Curl_set_in_callback(data, true);
+  wrote = writeheader(Curl_dyn_ptr(&data->state.headerb), 1, len,
+                      data->set.writeheader);
+  Curl_set_in_callback(data, false);
+  if(wrote != len)
+    return CURLE_WRITE_ERROR;
+
+  data->info.header_size += (long)len;
+  data->req.headerbytecount += (long)len;
+  data->req.httpcode = http_status;
+  return CURLE_OK;
+}
+
+/*
+ * Hyper does not pass on the last empty response header. The libcurl API
+ * does. This function sends an empty header in the header callback.
+ */
+static CURLcode empty_header(struct Curl_easy *data)
+{
+  return hyper_each_header(data, NULL, 0, NULL, 0) ?
+    CURLE_WRITE_ERROR : CURLE_OK;
+}
+
+CURLcode Curl_hyper_stream(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           int *didwhat,
+                           bool *done,
+                           int select_res)
+{
+  hyper_response *resp = NULL;
+  uint16_t http_status;
+  int http_version;
+  hyper_headers *headers = NULL;
+  hyper_body *resp_body = NULL;
+  struct hyptransfer *h = &data->hyp;
+  hyper_task *task;
+  hyper_task *foreach;
+  hyper_error *hypererr = NULL;
+  const uint8_t *reasonp;
+  size_t reason_len;
+  CURLcode result = CURLE_OK;
+  (void)conn;
+
+  if(select_res & CURL_CSELECT_IN) {
+    if(h->read_waker)
+      hyper_waker_wake(h->read_waker);
+    h->read_waker = NULL;
+  }
+  if(select_res & CURL_CSELECT_OUT) {
+    if(h->write_waker)
+      hyper_waker_wake(h->write_waker);
+    h->write_waker = NULL;
+  }
+
+  *done = FALSE;
+  do {
+    hyper_task_return_type t;
+    task = hyper_executor_poll(h->exec);
+    if(!task) {
+      *didwhat = KEEP_RECV;
+      break;
+    }
+    t = hyper_task_type(task);
+    switch(t) {
+    case HYPER_TASK_ERROR:
+      hypererr = hyper_task_value(task);
+      break;
+    case HYPER_TASK_RESPONSE:
+      resp = hyper_task_value(task);
+      break;
+    default:
+      break;
+    }
+    hyper_task_free(task);
+
+    if(t == HYPER_TASK_ERROR) {
+      hyper_code errnum = hyper_error_code(hypererr);
+      if(errnum == HYPERE_ABORTED_BY_CALLBACK) {
+        /* override Hyper's view, might not even be an error */
+        result = data->state.hresult;
+        infof(data, "hyperstream is done (by early callback)\n");
+      }
+      else {
+        uint8_t errbuf[256];
+        size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+        hyper_code code = hyper_error_code(hypererr);
+        failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
+        if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
+          result = CURLE_GOT_NOTHING;
+        else
+          result = CURLE_RECV_ERROR;
+      }
+      *done = TRUE;
+      hyper_error_free(hypererr);
+      break;
+    }
+    else if(h->endtask == task) {
+      /* end of transfer */
+      *done = TRUE;
+      infof(data, "hyperstream is done!\n");
+      break;
+    }
+    else if(t != HYPER_TASK_RESPONSE) {
+      *didwhat = KEEP_RECV;
+      break;
+    }
+    /* HYPER_TASK_RESPONSE */
+
+    *didwhat = KEEP_RECV;
+    if(!resp) {
+      failf(data, "hyperstream: couldn't get response");
+      return CURLE_RECV_ERROR;
+    }
+
+    http_status = hyper_response_status(resp);
+    http_version = hyper_response_version(resp);
+    reasonp = hyper_response_reason_phrase(resp);
+    reason_len = hyper_response_reason_phrase_len(resp);
+
+    result = status_line(data, conn,
+                         http_status, http_version, reasonp, reason_len);
+    if(result)
+      break;
+
+    headers = hyper_response_headers(resp);
+    if(!headers) {
+      failf(data, "hyperstream: couldn't get response headers");
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+
+    /* the headers are already received */
+    hyper_headers_foreach(headers, hyper_each_header, data);
+    if(data->state.hresult) {
+      result = data->state.hresult;
+      break;
+    }
+
+    if(empty_header(data)) {
+      failf(data, "hyperstream: couldn't pass blank header");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+
+    /* Curl_http_auth_act() checks what authentication methods that are
+     * available and decides which one (if any) to use. It will set 'newurl'
+     * if an auth method was picked. */
+    result = Curl_http_auth_act(data);
+    if(result)
+      break;
+
+    resp_body = hyper_response_body(resp);
+    if(!resp_body) {
+      failf(data, "hyperstream: couldn't get response body");
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+    foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
+    if(!foreach) {
+      failf(data, "hyperstream: body foreach failed");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    DEBUGASSERT(hyper_task_type(foreach) == HYPER_TASK_EMPTY);
+    if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
+      failf(data, "Couldn't hyper_executor_push the body-foreach");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    h->endtask = foreach;
+
+    hyper_response_free(resp);
+    resp = NULL;
+  } while(1);
+  if(resp)
+    hyper_response_free(resp);
+  return result;
+}
+
+static CURLcode debug_request(struct Curl_easy *data,
+                              const char *method,
+                              const char *path,
+                              bool h2)
+{
+  char *req = aprintf("%s %s HTTP/%s\r\n", method, path,
+                      h2?"2":"1.1");
+  if(!req)
+    return CURLE_OUT_OF_MEMORY;
+  Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
+  free(req);
+  return CURLE_OK;
+}
+
+/*
+ * Given a full header line "name: value" (optional CRLF in the input, should
+ * be in the output), add to Hyper and send to the debug callback.
+ *
+ * Supports multiple headers.
+ */
+
+CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
+                           const char *line)
+{
+  const char *p;
+  const char *n;
+  size_t nlen;
+  const char *v;
+  size_t vlen;
+  bool newline = TRUE;
+  int numh = 0;
+
+  if(!line)
+    return CURLE_OK;
+  n = line;
+  do {
+    size_t linelen = 0;
+
+    p = strchr(n, ':');
+    if(!p)
+      /* this is fine if we already added at least one header */
+      return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
+    nlen = p - n;
+    p++; /* move past the colon */
+    while(*p == ' ')
+      p++;
+    v = p;
+    p = strchr(v, '\r');
+    if(!p) {
+      p = strchr(v, '\n');
+      if(p)
+        linelen = 1; /* LF only */
+      else {
+        p = strchr(v, '\0');
+        newline = FALSE; /* no newline */
+      }
+    }
+    else
+      linelen = 2; /* CRLF ending */
+    linelen += (p - n);
+    if(!n)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    vlen = p - v;
+
+    if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
+                                      (uint8_t *)v, vlen)) {
+      failf(data, "hyper_headers_add host");
+      return CURLE_OUT_OF_MEMORY;
+    }
+    if(data->set.verbose) {
+      char *ptr = NULL;
+      if(!newline) {
+        ptr = aprintf("%.*s\r\n", (int)linelen, line);
+        if(!ptr)
+          return CURLE_OUT_OF_MEMORY;
+        Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
+        free(ptr);
+      }
+      else
+        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)line, linelen);
+    }
+    numh++;
+    n += linelen;
+  } while(newline);
+  return CURLE_OK;
+}
+
+static CURLcode request_target(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               const char *method,
+                               bool h2,
+                               hyper_request *req)
+{
+  CURLcode result;
+  struct dynbuf r;
+
+  Curl_dyn_init(&r, DYN_HTTP_REQUEST);
+
+  result = Curl_http_target(data, conn, &r);
+  if(result)
+    return result;
+
+  if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
+                           Curl_dyn_len(&r))) {
+    failf(data, "error setting path");
+    result = CURLE_OUT_OF_MEMORY;
+  }
+  else
+    result = debug_request(data, method, Curl_dyn_ptr(&r), h2);
+
+  Curl_dyn_free(&r);
+
+  return result;
+}
+
+static int uploadpostfields(void *userdata, hyper_context *ctx,
+                            hyper_buf **chunk)
+{
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  (void)ctx;
+  if(data->req.upload_done)
+    *chunk = NULL; /* nothing more to deliver */
+  else {
+    /* send everything off in a single go */
+    *chunk = hyper_buf_copy(data->set.postfields,
+                            (size_t)data->req.p.http->postsize);
+    data->req.upload_done = TRUE;
+  }
+  return HYPER_POLL_READY;
+}
+
+static int uploadstreamed(void *userdata, hyper_context *ctx,
+                          hyper_buf **chunk)
+{
+  size_t fillcount;
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  CURLcode result =
+    Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
+  (void)ctx;
+  if(result)
+    return HYPER_POLL_ERROR;
+  if(!fillcount)
+    /* done! */
+    *chunk = NULL;
+  else
+    *chunk = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
+  return HYPER_POLL_READY;
+}
+
+/*
+ * bodysend() sets up headers in the outgoing request for a HTTP transfer that
+ * sends a body
+ */
+
+static CURLcode bodysend(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         hyper_headers *headers,
+                         hyper_request *hyperreq,
+                         Curl_HttpReq httpreq)
+{
+  CURLcode result = CURLE_OK;
+  struct dynbuf req;
+  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
+    Curl_pgrsSetUploadSize(data, 0); /* no request body */
+  else {
+    hyper_body *body;
+    Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+    result = Curl_http_bodysend(data, conn, &req, httpreq);
+
+    if(!result)
+      result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
+
+    Curl_dyn_free(&req);
+
+    body = hyper_body_new();
+    hyper_body_set_userdata(body, data);
+    if(data->set.postfields)
+      hyper_body_set_data_func(body, uploadpostfields);
+    else {
+      result = Curl_get_upload_buffer(data);
+      if(result)
+        return result;
+      /* init the "upload from here" pointer */
+      data->req.upload_fromhere = data->state.ulbuf;
+      hyper_body_set_data_func(body, uploadstreamed);
+    }
+    if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
+      /* fail */
+      hyper_body_free(body);
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+  return result;
+}
+
+static CURLcode cookies(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        hyper_headers *headers)
+{
+  struct dynbuf req;
+  CURLcode result;
+  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+
+  result = Curl_http_cookies(data, conn, &req);
+  if(!result)
+    result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
+  Curl_dyn_free(&req);
+  return result;
+}
+
+/*
+ * Curl_http() gets called from the generic multi_do() function when a HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct hyptransfer *h = &data->hyp;
+  hyper_io *io = NULL;
+  hyper_clientconn_options *options = NULL;
+  hyper_task *task = NULL; /* for the handshake */
+  hyper_task *sendtask = NULL; /* for the send */
+  hyper_clientconn *client = NULL;
+  hyper_request *req = NULL;
+  hyper_headers *headers = NULL;
+  hyper_task *handshake = NULL;
+  hyper_error *hypererr = NULL;
+  CURLcode result;
+  const char *p_accept; /* Accept: string */
+  const char *method;
+  Curl_HttpReq httpreq;
+  bool h2 = FALSE;
+  const char *te = NULL; /* transfer-encoding */
+
+  /* Always consider the DO phase done after this function call, even if there
+     may be parts of the request that is not yet sent, since we can deal with
+     the rest of the request in the PERFORM phase. */
+  *done = TRUE;
+
+  infof(data, "Time for the Hyper dance\n");
+  memset(h, 0, sizeof(struct hyptransfer));
+
+  result = Curl_http_host(data, conn);
+  if(result)
+    return result;
+
+  Curl_http_method(data, conn, &method, &httpreq);
+
+  /* setup the authentication headers */
+  {
+    char *pq = NULL;
+    if(data->state.up.query) {
+      pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
+      if(!pq)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    result = Curl_http_output_auth(data, conn, method, httpreq,
+                                   (pq ? pq : data->state.up.path), FALSE);
+    free(pq);
+    if(result)
+      return result;
+  }
+
+  result = Curl_http_resume(data, conn, httpreq);
+  if(result)
+    return result;
+
+  result = Curl_http_range(data, httpreq);
+  if(result)
+    return result;
+
+  result = Curl_http_useragent(data);
+  if(result)
+    return result;
+
+  io = hyper_io_new();
+  if(!io) {
+    failf(data, "Couldn't create hyper IO");
+    goto error;
+  }
+  /* tell Hyper how to read/write network data */
+  hyper_io_set_userdata(io, data);
+  hyper_io_set_read(io, Curl_hyper_recv);
+  hyper_io_set_write(io, Curl_hyper_send);
+
+  /* create an executor to poll futures */
+  if(!h->exec) {
+    h->exec = hyper_executor_new();
+    if(!h->exec) {
+      failf(data, "Couldn't create hyper executor");
+      goto error;
+    }
+  }
+
+  options = hyper_clientconn_options_new();
+  if(!options) {
+    failf(data, "Couldn't create hyper client options");
+    goto error;
+  }
+  if(conn->negnpn == CURL_HTTP_VERSION_2) {
+    hyper_clientconn_options_http2(options, 1);
+    h2 = TRUE;
+  }
+
+  hyper_clientconn_options_exec(options, h->exec);
+
+  /* "Both the `io` and the `options` are consumed in this function call" */
+  handshake = hyper_clientconn_handshake(io, options);
+  if(!handshake) {
+    failf(data, "Couldn't create hyper client handshake");
+    goto error;
+  }
+  io = NULL;
+  options = NULL;
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+    failf(data, "Couldn't hyper_executor_push the handshake");
+    goto error;
+  }
+  handshake = NULL; /* ownership passed on */
+
+  task = hyper_executor_poll(h->exec);
+  if(!task) {
+    failf(data, "Couldn't hyper_executor_poll the handshake");
+    goto error;
+  }
+
+  client = hyper_task_value(task);
+  hyper_task_free(task);
+
+  req = hyper_request_new();
+  if(!req) {
+    failf(data, "Couldn't hyper_request_new");
+    goto error;
+  }
+
+  if(data->set.httpversion == CURL_HTTP_VERSION_1_0) {
+    if(HYPERE_OK != hyper_request_set_version(req,
+                                              HYPER_HTTP_VERSION_1_0)) {
+      failf(data, "error setting HTTP version");
+      goto error;
+    }
+  }
+
+  if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
+    failf(data, "error setting method");
+    goto error;
+  }
+
+  result = request_target(data, conn, method, h2, req);
+  if(result)
+    goto error;
+
+  headers = hyper_request_headers(req);
+  if(!headers) {
+    failf(data, "hyper_request_headers");
+    goto error;
+  }
+
+  result = Curl_http_body(data, conn, httpreq, &te);
+  if(result)
+    return result;
+
+  if(data->state.aptr.host &&
+     Curl_hyper_header(data, headers, data->state.aptr.host))
+    goto error;
+
+  if(data->state.aptr.proxyuserpwd &&
+     Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
+    goto error;
+
+  if(data->state.aptr.userpwd &&
+     Curl_hyper_header(data, headers, data->state.aptr.userpwd))
+    goto error;
+
+  if((data->state.use_range && data->state.aptr.rangeline) &&
+     Curl_hyper_header(data, headers, data->state.aptr.rangeline))
+    goto error;
+
+  if(data->set.str[STRING_USERAGENT] &&
+     *data->set.str[STRING_USERAGENT] &&
+     data->state.aptr.uagent &&
+     Curl_hyper_header(data, headers, data->state.aptr.uagent))
+    goto error;
+
+  p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
+  if(p_accept && Curl_hyper_header(data, headers, p_accept))
+    goto error;
+
+  if(te && Curl_hyper_header(data, headers, te))
+    goto error;
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
+     !Curl_checkheaders(data, "Proxy-Connection") &&
+     !Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
+    if(Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
+      goto error;
+  }
+#endif
+
+  Curl_safefree(data->state.aptr.ref);
+  if(data->change.referer && !Curl_checkheaders(data, "Referer")) {
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+    if(!data->state.aptr.ref)
+      return CURLE_OUT_OF_MEMORY;
+    if(Curl_hyper_header(data, headers, data->state.aptr.ref))
+      goto error;
+  }
+
+  result = cookies(data, conn, headers);
+  if(result)
+    return result;
+
+  result = Curl_add_timecondition(data, headers);
+  if(result)
+    return result;
+
+  result = Curl_add_custom_headers(data, FALSE, headers);
+  if(result)
+    return result;
+
+  result = bodysend(data, conn, headers, req, httpreq);
+  if(result)
+    return result;
+
+  Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
+
+  data->req.upload_chunky = FALSE;
+  sendtask = hyper_clientconn_send(client, req);
+  if(!sendtask) {
+    failf(data, "hyper_clientconn_send");
+    goto error;
+  }
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+    failf(data, "Couldn't hyper_executor_push the send");
+    goto error;
+  }
+
+  hyper_clientconn_free(client);
+
+  do {
+    task = hyper_executor_poll(h->exec);
+    if(task) {
+      bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
+      if(error)
+        hypererr = hyper_task_value(task);
+      hyper_task_free(task);
+      if(error)
+        goto error;
+    }
+  } while(task);
+
+  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
+    /* HTTP GET/HEAD download */
+    Curl_pgrsSetUploadSize(data, 0); /* nothing */
+    Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+  }
+  conn->datastream = Curl_hyper_stream;
+
+  return CURLE_OK;
+  error:
+
+  if(io)
+    hyper_io_free(io);
+
+  if(options)
+    hyper_clientconn_options_free(options);
+
+  if(handshake)
+    hyper_task_free(handshake);
+
+  if(hypererr) {
+    uint8_t errbuf[256];
+    size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+    hyper_code code = hyper_error_code(hypererr);
+    failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
+    hyper_error_free(hypererr);
+  }
+  return CURLE_OUT_OF_MEMORY;
+}
+
+void Curl_hyper_done(struct Curl_easy *data)
+{
+  struct hyptransfer *h = &data->hyp;
+  if(h->exec) {
+    hyper_executor_free(h->exec);
+    h->exec = NULL;
+  }
+  if(h->read_waker) {
+    hyper_waker_free(h->read_waker);
+    h->read_waker = NULL;
+  }
+  if(h->write_waker) {
+    hyper_waker_free(h->write_waker);
+    h->write_waker = NULL;
+  }
+}
+
+#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
diff --git a/Utilities/cmcurl/lib/c-hyper.h b/Utilities/cmcurl/lib/c-hyper.h
new file mode 100644 (file)
index 0000000..d60ed78
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_HYPER_H
+#define HEADER_CURL_HYPER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2021, 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.haxx.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.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
+
+#include <hyper.h>
+
+/* per-transfer data for the Hyper backend */
+struct hyptransfer {
+  hyper_waker *write_waker;
+  hyper_waker *read_waker;
+  const hyper_executor *exec;
+  hyper_task *endtask;
+};
+
+size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
+                       uint8_t *buf, size_t buflen);
+size_t Curl_hyper_send(void *userp, hyper_context *ctx,
+                       const uint8_t *buf, size_t buflen);
+CURLcode Curl_hyper_stream(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           int *didwhat,
+                           bool *done,
+                           int select_res);
+
+CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
+                           const char *line);
+void Curl_hyper_done(struct Curl_easy *);
+
+#else
+#define Curl_hyper_done(x)
+
+#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
+#endif /* HEADER_CURL_HYPER_H */
index d21a00c..8dfdc0a 100644 (file)
@@ -6,11 +6,11 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se>
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -59,7 +59,7 @@ 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, (Curl_llist_dtor) conn_llist_dtor);
   return CURLE_OK;
 }
 
@@ -87,7 +87,7 @@ static void bundle_add_conn(struct connectbundle *bundle,
 static int bundle_remove_conn(struct connectbundle *bundle,
                               struct connectdata *conn)
 {
-  struct curl_llist_element *curr;
+  struct Curl_llist_element *curr;
 
   curr = bundle->conn_list.head;
   while(curr) {
@@ -179,12 +179,14 @@ size_t Curl_conncache_size(struct Curl_easy *data)
    connectdata struct is setup to use.
 
    **NOTE**: When it returns, it holds the connection cache lock! */
-struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
-                                                 struct conncache *connc,
-                                                 const char **hostp)
+struct connectbundle *
+Curl_conncache_find_bundle(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct conncache *connc,
+                           const char **hostp)
 {
   struct connectbundle *bundle = NULL;
-  CONNCACHE_LOCK(conn->data);
+  CONNCACHE_LOCK(data);
   if(connc) {
     char key[HASHKEY_SIZE];
     hashkey(conn, key, sizeof(key), hostp);
@@ -206,8 +208,8 @@ static bool conncache_add_bundle(struct conncache *connc,
 static void conncache_remove_bundle(struct conncache *connc,
                                     struct connectbundle *bundle)
 {
-  struct curl_hash_iterator iter;
-  struct curl_hash_element *he;
+  struct Curl_hash_iterator iter;
+  struct Curl_hash_element *he;
 
   if(!connc)
     return;
@@ -227,15 +229,17 @@ static void conncache_remove_bundle(struct conncache *connc,
   }
 }
 
-CURLcode Curl_conncache_add_conn(struct conncache *connc,
-                                 struct connectdata *conn)
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
   struct connectbundle *bundle = NULL;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
+  struct conncache *connc = data->state.conn_cache;
+  DEBUGASSERT(conn);
 
   /* *find_bundle() locks the connection cache */
-  bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache, NULL);
+  bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache,
+                                      NULL);
   if(!bundle) {
     int rc;
     char key[HASHKEY_SIZE];
@@ -259,7 +263,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
   conn->connection_id = connc->next_connection_id++;
   connc->num_conn++;
 
-  DEBUGF(infof(conn->data, "Added connection %ld. "
+  DEBUGF(infof(data, "Added connection %ld. "
                "The cache now contains %zu members\n",
                conn->connection_id, connc->num_conn));
 
@@ -270,8 +274,8 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
 }
 
 /*
- * Removes the connectdata object from the connection cache, but does *not*
- * clear the conn->data association. The transfer still owns this connection.
+ * Removes the connectdata object from the connection cache, but the transfer
+ * still owns this connection.
  *
  * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
  * already holds the lock or not.
@@ -318,11 +322,12 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
 bool Curl_conncache_foreach(struct Curl_easy *data,
                             struct conncache *connc,
                             void *param,
-                            int (*func)(struct connectdata *conn, void *param))
+                            int (*func)(struct Curl_easy *data,
+                                        struct connectdata *conn, void *param))
 {
-  struct curl_hash_iterator iter;
-  struct curl_llist_element *curr;
-  struct curl_hash_element *he;
+  struct Curl_hash_iterator iter;
+  struct Curl_llist_element *curr;
+  struct Curl_hash_element *he;
 
   if(!connc)
     return FALSE;
@@ -344,7 +349,7 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
       struct connectdata *conn = curr->ptr;
       curr = curr->next;
 
-      if(1 == func(conn, param)) {
+      if(1 == func(data, conn, param)) {
         CONNCACHE_UNLOCK(data);
         return TRUE;
       }
@@ -363,15 +368,15 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
 static struct connectdata *
 conncache_find_first_connection(struct conncache *connc)
 {
-  struct curl_hash_iterator iter;
-  struct curl_hash_element *he;
+  struct Curl_hash_iterator iter;
+  struct Curl_hash_element *he;
   struct connectbundle *bundle;
 
   Curl_hash_start_iterate(&connc->hash, &iter);
 
   he = Curl_hash_next_element(&iter);
   while(he) {
-    struct curl_llist_element *curr;
+    struct Curl_llist_element *curr;
     bundle = he->ptr;
 
     curr = bundle->conn_list.head;
@@ -429,7 +434,7 @@ struct connectdata *
 Curl_conncache_extract_bundle(struct Curl_easy *data,
                               struct connectbundle *bundle)
 {
-  struct curl_llist_element *curr;
+  struct Curl_llist_element *curr;
   timediff_t highscore = -1;
   timediff_t score;
   struct curltime now;
@@ -444,7 +449,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
   while(curr) {
     conn = curr->ptr;
 
-    if(!CONN_INUSE(conn) && !conn->data) {
+    if(!CONN_INUSE(conn)) {
       /* Set higher score for the age passed since the connection was used */
       score = Curl_timediff(now, conn->lastused);
 
@@ -477,9 +482,9 @@ struct connectdata *
 Curl_conncache_extract_oldest(struct Curl_easy *data)
 {
   struct conncache *connc = data->state.conn_cache;
-  struct curl_hash_iterator iter;
-  struct curl_llist_element *curr;
-  struct curl_hash_element *he;
+  struct Curl_hash_iterator iter;
+  struct Curl_llist_element *curr;
+  struct Curl_hash_element *he;
   timediff_t highscore =- 1;
   timediff_t score;
   struct curltime now;
@@ -502,7 +507,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
     while(curr) {
       conn = curr->ptr;
 
-      if(!CONN_INUSE(conn) && !conn->data && !conn->bits.close &&
+      if(!CONN_INUSE(conn) && !conn->bits.close &&
          !conn->bits.connect_only) {
         /* Set higher score for the age passed since the connection was used */
         score = Curl_timediff(now, conn->lastused);
@@ -543,12 +548,10 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
   conn = conncache_find_first_connection(connc);
   while(conn) {
     SIGPIPE_VARIABLE(pipe_st);
-    conn->data = connc->closure_handle;
-
-    sigpipe_ignore(conn->data, &pipe_st);
+    sigpipe_ignore(connc->closure_handle, &pipe_st);
     /* This will remove the connection from the cache */
     connclose(conn, "kill all");
-    Curl_conncache_remove_conn(conn->data, conn, TRUE);
+    Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
     (void)Curl_disconnect(connc->closure_handle, conn, FALSE);
     sigpipe_restore(&pipe_st);
 
@@ -571,9 +574,9 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
 /* Useful for debugging the connection cache */
 void Curl_conncache_print(struct conncache *connc)
 {
-  struct curl_hash_iterator iter;
-  struct curl_llist_element *curr;
-  struct curl_hash_element *he;
+  struct Curl_hash_iterator iter;
+  struct Curl_llist_element *curr;
+  struct Curl_hash_element *he;
 
   if(!connc)
     return;
index 3dda21c..e9c1e32 100644 (file)
@@ -7,12 +7,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <linus@haxx.se>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
  * be shared.
  */
 
+#include "timeval.h"
+
+struct connectdata;
+
 struct conncache {
-  struct curl_hash hash;
+  struct Curl_hash hash;
   size_t num_conn;
   long next_connection_id;
   struct curltime last_cleanup;
@@ -45,17 +49,24 @@ struct conncache {
 #ifdef CURLDEBUG
 /* the debug versions of these macros make extra certain that the lock is
    never doubly locked or unlocked */
-#define CONNCACHE_LOCK(x) if((x)->share) {                              \
-    Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \
-    DEBUGASSERT(!(x)->state.conncache_lock);                            \
-    (x)->state.conncache_lock = TRUE;                                   \
-  }
+#define CONNCACHE_LOCK(x)                                               \
+  do {                                                                  \
+    if((x)->share) {                                                    \
+      Curl_share_lock((x), CURL_LOCK_DATA_CONNECT,                      \
+                      CURL_LOCK_ACCESS_SINGLE);                         \
+      DEBUGASSERT(!(x)->state.conncache_lock);                          \
+      (x)->state.conncache_lock = TRUE;                                 \
+    }                                                                   \
+  } while(0)
 
-#define CONNCACHE_UNLOCK(x) if((x)->share) {                            \
-    DEBUGASSERT((x)->state.conncache_lock);                             \
-    (x)->state.conncache_lock = FALSE;                                  \
-    Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT);                     \
-  }
+#define CONNCACHE_UNLOCK(x)                                             \
+  do {                                                                  \
+    if((x)->share) {                                                    \
+      DEBUGASSERT((x)->state.conncache_lock);                           \
+      (x)->state.conncache_lock = FALSE;                                \
+      Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT);                   \
+    }                                                                   \
+  } while(0)
 #else
 #define CONNCACHE_LOCK(x) if((x)->share)                                \
     Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
@@ -66,7 +77,7 @@ struct conncache {
 struct connectbundle {
   int multiuse;                 /* supports multi-use */
   size_t num_connections;       /* Number of connections in the bundle */
-  struct curl_llist conn_list;  /* The connectdata members of the bundle */
+  struct Curl_llist conn_list;  /* The connectdata members of the bundle */
 };
 
 /* returns 1 on error, 0 is fine */
@@ -74,7 +85,8 @@ int Curl_conncache_init(struct conncache *, int size);
 void Curl_conncache_destroy(struct conncache *connc);
 
 /* return the correct bundle, to a host or a proxy */
-struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
+struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
+                                                 struct connectdata *conn,
                                                  struct conncache *connc,
                                                  const char **hostp);
 /* returns number of connections currently held in the connection cache */
@@ -82,15 +94,15 @@ size_t Curl_conncache_size(struct Curl_easy *data);
 
 bool Curl_conncache_return_conn(struct Curl_easy *data,
                                 struct connectdata *conn);
-CURLcode Curl_conncache_add_conn(struct conncache *connc,
-                                 struct connectdata *conn) WARN_UNUSED_RESULT;
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data) WARN_UNUSED_RESULT;
 void Curl_conncache_remove_conn(struct Curl_easy *data,
                                 struct connectdata *conn,
                                 bool lock);
 bool Curl_conncache_foreach(struct Curl_easy *data,
                             struct conncache *connc,
                             void *param,
-                            int (*func)(struct connectdata *conn,
+                            int (*func)(struct Curl_easy *data,
+                                        struct connectdata *conn,
                                         void *param));
 
 struct connectdata *
index b000b1b..baab184 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "curl_memory.h"
 #include "memdebug.h"
 
-#ifdef __SYMBIAN32__
-/* This isn't actually supported under Symbian OS */
-#undef SO_NOSIGPIPE
-#endif
-
 static bool verifyconnect(curl_socket_t sockfd, int *error);
 
 #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
@@ -165,7 +160,8 @@ tcpkeepalive(struct Curl_easy *data,
 }
 
 static CURLcode
-singleipconnect(struct connectdata *conn,
+singleipconnect(struct Curl_easy *data,
+                struct connectdata *conn,
                 const struct Curl_addrinfo *ai, /* start connecting to this */
                 int tempindex);          /* 0 or 1 among the temp ones */
 
@@ -241,11 +237,10 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
   return timeout_ms;
 }
 
-static CURLcode bindlocal(struct connectdata *conn,
+static CURLcode bindlocal(struct Curl_easy *data,
                           curl_socket_t sockfd, int af, unsigned int scope)
 {
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
   struct Curl_sockaddr_storage sa;
   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
   curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
@@ -261,6 +256,9 @@ static CURLcode bindlocal(struct connectdata *conn,
   int portnum = data->set.localportrange;
   const char *dev = data->set.str[STRING_DEVICE];
   int error;
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  int on = 1;
+#endif
 
   /*************************************************************
    * Select device to bind socket to
@@ -350,7 +348,7 @@ static CURLcode bindlocal(struct connectdata *conn,
        * of the connection. The resolve functions should really be changed
        * to take a type parameter instead.
        */
-      long ipver = conn->ip_version;
+      unsigned char ipver = conn->ip_version;
       int rc;
 
       if(af == AF_INET)
@@ -360,9 +358,9 @@ static CURLcode bindlocal(struct connectdata *conn,
         conn->ip_version = CURL_IPRESOLVE_V6;
 #endif
 
-      rc = Curl_resolv(conn, dev, 0, FALSE, &h);
+      rc = Curl_resolv(data, dev, 0, FALSE, &h);
       if(rc == CURLRESOLV_PENDING)
-        (void)Curl_resolver_wait_resolv(conn, &h);
+        (void)Curl_resolver_wait_resolv(data, &h);
       conn->ip_version = ipver;
 
       if(h) {
@@ -446,7 +444,9 @@ static CURLcode bindlocal(struct connectdata *conn,
       sizeof_sa = sizeof(struct sockaddr_in);
     }
   }
-
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
+#endif
   for(;;) {
     if(bind(sockfd, sock, sizeof_sa) >= 0) {
       /* we succeeded to bind */
@@ -573,7 +573,8 @@ static struct Curl_addrinfo *ainext(struct connectdata *conn,
 
 /* Used within the multi interface. Try next IP address, returns error if no
    more address exists or error */
-static CURLcode trynextip(struct connectdata *conn,
+static CURLcode trynextip(struct Curl_easy *data,
+                          struct connectdata *conn,
                           int sockindex,
                           int tempindex)
 {
@@ -591,7 +592,7 @@ static CURLcode trynextip(struct connectdata *conn,
 
     while(ai) {
       if(ai) {
-        result = singleipconnect(conn, ai, tempindex);
+        result = singleipconnect(data, conn, ai, tempindex);
         if(result == CURLE_COULDNT_CONNECT) {
           ai = ainext(conn, tempindex, TRUE);
           continue;
@@ -602,21 +603,25 @@ static CURLcode trynextip(struct connectdata *conn,
   }
 
   if(fd_to_close != CURL_SOCKET_BAD)
-    Curl_closesocket(conn, fd_to_close);
+    Curl_closesocket(data, conn, fd_to_close);
 
   return result;
 }
 
-/* Copies connection info into the session handle to make it available
-   when the session handle is no longer associated with a connection. */
-void Curl_persistconninfo(struct connectdata *conn)
+/* Copies connection info into the transfer handle to make it available when
+   the transfer handle is no longer associated with the connection. */
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+                          char *local_ip, long local_port)
 {
-  memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
-  memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
-  conn->data->info.conn_scheme = conn->handler->scheme;
-  conn->data->info.conn_protocol = conn->handler->protocol;
-  conn->data->info.conn_primary_port = conn->primary_port;
-  conn->data->info.conn_local_port = conn->local_port;
+  memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
+  if(local_ip && local_ip[0])
+    memcpy(data->info.conn_local_ip, local_ip, MAX_IPADR_LEN);
+  else
+    data->info.conn_local_ip[0] = 0;
+  data->info.conn_scheme = conn->handler->scheme;
+  data->info.conn_protocol = conn->handler->protocol;
+  data->info.conn_primary_port = conn->port;
+  data->info.conn_local_port = local_port;
 }
 
 /* retrieves ip address and port from a sockaddr structure.
@@ -678,61 +683,86 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 
 /* retrieves the start/end point information of a socket of an established
    connection */
-void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
+void Curl_conninfo_remote(struct Curl_easy *data,
+                          struct connectdata *conn, curl_socket_t sockfd)
 {
-  if(conn->transport == TRNSPRT_TCP) {
-#if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME)
-    if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
-      struct Curl_easy *data = conn->data;
-      char buffer[STRERROR_LEN];
-      struct Curl_sockaddr_storage ssrem;
-      struct Curl_sockaddr_storage ssloc;
-      curl_socklen_t plen;
-      curl_socklen_t slen;
 #ifdef HAVE_GETPEERNAME
-      plen = sizeof(struct Curl_sockaddr_storage);
-      if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
-        int error = SOCKERRNO;
-        failf(data, "getpeername() failed with errno %d: %s",
-              error, Curl_strerror(error, buffer, sizeof(buffer)));
-        return;
-      }
-#endif
-#ifdef HAVE_GETSOCKNAME
-      slen = sizeof(struct Curl_sockaddr_storage);
-      memset(&ssloc, 0, sizeof(ssloc));
-      if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
-        int error = SOCKERRNO;
-        failf(data, "getsockname() failed with errno %d: %s",
-              error, Curl_strerror(error, buffer, sizeof(buffer)));
-        return;
-      }
-#endif
-#ifdef HAVE_GETPEERNAME
-      if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
-                           conn->primary_ip, &conn->primary_port)) {
-        failf(data, "ssrem inet_ntop() failed with errno %d: %s",
-              errno, Curl_strerror(errno, buffer, sizeof(buffer)));
-        return;
-      }
-      memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
+  char buffer[STRERROR_LEN];
+  struct Curl_sockaddr_storage ssrem;
+  curl_socklen_t plen;
+  long port;
+  plen = sizeof(struct Curl_sockaddr_storage);
+  memset(&ssrem, 0, sizeof(ssrem));
+  if(getpeername(sockfd, (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,
+                       conn->primary_ip, &port)) {
+    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    return;
+  }
+#else
+  (void)data;
+  (void)conn;
+  (void)sockfd;
 #endif
+}
+
+/* retrieves the start/end point information of a socket of an established
+   connection */
+void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
+                         char *local_ip, long *local_port)
+{
 #ifdef HAVE_GETSOCKNAME
-      if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
-                           conn->local_ip, &conn->local_port)) {
-        failf(data, "ssloc inet_ntop() failed with errno %d: %s",
-              errno, Curl_strerror(errno, buffer, sizeof(buffer)));
-        return;
-      }
+  char buffer[STRERROR_LEN];
+  struct Curl_sockaddr_storage ssloc;
+  curl_socklen_t slen;
+  slen = sizeof(struct Curl_sockaddr_storage);
+  memset(&ssloc, 0, sizeof(ssloc));
+  if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
+    int error = SOCKERRNO;
+    failf(data, "getsockname() failed with errno %d: %s",
+          error, Curl_strerror(error, buffer, sizeof(buffer)));
+    return;
+  }
+  if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
+                       local_ip, local_port)) {
+    failf(data, "ssloc inet_ntop() failed with errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    return;
+  }
+#else
+  (void)data;
+  (void)sockfd;
+  (void)local_ip;
+  (void)local_port;
 #endif
+}
+
+/* retrieves the start/end point information of a socket of an established
+   connection */
+void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t sockfd)
+{
+  /* 'local_ip' and 'local_port' get filled with local's numerical
+     ip address and port number whenever an outgoing connection is
+     **established** from the primary socket to a remote address. */
+  char local_ip[MAX_IPADR_LEN] = "";
+  long local_port = -1;
+
+  if(conn->transport == TRNSPRT_TCP) {
+    if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
+      Curl_conninfo_remote(data, conn, sockfd);
+      Curl_conninfo_local(data, sockfd, local_ip, &local_port);
     }
-#else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */
-    (void)sockfd; /* unused */
-#endif
   } /* end of TCP-only section */
 
   /* persist connection info in session handle */
-  Curl_persistconninfo(conn);
+  Curl_persistconninfo(data, conn, local_ip, local_port);
 }
 
 /* After a TCP connection to the proxy has been verified, this function does
@@ -742,12 +772,13 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
    Note: this function's sub-functions call failf()
 
 */
-static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
+static CURLcode connect_SOCKS(struct Curl_easy *data, int sockindex,
                               bool *done)
 {
   CURLcode result = CURLE_OK;
-
 #ifndef CURL_DISABLE_PROXY
+  CURLproxycode pxresult = CURLPX_OK;
+  struct connectdata *conn = data->conn;
   if(conn->bits.socksproxy) {
     /* for the secondary socket (FTP), use the "connect to host"
      * but ignore the "connect to port" (use the secondary port)
@@ -767,24 +798,28 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
     switch(conn->socks_proxy.proxytype) {
     case CURLPROXY_SOCKS5:
     case CURLPROXY_SOCKS5_HOSTNAME:
-      result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
-                           host, port, sockindex, conn, done);
+      pxresult = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
+                             host, port, sockindex, data, done);
       break;
 
     case CURLPROXY_SOCKS4:
     case CURLPROXY_SOCKS4A:
-      result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
-                           conn, done);
+      pxresult = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
+                             data, done);
       break;
 
     default:
-      failf(conn->data, "unknown proxytype option given");
+      failf(data, "unknown proxytype option given");
       result = CURLE_COULDNT_CONNECT;
     } /* switch proxytype */
+    if(pxresult) {
+      result = CURLE_PROXY;
+      data->info.pxcode = pxresult;
+    }
   }
   else
 #else
-    (void)conn;
+    (void)data;
     (void)sockindex;
 #endif /* CURL_DISABLE_PROXY */
     *done = TRUE; /* no SOCKS proxy, so consider us connected */
@@ -796,7 +831,8 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
  * post_SOCKS() is called after a successful connect to the peer, which
  * *could* be a SOCKS proxy
  */
-static void post_SOCKS(struct connectdata *conn,
+static void post_SOCKS(struct Curl_easy *data,
+                       struct connectdata *conn,
                        int sockindex,
                        bool *connected)
 {
@@ -804,21 +840,21 @@ static void post_SOCKS(struct connectdata *conn,
 
   *connected = TRUE;
   if(sockindex == FIRSTSOCKET)
-    Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */
-  Curl_updateconninfo(conn, conn->sock[sockindex]);
-  Curl_verboseconnect(conn);
-  conn->data->info.numconnects++; /* to track the number of connections made */
+    Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+  Curl_updateconninfo(data, conn, conn->sock[sockindex]);
+  Curl_verboseconnect(data, conn);
+  data->info.numconnects++; /* to track the number of connections made */
 }
 
 /*
  * Curl_is_connected() checks if the socket has connected.
  */
 
-CURLcode Curl_is_connected(struct connectdata *conn,
+CURLcode Curl_is_connected(struct Curl_easy *data,
+                           struct connectdata *conn,
                            int sockindex,
                            bool *connected)
 {
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   timediff_t allow;
   int error = 0;
@@ -849,9 +885,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
   if(SOCKS_STATE(conn->cnnct.state)) {
     /* still doing SOCKS */
-    result = connect_SOCKS(conn, sockindex, connected);
+    result = connect_SOCKS(data, sockindex, connected);
     if(!result && *connected)
-      post_SOCKS(conn, sockindex, connected);
+      post_SOCKS(data, conn, sockindex, connected);
     return result;
   }
 
@@ -862,13 +898,13 @@ CURLcode Curl_is_connected(struct connectdata *conn,
     error = 0;
 #ifdef ENABLE_QUIC
     if(conn->transport == TRNSPRT_QUIC) {
-      result = Curl_quic_is_connected(conn, i, connected);
+      result = Curl_quic_is_connected(data, conn, i, connected);
       if(!result && *connected) {
         /* use this socket from now on */
         conn->sock[sockindex] = conn->tempsock[i];
         conn->ip_addr = conn->tempaddr[i];
         conn->tempsock[i] = CURL_SOCKET_BAD;
-        post_SOCKS(conn, sockindex, connected);
+        post_SOCKS(data, conn, sockindex, connected);
         connkeep(conn, "HTTP/3 default");
         return CURLE_OK;
       }
@@ -903,7 +939,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
          (Curl_timediff(now, conn->connecttime) >=
           data->set.happy_eyeballs_timeout)) {
         conn->bits.parallel_connect = TRUE; /* starting now */
-        trynextip(conn, sockindex, 1);
+        trynextip(data, conn, sockindex, 1);
       }
     }
     else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
@@ -920,17 +956,17 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
         /* close the other socket, if open */
         if(conn->tempsock[other] != CURL_SOCKET_BAD) {
-          Curl_closesocket(conn, conn->tempsock[other]);
+          Curl_closesocket(data, conn, conn->tempsock[other]);
           conn->tempsock[other] = CURL_SOCKET_BAD;
         }
 
         /* see if we need to kick off any SOCKS proxy magic once we
            connected */
-        result = connect_SOCKS(conn, sockindex, connected);
+        result = connect_SOCKS(data, sockindex, connected);
         if(result || !*connected)
           return result;
 
-        post_SOCKS(conn, sockindex, connected);
+        post_SOCKS(data, conn, sockindex, connected);
 
         return CURLE_OK;
       }
@@ -961,7 +997,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
         conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
           allow : allow / 2;
         ainext(conn, i, TRUE);
-        status = trynextip(conn, sockindex, i);
+        status = trynextip(data, conn, sockindex, i);
         if((status != CURLE_COULDNT_CONNECT) ||
            conn->tempsock[other] == CURL_SOCKET_BAD)
           /* the last attempt failed and no other sockets remain open */
@@ -979,7 +1015,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
     /* if the first address family runs out of addresses to try before the
        happy eyeball timeout, go ahead and try the next family now */
-    result = trynextip(conn, sockindex, 1);
+    result = trynextip(data, conn, sockindex, 1);
     if(!result)
       return result;
 
@@ -999,8 +1035,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
           hostname, conn->port,
           Curl_strerror(error, buffer, sizeof(buffer)));
 
-    Curl_quic_disconnect(conn, 0);
-    Curl_quic_disconnect(conn, 1);
+    Curl_quic_disconnect(data, conn, 0);
+    Curl_quic_disconnect(data, conn, 1);
 
 #ifdef WSAETIMEDOUT
     if(WSAETIMEDOUT == data->state.os_errno)
@@ -1016,16 +1052,15 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   return result;
 }
 
-static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
+static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
 {
 #if defined(TCP_NODELAY)
   curl_socklen_t onoff = (curl_socklen_t) 1;
   int level = IPPROTO_TCP;
 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  struct Curl_easy *data = conn->data;
   char buffer[STRERROR_LEN];
 #else
-  (void) conn;
+  (void) data;
 #endif
 
   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
@@ -1033,7 +1068,7 @@ static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
     infof(data, "Could not set TCP_NODELAY: %s\n",
           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
 #else
-  (void)conn;
+  (void)data;
   (void)sockfd;
 #endif
 }
@@ -1043,10 +1078,9 @@ static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
    sending data to a dead peer (instead of relying on the 4th argument to send
    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
    systems? */
-static void nosigpipe(struct connectdata *conn,
+static void nosigpipe(struct Curl_easy *data,
                       curl_socket_t sockfd)
 {
-  struct Curl_easy *data = conn->data;
   int onoff = 1;
   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
                 sizeof(onoff)) < 0) {
@@ -1112,7 +1146,8 @@ void Curl_sndbufset(curl_socket_t sockfd)
  * singleipconnect() connects to the given IP only, and it may return without
  * having connected.
  */
-static CURLcode singleipconnect(struct connectdata *conn,
+static CURLcode singleipconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 const struct Curl_addrinfo *ai,
                                 int tempindex)
 {
@@ -1120,7 +1155,6 @@ static CURLcode singleipconnect(struct connectdata *conn,
   int rc = -1;
   int error = 0;
   bool isconnected = FALSE;
-  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd;
   CURLcode result;
   char ipaddress[MAX_IPADR_LEN];
@@ -1133,7 +1167,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
   curl_socket_t *sockp = &conn->tempsock[tempindex];
   *sockp = CURL_SOCKET_BAD;
 
-  result = Curl_socket(conn, ai, &addr, &sockfd);
+  result = Curl_socket(data, ai, &addr, &sockfd);
   if(result)
     return result;
 
@@ -1143,7 +1177,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
     /* malformed address or bug in inet_ntop, try next address */
     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
-    Curl_closesocket(conn, sockfd);
+    Curl_closesocket(data, conn, sockfd);
     return CURLE_OK;
   }
   infof(data, "  Trying %s:%ld...\n", ipaddress, port);
@@ -1155,9 +1189,9 @@ static CURLcode singleipconnect(struct connectdata *conn,
   is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
 #endif
   if(is_tcp && data->set.tcp_nodelay)
-    tcpnodelay(conn, sockfd);
+    tcpnodelay(data, sockfd);
 
-  nosigpipe(conn, sockfd);
+  nosigpipe(data, sockfd);
 
   Curl_sndbufset(sockfd);
 
@@ -1175,7 +1209,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
       isconnected = TRUE;
     else if(error) {
-      Curl_closesocket(conn, sockfd); /* close the socket and bail out */
+      Curl_closesocket(data, conn, sockfd); /* close the socket and bail out */
       return CURLE_ABORTED_BY_CALLBACK;
     }
   }
@@ -1186,10 +1220,10 @@ static CURLcode singleipconnect(struct connectdata *conn,
      || addr.family == AF_INET6
 #endif
     ) {
-    result = bindlocal(conn, sockfd, addr.family,
+    result = bindlocal(data, sockfd, addr.family,
                        Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
     if(result) {
-      Curl_closesocket(conn, sockfd); /* close socket and bail out */
+      Curl_closesocket(data, conn, sockfd); /* close socket and bail out */
       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
         /* The address family is not supported on this interface.
            We can continue trying addresses */
@@ -1257,7 +1291,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
     else if(conn->transport == TRNSPRT_QUIC) {
       /* pass in 'sockfd' separately since it hasn't been put into the
          tempsock array at this point */
-      result = Curl_quic_connect(conn, sockfd, tempindex,
+      result = Curl_quic_connect(data, conn, sockfd, tempindex,
                                  &addr.sa_addr, addr.addrlen);
       if(result)
         error = SOCKERRNO;
@@ -1292,7 +1326,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
       data->state.os_errno = error;
 
       /* connect failed */
-      Curl_closesocket(conn, sockfd);
+      Curl_closesocket(data, conn, sockfd);
       result = CURLE_COULDNT_CONNECT;
     }
   }
@@ -1309,14 +1343,13 @@ static CURLcode singleipconnect(struct connectdata *conn,
  * pointer with the connected socket.
  */
 
-CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
+CURLcode Curl_connecthost(struct Curl_easy *data,
+                          struct connectdata *conn,  /* context */
                           const struct Curl_dns_entry *remotehost)
 {
-  struct Curl_easy *data = conn->data;
-  struct curltime before = Curl_now();
   CURLcode result = CURLE_COULDNT_CONNECT;
   int i;
-  timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE);
+  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
 
   if(timeout_ms < 0) {
     /* a precaution, no need to continue if time already is up */
@@ -1336,8 +1369,12 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
 
   conn->tempfamily[0] = conn->tempaddr[0]?
     conn->tempaddr[0]->ai_family:0;
+#ifdef ENABLE_IPV6
   conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
     AF_INET : AF_INET6;
+#else
+  conn->tempfamily[1] = AF_UNSPEC;
+#endif
   ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
 
   DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
@@ -1347,7 +1384,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   /* get through the list in family order in case of quick failures */
   for(i = 0; (i < 2) && result; i++) {
     while(conn->tempaddr[i]) {
-      result = singleipconnect(conn, conn->tempaddr[i], i);
+      result = singleipconnect(data, conn, conn->tempaddr[i], i);
       if(!result)
         break;
       ainext(conn, i, TRUE);
@@ -1356,7 +1393,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   if(result)
     return result;
 
-  Curl_expire(conn->data, data->set.happy_eyeballs_timeout,
+  Curl_expire(data, data->set.happy_eyeballs_timeout,
               EXPIRE_HAPPY_EYEBALLS);
 
   return CURLE_OK;
@@ -1367,9 +1404,11 @@ struct connfind {
   struct connectdata *found;
 };
 
-static int conn_is_conn(struct connectdata *conn, void *param)
+static int conn_is_conn(struct Curl_easy *data,
+                        struct connectdata *conn, void *param)
 {
   struct connfind *f = (struct connfind *)param;
+  (void)data;
   if(conn->connection_id == f->id_tofind) {
     f->found = conn;
     return 1;
@@ -1416,8 +1455,7 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
     }
     return c->sock[FIRSTSOCKET];
   }
-  else
-    return CURL_SOCKET_BAD;
+  return CURL_SOCKET_BAD;
 }
 
 /*
@@ -1452,8 +1490,8 @@ bool Curl_connalive(struct connectdata *conn)
  *
  * 'conn' can be NULL, beware!
  */
-int Curl_closesocket(struct connectdata *conn,
-                      curl_socket_t sock)
+int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
+                     curl_socket_t sock)
 {
   if(conn && conn->fclosesocket) {
     if((sock == conn->sock[SECONDARYSOCKET]) && conn->bits.sock_accepted)
@@ -1463,17 +1501,17 @@ int Curl_closesocket(struct connectdata *conn,
       conn->bits.sock_accepted = FALSE;
     else {
       int rc;
-      Curl_multi_closed(conn->data, sock);
-      Curl_set_in_callback(conn->data, true);
+      Curl_multi_closed(data, sock);
+      Curl_set_in_callback(data, true);
       rc = conn->fclosesocket(conn->closesocket_client, sock);
-      Curl_set_in_callback(conn->data, false);
+      Curl_set_in_callback(data, false);
       return rc;
     }
   }
 
   if(conn)
     /* tell the multi-socket code about this */
-    Curl_multi_closed(conn->data, sock);
+    Curl_multi_closed(data, sock);
 
   sclose(sock);
 
@@ -1489,12 +1527,12 @@ int Curl_closesocket(struct connectdata *conn,
  * If the open socket callback is set, used that!
  *
  */
-CURLcode Curl_socket(struct connectdata *conn,
+CURLcode Curl_socket(struct Curl_easy *data,
                      const struct Curl_addrinfo *ai,
                      struct Curl_sockaddr_ex *addr,
                      curl_socket_t *sockfd)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct Curl_sockaddr_ex dummy;
 
   if(!addr)
@@ -1555,8 +1593,21 @@ CURLcode Curl_socket(struct connectdata *conn,
   }
 #endif
 
-  return CURLE_OK;
+#if defined(__linux__) && defined(IP_RECVERR)
+  if(addr->socktype == SOCK_DGRAM) {
+    int one = 1;
+    switch(addr->family) {
+    case AF_INET:
+      (void)setsockopt(*sockfd, SOL_IP, IP_RECVERR, &one, sizeof(one));
+      break;
+    case AF_INET6:
+      (void)setsockopt(*sockfd, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
+      break;
+    }
+  }
+#endif
 
+  return CURLE_OK;
 }
 
 /*
@@ -1569,16 +1620,20 @@ void Curl_conncontrol(struct connectdata *conn,
 #endif
   )
 {
-  /* close if a connection, or a stream that isn't multiplexed */
-  bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
-    ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
+  /* close if a connection, or a stream that isn't multiplexed. */
+  /* This function will be called both before and after this connection is
+     associated with a transfer. */
+  bool closeit;
   DEBUGASSERT(conn);
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void)reason; /* useful for debugging */
+#endif
+  closeit = (ctrl == CONNCTRL_CONNECTION) ||
+    ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
   if((ctrl == CONNCTRL_STREAM) &&
      (conn->handler->flags & PROTOPT_STREAM))
-    DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
+    ;
   else if((bit)closeit != conn->bits.close) {
-    DEBUGF(infof(conn->data, "Marked for [%s]: %s\n",
-                 closeit?"closure":"keep alive", reason));
     conn->bits.close = closeit; /* the only place in the source code that
                                    should assign this bit */
   }
index 6fd9ea8..566b353 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "sockaddr.h"
 #include "timeval.h"
 
-CURLcode Curl_is_connected(struct connectdata *conn,
+CURLcode Curl_is_connected(struct Curl_easy *data,
+                           struct connectdata *conn,
                            int sockindex,
                            bool *connected);
 
-CURLcode Curl_connecthost(struct connectdata *conn,
+CURLcode Curl_connecthost(struct Curl_easy *data,
+                          struct connectdata *conn,
                           const struct Curl_dns_entry *host);
 
 /* generic function that returns how much time there's left to run, according
@@ -74,9 +76,16 @@ void Curl_sndbufset(curl_socket_t sockfd);
 #define Curl_sndbufset(y) Curl_nop_stmt
 #endif
 
-void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd);
-void Curl_persistconninfo(struct connectdata *conn);
-int Curl_closesocket(struct connectdata *conn, curl_socket_t sock);
+void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t sockfd);
+void Curl_conninfo_remote(struct Curl_easy *data, struct connectdata *conn,
+                          curl_socket_t sockfd);
+void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
+                         char *local_ip, long *local_port);
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+                          char *local_ip, long local_port);
+int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
+                     curl_socket_t sock);
 
 /*
  * The Curl_sockaddr_ex structure is basically libcurl's external API
@@ -104,7 +113,7 @@ struct Curl_sockaddr_ex {
  * socket callback is set, used that!
  *
  */
-CURLcode Curl_socket(struct connectdata *conn,
+CURLcode Curl_socket(struct Curl_easy *data,
                      const struct Curl_addrinfo *ai,
                      struct Curl_sockaddr_ex *addr,
                      curl_socket_t *sockfd);
index 2fc3d43..f179b81 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 
 #ifdef HAVE_ZLIB_H
 #include <zlib.h>
-#ifdef __SYMBIAN32__
-/* zlib pollutes the namespace with this definition */
-#undef WIN32
-#endif
 #endif
 
 #ifdef HAVE_BROTLI
@@ -108,9 +104,8 @@ zfree_cb(voidpf opaque, voidpf ptr)
 }
 
 static CURLcode
-process_zlib_error(struct connectdata *conn, z_stream *z)
+process_zlib_error(struct Curl_easy *data, z_stream *z)
 {
-  struct Curl_easy *data = conn->data;
   if(z->msg)
     failf(data, "Error while processing content unencoding: %s",
           z->msg);
@@ -122,7 +117,7 @@ process_zlib_error(struct connectdata *conn, z_stream *z)
 }
 
 static CURLcode
-exit_zlib(struct connectdata *conn,
+exit_zlib(struct Curl_easy *data,
           z_stream *z, zlibInitState *zlib_init, CURLcode result)
 {
   if(*zlib_init == ZLIB_GZIP_HEADER)
@@ -130,14 +125,14 @@ exit_zlib(struct connectdata *conn,
 
   if(*zlib_init != ZLIB_UNINIT) {
     if(inflateEnd(z) != Z_OK && result == CURLE_OK)
-      result = process_zlib_error(conn, z);
+      result = process_zlib_error(data, z);
     *zlib_init = ZLIB_UNINIT;
   }
 
   return result;
 }
 
-static CURLcode process_trailer(struct connectdata *conn,
+static CURLcode process_trailer(struct Curl_easy *data,
                                 struct zlib_params *zp)
 {
   z_stream *z = &zp->z;
@@ -153,7 +148,7 @@ static CURLcode process_trailer(struct connectdata *conn,
   if(z->avail_in)
     result = CURLE_WRITE_ERROR;
   if(result || !zp->trailerlen)
-    result = exit_zlib(conn, z, &zp->zlib_init, result);
+    result = exit_zlib(data, z, &zp->zlib_init, result);
   else {
     /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */
     zp->zlib_init = ZLIB_EXTERNAL_TRAILER;
@@ -161,7 +156,7 @@ static CURLcode process_trailer(struct connectdata *conn,
   return result;
 }
 
-static CURLcode inflate_stream(struct connectdata *conn,
+static CURLcode inflate_stream(struct Curl_easy *data,
                                struct contenc_writer *writer,
                                zlibInitState started)
 {
@@ -178,13 +173,13 @@ static CURLcode inflate_stream(struct connectdata *conn,
      zp->zlib_init != ZLIB_INFLATING &&
      zp->zlib_init != ZLIB_INIT_GZIP &&
      zp->zlib_init != ZLIB_GZIP_INFLATING)
-    return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
+    return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
   /* Dynamically allocate a buffer for decompression because it's uncommonly
      large to hold on the stack */
   decomp = malloc(DSIZ);
   if(decomp == NULL)
-    return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+    return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
 
   /* because the buffer size is fixed, iteratively decompress and transfer to
      the client via downstream_write function. */
@@ -208,10 +203,10 @@ static CURLcode inflate_stream(struct connectdata *conn,
     if(z->avail_out != DSIZ) {
       if(status == Z_OK || status == Z_STREAM_END) {
         zp->zlib_init = started;      /* Data started. */
-        result = Curl_unencode_write(conn, writer->downstream, decomp,
+        result = Curl_unencode_write(data, writer->downstream, decomp,
                                      DSIZ - z->avail_out);
         if(result) {
-          exit_zlib(conn, z, &zp->zlib_init, result);
+          exit_zlib(data, z, &zp->zlib_init, result);
           break;
         }
       }
@@ -227,7 +222,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
       /* No more data to flush: just exit loop. */
       break;
     case Z_STREAM_END:
-      result = process_trailer(conn, zp);
+      result = process_trailer(data, zp);
       break;
     case Z_DATA_ERROR:
       /* some servers seem to not generate zlib headers, so this is an attempt
@@ -247,7 +242,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
       }
       /* FALLTHROUGH */
     default:
-      result = exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
+      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
       break;
     }
   }
@@ -264,7 +259,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
 
 
 /* Deflate handler. */
-static CURLcode deflate_init_writer(struct connectdata *conn,
+static CURLcode deflate_init_writer(struct Curl_easy *data,
                                     struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
@@ -278,12 +273,12 @@ static CURLcode deflate_init_writer(struct connectdata *conn,
   z->zfree = (free_func) zfree_cb;
 
   if(inflateInit(z) != Z_OK)
-    return process_zlib_error(conn, z);
+    return process_zlib_error(data, z);
   zp->zlib_init = ZLIB_INIT;
   return CURLE_OK;
 }
 
-static CURLcode deflate_unencode_write(struct connectdata *conn,
+static CURLcode deflate_unencode_write(struct Curl_easy *data,
                                        struct contenc_writer *writer,
                                        const char *buf, size_t nbytes)
 {
@@ -295,19 +290,19 @@ static CURLcode deflate_unencode_write(struct connectdata *conn,
   z->avail_in = (uInt) nbytes;
 
   if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
-    return process_trailer(conn, zp);
+    return process_trailer(data, zp);
 
   /* Now uncompress the data */
-  return inflate_stream(conn, writer, ZLIB_INFLATING);
+  return inflate_stream(data, writer, ZLIB_INFLATING);
 }
 
-static void deflate_close_writer(struct connectdata *conn,
+static void deflate_close_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
   z_stream *z = &zp->z;     /* zlib state structure */
 
-  exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+  exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
 }
 
 static const struct content_encoding deflate_encoding = {
@@ -321,7 +316,7 @@ static const struct content_encoding deflate_encoding = {
 
 
 /* Gzip handler. */
-static CURLcode gzip_init_writer(struct connectdata *conn,
+static CURLcode gzip_init_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
@@ -337,14 +332,14 @@ static CURLcode gzip_init_writer(struct connectdata *conn,
   if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
     /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
     if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
-      return process_zlib_error(conn, z);
+      return process_zlib_error(data, z);
     }
     zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
   }
   else {
     /* we must parse the gzip header and trailer ourselves */
     if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
-      return process_zlib_error(conn, z);
+      return process_zlib_error(data, z);
     }
     zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */
     zp->zlib_init = ZLIB_INIT; /* Initial call state */
@@ -437,7 +432,7 @@ static enum {
 }
 #endif
 
-static CURLcode gzip_unencode_write(struct connectdata *conn,
+static CURLcode gzip_unencode_write(struct Curl_easy *data,
                                     struct contenc_writer *writer,
                                     const char *buf, size_t nbytes)
 {
@@ -449,13 +444,13 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
     z->next_in = (Bytef *) buf;
     z->avail_in = (uInt) nbytes;
     /* Now uncompress the data */
-    return inflate_stream(conn, writer, ZLIB_INIT_GZIP);
+    return inflate_stream(data, writer, ZLIB_INIT_GZIP);
   }
 
 #ifndef OLD_ZLIB_SUPPORT
   /* Support for old zlib versions is compiled away and we are running with
      an old version, so return an error. */
-  return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
+  return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
 #else
   /* This next mess is to get around the potential case where there isn't
@@ -493,7 +488,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
       z->avail_in = (uInt) nbytes;
       z->next_in = malloc(z->avail_in);
       if(z->next_in == NULL) {
-        return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+        return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
       }
       memcpy(z->next_in, buf, z->avail_in);
       zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
@@ -502,7 +497,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
 
     case GZIP_BAD:
     default:
-      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
+      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
     }
 
   }
@@ -515,7 +510,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
     z->avail_in += (uInt) nbytes;
     z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
     if(z->next_in == NULL) {
-      return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+      return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
     }
     /* Append the new block of data to the previous one */
     memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
@@ -536,7 +531,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
 
     case GZIP_BAD:
     default:
-      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
+      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
     }
 
   }
@@ -545,7 +540,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
   case ZLIB_EXTERNAL_TRAILER:
     z->next_in = (Bytef *) buf;
     z->avail_in = (uInt) nbytes;
-    return process_trailer(conn, zp);
+    return process_trailer(data, zp);
 
   case ZLIB_GZIP_INFLATING:
   default:
@@ -561,17 +556,17 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
   }
 
   /* We've parsed the header, now uncompress the data */
-  return inflate_stream(conn, writer, ZLIB_GZIP_INFLATING);
+  return inflate_stream(data, writer, ZLIB_GZIP_INFLATING);
 #endif
 }
 
-static void gzip_close_writer(struct connectdata *conn,
+static void gzip_close_writer(struct Curl_easy *data,
                               struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
   z_stream *z = &zp->z;     /* zlib state structure */
 
-  exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+  exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
 }
 
 static const struct content_encoding gzip_encoding = {
@@ -630,11 +625,11 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
   return CURLE_WRITE_ERROR;
 }
 
-static CURLcode brotli_init_writer(struct connectdata *conn,
+static CURLcode brotli_init_writer(struct Curl_easy *data,
                                    struct contenc_writer *writer)
 {
   struct brotli_params *bp = (struct brotli_params *) &writer->params;
-  (void) conn;
+  (void) data;
 
   if(!writer->downstream)
     return CURLE_WRITE_ERROR;
@@ -643,7 +638,7 @@ static CURLcode brotli_init_writer(struct connectdata *conn,
   return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
 }
 
-static CURLcode brotli_unencode_write(struct connectdata *conn,
+static CURLcode brotli_unencode_write(struct Curl_easy *data,
                                       struct contenc_writer *writer,
                                       const char *buf, size_t nbytes)
 {
@@ -668,7 +663,7 @@ static CURLcode brotli_unencode_write(struct connectdata *conn,
     dstleft = DSIZ;
     r = BrotliDecoderDecompressStream(bp->br,
                                       &nbytes, &src, &dstleft, &dst, NULL);
-    result = Curl_unencode_write(conn, writer->downstream,
+    result = Curl_unencode_write(data, writer->downstream,
                                  decomp, DSIZ - dstleft);
     if(result)
       break;
@@ -691,11 +686,11 @@ static CURLcode brotli_unencode_write(struct connectdata *conn,
   return result;
 }
 
-static void brotli_close_writer(struct connectdata *conn,
+static void brotli_close_writer(struct Curl_easy *data,
                                 struct contenc_writer *writer)
 {
   struct brotli_params *bp = (struct brotli_params *) &writer->params;
-  (void) conn;
+  (void) data;
 
   if(bp->br) {
     BrotliDecoderDestroyInstance(bp->br);
@@ -721,11 +716,11 @@ struct zstd_params {
   void *decomp;
 };
 
-static CURLcode zstd_init_writer(struct connectdata *conn,
+static CURLcode zstd_init_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
   struct zstd_params *zp = (struct zstd_params *)&writer->params;
-  (void)conn;
+  (void)data;
 
   if(!writer->downstream)
     return CURLE_WRITE_ERROR;
@@ -735,9 +730,9 @@ static CURLcode zstd_init_writer(struct connectdata *conn,
   return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
 }
 
-static CURLcode zstd_unencode_write(struct connectdata *conn,
-    struct contenc_writer *writer,
-    const char *buf, size_t nbytes)
+static CURLcode zstd_unencode_write(struct Curl_easy *data,
+                                    struct contenc_writer *writer,
+                                    const char *buf, size_t nbytes)
 {
   CURLcode result = CURLE_OK;
   struct zstd_params *zp = (struct zstd_params *)&writer->params;
@@ -764,7 +759,7 @@ static CURLcode zstd_unencode_write(struct connectdata *conn,
       return CURLE_BAD_CONTENT_ENCODING;
     }
     if(out.pos > 0) {
-      result = Curl_unencode_write(conn, writer->downstream,
+      result = Curl_unencode_write(data, writer->downstream,
                                    zp->decomp, out.pos);
       if(result)
         break;
@@ -776,11 +771,11 @@ static CURLcode zstd_unencode_write(struct connectdata *conn,
   return result;
 }
 
-static void zstd_close_writer(struct connectdata *conn,
-    struct contenc_writer *writer)
+static void zstd_close_writer(struct Curl_easy *data,
+                              struct contenc_writer *writer)
 {
   struct zstd_params *zp = (struct zstd_params *)&writer->params;
-  (void)conn;
+  (void)data;
 
   if(zp->decomp) {
     free(zp->decomp);
@@ -804,24 +799,24 @@ static const struct content_encoding zstd_encoding = {
 
 
 /* Identity handler. */
-static CURLcode identity_init_writer(struct connectdata *conn,
+static CURLcode identity_init_writer(struct Curl_easy *data,
                                      struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
 }
 
-static CURLcode identity_unencode_write(struct connectdata *conn,
+static CURLcode identity_unencode_write(struct Curl_easy *data,
                                         struct contenc_writer *writer,
                                         const char *buf, size_t nbytes)
 {
-  return Curl_unencode_write(conn, writer->downstream, buf, nbytes);
+  return Curl_unencode_write(data, writer->downstream, buf, nbytes);
 }
 
-static void identity_close_writer(struct connectdata *conn,
+static void identity_close_writer(struct Curl_easy *data,
                                   struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
 }
 
@@ -889,18 +884,17 @@ char *Curl_all_content_encodings(void)
 
 
 /* Real client writer: no downstream. */
-static CURLcode client_init_writer(struct connectdata *conn,
+static CURLcode client_init_writer(struct Curl_easy *data,
                                    struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
 }
 
-static CURLcode client_unencode_write(struct connectdata *conn,
+static CURLcode client_unencode_write(struct Curl_easy *data,
                                       struct contenc_writer *writer,
                                       const char *buf, size_t nbytes)
 {
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
 
   (void) writer;
@@ -908,13 +902,13 @@ static CURLcode client_unencode_write(struct connectdata *conn,
   if(!nbytes || k->ignorebody)
     return CURLE_OK;
 
-  return Curl_client_write(conn, CLIENTWRITE_BODY, (char *) buf, nbytes);
+  return Curl_client_write(data, CLIENTWRITE_BODY, (char *) buf, nbytes);
 }
 
-static void client_close_writer(struct connectdata *conn,
+static void client_close_writer(struct Curl_easy *data,
                                 struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
 }
 
@@ -929,14 +923,14 @@ static const struct content_encoding client_encoding = {
 
 
 /* Deferred error dummy writer. */
-static CURLcode error_init_writer(struct connectdata *conn,
+static CURLcode error_init_writer(struct Curl_easy *data,
                                   struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
 }
 
-static CURLcode error_unencode_write(struct connectdata *conn,
+static CURLcode error_unencode_write(struct Curl_easy *data,
                                      struct contenc_writer *writer,
                                      const char *buf, size_t nbytes)
 {
@@ -948,16 +942,16 @@ static CURLcode error_unencode_write(struct connectdata *conn,
 
   if(!all)
     return CURLE_OUT_OF_MEMORY;
-  failf(conn->data, "Unrecognized content encoding type. "
-                    "libcurl understands %s content encodings.", all);
+  failf(data, "Unrecognized content encoding type. "
+        "libcurl understands %s content encodings.", all);
   free(all);
   return CURLE_BAD_CONTENT_ENCODING;
 }
 
-static void error_close_writer(struct connectdata *conn,
+static void error_close_writer(struct Curl_easy *data,
                                struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
 }
 
@@ -972,7 +966,7 @@ static const struct content_encoding error_encoding = {
 
 /* Create an unencoding writer stage using the given handler. */
 static struct contenc_writer *
-new_unencoding_writer(struct connectdata *conn,
+new_unencoding_writer(struct Curl_easy *data,
                       const struct content_encoding *handler,
                       struct contenc_writer *downstream)
 {
@@ -982,7 +976,7 @@ new_unencoding_writer(struct connectdata *conn,
   if(writer) {
     writer->handler = handler;
     writer->downstream = downstream;
-    if(handler->init_writer(conn, writer)) {
+    if(handler->init_writer(data, writer)) {
       free(writer);
       writer = NULL;
     }
@@ -992,25 +986,24 @@ new_unencoding_writer(struct connectdata *conn,
 }
 
 /* Write data using an unencoding writer stack. */
-CURLcode Curl_unencode_write(struct connectdata *conn,
+CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes)
 {
   if(!nbytes)
     return CURLE_OK;
-  return writer->handler->unencode_write(conn, writer, buf, nbytes);
+  return writer->handler->unencode_write(data, writer, buf, nbytes);
 }
 
 /* Close and clean-up the connection's writer stack. */
-void Curl_unencode_cleanup(struct connectdata *conn)
+void Curl_unencode_cleanup(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
   struct contenc_writer *writer = k->writer_stack;
 
   while(writer) {
     k->writer_stack = writer->downstream;
-    writer->handler->close_writer(conn, writer);
+    writer->handler->close_writer(data, writer);
     free(writer);
     writer = k->writer_stack;
   }
@@ -1033,10 +1026,9 @@ static const struct content_encoding *find_encoding(const char *name,
 
 /* Set-up the unencoding stack from the Content-Encoding header value.
  * See RFC 7231 section 3.1.2.2. */
-CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int maybechunked)
 {
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
 
   do {
@@ -1056,14 +1048,14 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
     /* Special case: chunked encoding is handled at the reader level. */
     if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) {
       k->chunk = TRUE;             /* chunks coming our way. */
-      Curl_httpchunk_init(conn);   /* init our chunky engine. */
+      Curl_httpchunk_init(data);   /* init our chunky engine. */
     }
     else if(namelen) {
       const struct content_encoding *encoding = find_encoding(name, namelen);
       struct contenc_writer *writer;
 
       if(!k->writer_stack) {
-        k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL);
+        k->writer_stack = new_unencoding_writer(data, &client_encoding, NULL);
 
         if(!k->writer_stack)
           return CURLE_OUT_OF_MEMORY;
@@ -1073,7 +1065,7 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
         encoding = &error_encoding;  /* Defer error at stack use. */
 
       /* Stack the unencoding stage. */
-      writer = new_unencoding_writer(conn, encoding, k->writer_stack);
+      writer = new_unencoding_writer(data, encoding, k->writer_stack);
       if(!writer)
         return CURLE_OUT_OF_MEMORY;
       k->writer_stack = writer;
@@ -1085,29 +1077,29 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
 
 #else
 /* Stubs for builds without HTTP. */
-CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int maybechunked)
 {
-  (void) conn;
+  (void) data;
   (void) enclist;
   (void) maybechunked;
   return CURLE_NOT_BUILT_IN;
 }
 
-CURLcode Curl_unencode_write(struct connectdata *conn,
+CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
   (void) buf;
   (void) nbytes;
   return CURLE_NOT_BUILT_IN;
 }
 
-void Curl_unencode_cleanup(struct connectdata *conn)
+void Curl_unencode_cleanup(struct Curl_easy *data)
 {
-  (void) conn;
+  (void) data;
 }
 
 char *Curl_all_content_encodings(void)
index bdd3f1c..acfd0c2 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -33,23 +33,23 @@ struct contenc_writer {
 struct content_encoding {
   const char *name;        /* Encoding name. */
   const char *alias;       /* Encoding name alias. */
-  CURLcode (*init_writer)(struct connectdata *conn,
+  CURLcode (*init_writer)(struct Curl_easy *data,
                           struct contenc_writer *writer);
-  CURLcode (*unencode_write)(struct connectdata *conn,
+  CURLcode (*unencode_write)(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes);
-  void (*close_writer)(struct connectdata *conn,
+  void (*close_writer)(struct Curl_easy *data,
                        struct contenc_writer *writer);
   size_t paramsize;
 };
 
 
-CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int maybechunked);
-CURLcode Curl_unencode_write(struct connectdata *conn,
+CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes);
-void Curl_unencode_cleanup(struct connectdata *conn);
+void Curl_unencode_cleanup(struct Curl_easy *data);
 char *Curl_all_content_encodings(void);
 
 #endif /* HEADER_CURL_CONTENT_ENCODING_H */
index cb7d94b..09fd092 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -264,6 +264,11 @@ static const char *get_top_domain(const char * const domain, size_t *outlen)
   return first? first: domain;
 }
 
+/* Avoid C1001, an "internal error" with MSVC14 */
+#if defined(_MSC_VER) && (_MSC_VER == 1900)
+#pragma optimize("", off)
+#endif
+
 /*
  * A case-insensitive hash for the cookie domains.
  */
@@ -280,6 +285,10 @@ static size_t cookie_hash_domain(const char *domain, const size_t len)
   return (h % COOKIE_HASH_SIZE);
 }
 
+#if defined(_MSC_VER) && (_MSC_VER == 1900)
+#pragma optimize("", on)
+#endif
+
 /*
  * Hash this domain.
  */
@@ -1539,7 +1548,7 @@ static int cookie_output(struct Curl_easy *data,
   }
 
   fputs("# Netscape HTTP Cookie File\n"
-        "# https://curl.haxx.se/docs/http-cookies.html\n"
+        "# https://curl.se/docs/http-cookies.html\n"
         "# This file was generated by libcurl! Edit at your own risk.\n\n",
         out);
 
index b3865e6..e0aa383 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -34,12 +34,12 @@ struct Cookie {
   char *domain;      /* domain = <this> */
   curl_off_t expires;  /* expires = <this> */
   char *expirestr;   /* the plain text version */
-  bool tailmatch;    /* whether we do tail-matching of the domain name */
 
   /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
   char *version;     /* Version = <value> */
   char *maxage;      /* Max-Age = <value> */
 
+  bool tailmatch;    /* whether we do tail-matching of the domain name */
   bool secure;       /* whether the 'secure' keyword was used */
   bool livecookie;   /* updated from a server, not a stored file */
   bool httponly;     /* true if the httponly directive is present */
@@ -61,8 +61,8 @@ struct CookieInfo {
   struct Cookie *cookies[COOKIE_HASH_SIZE];
 
   char *filename;  /* file we read from/write to */
-  bool running;    /* state info, for cookie adding information */
   long numcookies; /* number of cookies in the "jar" */
+  bool running;    /* state info, for cookie adding information */
   bool newsession; /* new session, discard session cookies on load */
   int lastct;      /* last creation-time used in the jar */
 };
index 947d0d3..06537b2 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -285,7 +285,7 @@ Curl_he2ai(const struct hostent *he, int port)
 #endif
       ss_size = sizeof(struct sockaddr_in);
 
-    /* allocate memory to told the struct, the address and the name */
+    /* allocate memory to hold the struct, the address and the name */
     ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
     if(!ai) {
       result = CURLE_OUT_OF_MEMORY;
index a0cade6..73a8c1b 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index cfb6ee7..d48edc4 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index d5bf4fe..8dfe328 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -56,8 +56,8 @@
 /* to disable LDAPS */
 #cmakedefine CURL_DISABLE_LDAPS 1
 
-/* to enable MQTT */
-#undef CURL_ENABLE_MQTT
+/* to disable MQTT */
+#cmakedefine CURL_DISABLE_MQTT 1
 
 /* to disable POP3 */
 #cmakedefine CURL_DISABLE_POP3 1
 /* Define to 1 if you have the <libgen.h> header file. */
 #cmakedefine HAVE_LIBGEN_H 1
 
-/* Define to 1 if you have the `idn' library (-lidn). */
-#cmakedefine HAVE_LIBIDN 1
+/* Define to 1 if you have the `idn2' library (-lidn2). */
+#cmakedefine HAVE_LIBIDN2 1
+
+/* Define to 1 if you have the idn2.h header file. */
+#cmakedefine HAVE_IDN2_H 1
 
 /* Define to 1 if you have the `resolv' library (-lresolv). */
 #cmakedefine HAVE_LIBRESOLV 1
 /* Define to 1 if you have the <netinet/tcp.h> header file. */
 #cmakedefine HAVE_NETINET_TCP_H 1
 
+/* Define to 1 if you have the <linux/tcp.h> header file. */
+#cmakedefine HAVE_LINUX_TCP_H 1
+
 /* Define to 1 if you have the <net/if.h> header file. */
 #cmakedefine HAVE_NET_IF_H 1
 
@@ -999,6 +1005,10 @@ ${SIZEOF_TIME_T_CODE}
 /* if OpenSSL is in use */
 #cmakedefine USE_OPENSSL 1
 
+/* Define to 1 if you don't want the OpenSSL configuration to be loaded
+   automatically */
+#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
+
 /* to enable NGHTTP2  */
 #cmakedefine USE_NGHTTP2 1
 
@@ -1017,8 +1027,8 @@ ${SIZEOF_TIME_T_CODE}
 /* if Unix domain sockets are enabled  */
 #cmakedefine USE_UNIX_SOCKETS
 
-/* to enable alt-svc */
-#cmakedefine USE_ALTSVC 1
+/* to disable alt-svc */
+#cmakedefine CURL_DISABLE_ALTSVC 1
 
 /* to enable SSPI support */
 #cmakedefine USE_WINDOWS_SSPI 1
index 1a47fb5..d6cd08a 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 6e94bb1..17dfaa0 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 39c0f35..8c5af19 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2019, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2015 - 2020, Steve Holme, <steve_holme@hotmail.com>.
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index a42eeb5..438706a 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2019, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2015 - 2020, Steve Holme, <steve_holme@hotmail.com>.
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index a774d13..2fc25bc 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 9830e58..341dfaf 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index ab3e742..4bfa585 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 34fccae..1c80ea7 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index c419485..438ede7 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -22,6 +22,9 @@
 
 #include "curl_setup.h"
 
+#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) ||  \
+  defined(USE_HSTS)
+
 #include "curl_get_line.h"
 #include "curl_memory.h"
 /* The last #include file should be: */
@@ -53,3 +56,5 @@ char *Curl_get_line(char *buf, int len, FILE *input)
   }
   return NULL;
 }
+
+#endif /* if not disabled */
index 532ab08..597aa09 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 8337c72..2d5ff61 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -48,7 +48,7 @@
  * For libcurl static library release builds no overriding takes place.
  */
 
-int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen)
+int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
 {
 #ifndef HAVE_GETHOSTNAME
 
index 8ae15e6..2161c40 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -26,6 +26,6 @@
 #define HOSTNAME_MAX 1024
 
 /* This returns the local machine's un-qualified hostname */
-int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen);
+int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen);
 
 #endif /* HEADER_CURL_GETHOSTNAME_H */
index d854ab0..6445fba 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2011 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -131,6 +131,10 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
   display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
 
   infof(data, "%s%s\n", prefix, buf);
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+  (void)prefix;
+#endif
 }
 
 #endif /* HAVE_GSSAPI */
index 88f68db..466d09e 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2011 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 9b70c84..84c7312 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
similarity index 76%
rename from Utilities/cmcurl/lib/curl_sec.h
rename to Utilities/cmcurl/lib/curl_krb5.h
index 7bdde26..3f40f9a 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_SECURITY_H
-#define HEADER_CURL_SECURITY_H
+#ifndef HEADER_CURL_KRB5_H
+#define HEADER_CURL_KRB5_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -26,7 +26,7 @@ struct Curl_sec_client_mech {
   const char *name;
   size_t size;
   int (*init)(void *);
-  int (*auth)(void *, struct connectdata *);
+  int (*auth)(void *, struct Curl_easy *data, struct connectdata *);
   void (*end)(void *);
   int (*check_prot)(void *, int);
   int (*overhead)(void *, int, int);
@@ -39,13 +39,13 @@ struct Curl_sec_client_mech {
 #define AUTH_ERROR      2
 
 #ifdef HAVE_GSSAPI
-int Curl_sec_read_msg(struct connectdata *conn, char *,
+int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *,
                       enum protection_level);
 void Curl_sec_end(struct connectdata *);
-CURLcode Curl_sec_login(struct connectdata *);
+CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *);
 int Curl_sec_request_prot(struct connectdata *conn, const char *level);
-
-extern struct Curl_sec_client_mech Curl_krb5_client_mech;
+#else
+#define Curl_sec_end(x)
 #endif
 
-#endif /* HEADER_CURL_SECURITY_H */
+#endif /* HEADER_CURL_KRB5_H */
index 912e131..124e18b 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index c7bb209..f9dafcb 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index e06c68e..5739c89 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index ce38a08..5806290 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index eeb3044..0bd845f 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 90a8a07..c8394bb 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 2c8925b..d327c8b 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 5f8c05a..8adaf49 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 0eefb15..9a075ac 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -22,7 +22,7 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_NTLM)
+#if defined(USE_CURL_NTLM_CORE)
 
 /*
  * NTLM details:
@@ -50,8 +50,6 @@
      in NTLM type-3 messages.
  */
 
-#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
-
 #if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
 
 #ifdef USE_WOLFSSL
@@ -582,15 +580,11 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
   unsigned char *identity;
   CURLcode result = CURLE_OK;
 
-  /* we do the length checks below separately to avoid integer overflow risk
-     on extreme data lengths */
-  if((userlen > SIZE_T_MAX/2) ||
-     (domlen > SIZE_T_MAX/2) ||
-     ((userlen + domlen) > SIZE_T_MAX/2))
+  if((userlen > CURL_MAX_INPUT_LENGTH) || (domlen > CURL_MAX_INPUT_LENGTH))
     return CURLE_OUT_OF_MEMORY;
 
   identity_len = (userlen + domlen) * 2;
-  identity = malloc(identity_len);
+  identity = malloc(identity_len + 1);
 
   if(!identity)
     return CURLE_OUT_OF_MEMORY;
@@ -744,6 +738,4 @@ CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
 
 #endif /* USE_NTRESPONSES */
 
-#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
-
-#endif /* USE_NTLM */
+#endif /* USE_CURL_NTLM_CORE */
index 7895b64..fab628c 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -24,7 +24,7 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_NTLM)
+#if defined(USE_CURL_NTLM_CORE)
 
 /* If NSS is the first available SSL backend (see order in curl_ntlm_core.c)
    then it must be initialized to be used by NTLM. */
@@ -36,8 +36,6 @@
 #define NTLM_NEEDS_NSS_INIT
 #endif
 
-#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
-
 #if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
 #ifdef USE_WOLFSSL
 #  include <wolfssl/options.h>
@@ -102,8 +100,6 @@ CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
 
 #endif /* USE_NTRESPONSES */
 
-#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
-
-#endif /* USE_NTLM */
+#endif /* USE_CURL_NTLM_CORE */
 
 #endif /* HEADER_CURL_NTLM_CORE_H */
index 17a92f8..9af79fd 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -329,13 +329,16 @@ done:
   return CURLE_REMOTE_ACCESS_DENIED;
 }
 
-CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool proxy,
                             const char *header)
 {
   struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
   curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
 
+  (void) data;  /* In case it gets unused by nop log macros. */
+
   if(!checkprefix("NTLM", header))
     return CURLE_BAD_CONTENT_ENCODING;
 
@@ -352,17 +355,17 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
   }
   else {
     if(*state == NTLMSTATE_LAST) {
-      infof(conn->data, "NTLM auth restarted\n");
+      infof(data, "NTLM auth restarted\n");
       Curl_http_auth_cleanup_ntlm_wb(conn);
     }
     else if(*state == NTLMSTATE_TYPE3) {
-      infof(conn->data, "NTLM handshake rejected\n");
+      infof(data, "NTLM handshake rejected\n");
       Curl_http_auth_cleanup_ntlm_wb(conn);
       *state = NTLMSTATE_NONE;
       return CURLE_REMOTE_ACCESS_DENIED;
     }
     else if(*state >= NTLMSTATE_TYPE1) {
-      infof(conn->data, "NTLM handshake failure (internal error)\n");
+      infof(data, "NTLM handshake failure (internal error)\n");
       return CURLE_REMOTE_ACCESS_DENIED;
     }
 
@@ -376,7 +379,8 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
  * This is for creating ntlm header output by delegating challenge/response
  * to Samba's winbind daemon helper ntlm_auth.
  */
-CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+                             bool proxy)
 {
   /* point to the address of the pointer that holds the string to send to the
      server, which is for a plain host or for a HTTP proxy */
@@ -386,12 +390,11 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
   struct ntlmdata *ntlm;
   curlntlm *state;
   struct auth *authp;
-  struct Curl_easy *data = conn->data;
 
   CURLcode res = CURLE_OK;
 
   DEBUGASSERT(conn);
-  DEBUGASSERT(conn->data);
+  DEBUGASSERT(data);
 
   if(proxy) {
 #ifndef CURL_DISABLE_PROXY
@@ -399,7 +402,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
     userp = conn->http_proxy.user;
     ntlm = &conn->proxyntlm;
     state = &conn->proxy_ntlm_state;
-    authp = &conn->data->state.authproxy;
+    authp = &data->state.authproxy;
 #else
     return CURLE_NOT_BUILT_IN;
 #endif
@@ -409,7 +412,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
     userp = conn->user;
     ntlm = &conn->ntlm;
     state = &conn->http_ntlm_state;
-    authp = &conn->data->state.authhost;
+    authp = &data->state.authhost;
   }
   authp->done = FALSE;
 
@@ -433,10 +436,10 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
      * request handling process.
      */
     /* Create communication with ntlm_auth */
-    res = ntlm_wb_init(conn->data, ntlm, userp);
+    res = ntlm_wb_init(data, ntlm, userp);
     if(res)
       return res;
-    res = ntlm_wb_response(conn->data, ntlm, "YR\n", *state);
+    res = ntlm_wb_response(data, ntlm, "YR\n", *state);
     if(res)
       return res;
 
@@ -454,7 +457,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
     char *input = aprintf("TT %s\n", ntlm->challenge);
     if(!input)
       return CURLE_OUT_OF_MEMORY;
-    res = ntlm_wb_response(conn->data, ntlm, input, *state);
+    res = ntlm_wb_response(data, ntlm, input, *state);
     free(input);
     if(res)
       return res;
index 3cf841c..961b568 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
     defined(NTLM_WB_ENABLED)
 
 /* this is for ntlm header input */
-CURLcode Curl_input_ntlm_wb(struct connectdata *conn, bool proxy,
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+                            struct connectdata *conn, bool proxy,
                             const char *header);
 
 /* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy);
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+                             bool proxy);
 
 void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn);
 
index fbd98cb..6100d77 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "memdebug.h"
 
 /* figure out the path to work with in this particular request */
-CURLcode Curl_getworkingpath(struct connectdata *conn,
+CURLcode Curl_getworkingpath(struct Curl_easy *data,
                              char *homedir,  /* when SFTP is used */
                              char **path) /* returns the  allocated
                                              real path to work with */
 {
-  struct Curl_easy *data = conn->data;
   char *real_path = NULL;
   char *working_path;
   size_t working_path_len;
@@ -47,7 +46,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
     return result;
 
   /* Check for /~/, indicating relative to the user's home directory */
-  if(conn->handler->protocol & CURLPROTO_SCP) {
+  if(data->conn->handler->protocol & CURLPROTO_SCP) {
     real_path = malloc(working_path_len + 1);
     if(real_path == NULL) {
       free(working_path);
@@ -59,7 +58,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
     else
       memcpy(real_path, working_path, 1 + working_path_len);
   }
-  else if(conn->handler->protocol & CURLPROTO_SFTP) {
+  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);
@@ -168,7 +167,7 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
     *cpp = cp + i + strspn(cp + i, WHITESPACE);
   }
   else {
-    /* Read to end of filename - either to white space or terminator */
+    /* Read to end of filename - either to whitespace or terminator */
     end = strpbrk(cp, WHITESPACE);
     if(end == NULL)
       end = strchr(cp, '\0');
@@ -184,7 +183,7 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
       (*path)[pathLength] = '\0';
       cp += 3;
     }
-    /* Copy path name up until first "white space" */
+    /* Copy path name up until first "whitespace" */
     memcpy(&(*path)[pathLength], cp, (int)(end - cp));
     pathLength += (int)(end - cp);
     (*path)[pathLength] = '\0';
index 636c37f..a376bd1 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -39,7 +39,7 @@
                          have their definition hidden well */
 #endif
 
-CURLcode Curl_getworkingpath(struct connectdata *conn,
+CURLcode Curl_getworkingpath(struct Curl_easy *data,
                              char *homedir,
                              char **path);
 
index 0d37b8e..9fa625f 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index aa3c493..f7fb7c0 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
   Check if this is a range download, and if so, set the internal variables
   properly.
  */
-CURLcode Curl_range(struct connectdata *conn)
+CURLcode Curl_range(struct Curl_easy *data)
 {
   curl_off_t from, to;
   char *ptr;
   char *ptr2;
-  struct Curl_easy *data = conn->data;
 
   if(data->state.use_range && data->state.range) {
     CURLofft from_t;
index 2350df9..0a07baf 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -25,6 +25,5 @@
 #include "curl_setup.h"
 #include "urldata.h"
 
-CURLcode Curl_range(struct connectdata *conn);
-
+CURLcode Curl_range(struct Curl_easy *data);
 #endif /* HEADER_CURL_RANGE_H */
index df8f2b1..fabdc88 100644 (file)
@@ -5,12 +5,12 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
 
 #define DEF_BUFTIME    (2*60*60*1000)    /* 2 hours */
 
-static CURLcode rtmp_setup_connection(struct connectdata *conn);
-static CURLcode rtmp_do(struct connectdata *conn, bool *done);
-static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature);
-static CURLcode rtmp_connect(struct connectdata *conn, bool *done);
-static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead);
+static CURLcode rtmp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode rtmp_do(struct Curl_easy *data, bool *done);
+static CURLcode rtmp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode rtmp_connect(struct Curl_easy *data, bool *done);
+static CURLcode rtmp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
 
 static Curl_recv rtmp_recv;
 static Curl_send rtmp_send;
@@ -79,6 +81,7 @@ const struct Curl_handler Curl_handler_rtmp = {
   ZERO_NULL,                            /* connection_check */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMP,                       /* protocol */
+  CURLPROTO_RTMP,                       /* family */
   PROTOPT_NONE                          /* flags*/
 };
 
@@ -100,6 +103,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
   ZERO_NULL,                            /* connection_check */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPT,                      /* protocol */
+  CURLPROTO_RTMPT,                      /* family */
   PROTOPT_NONE                          /* flags*/
 };
 
@@ -121,6 +125,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
   ZERO_NULL,                            /* connection_check */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMPE,                      /* protocol */
+  CURLPROTO_RTMPE,                      /* family */
   PROTOPT_NONE                          /* flags*/
 };
 
@@ -142,6 +147,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
   ZERO_NULL,                            /* connection_check */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPTE,                     /* protocol */
+  CURLPROTO_RTMPTE,                     /* family */
   PROTOPT_NONE                          /* flags*/
 };
 
@@ -163,6 +169,7 @@ const struct Curl_handler Curl_handler_rtmps = {
   ZERO_NULL,                            /* connection_check */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPS,                      /* protocol */
+  CURLPROTO_RTMP,                       /* family */
   PROTOPT_NONE                          /* flags*/
 };
 
@@ -184,10 +191,12 @@ const struct Curl_handler Curl_handler_rtmpts = {
   ZERO_NULL,                            /* connection_check */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPTS,                     /* protocol */
+  CURLPROTO_RTMPT,                      /* family */
   PROTOPT_NONE                          /* flags*/
 };
 
-static CURLcode rtmp_setup_connection(struct connectdata *conn)
+static CURLcode rtmp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   RTMP *r = RTMP_Alloc();
   if(!r)
@@ -195,7 +204,7 @@ static CURLcode rtmp_setup_connection(struct connectdata *conn)
 
   RTMP_Init(r);
   RTMP_SetBufferMS(r, DEF_BUFTIME);
-  if(!RTMP_SetupURL(r, conn->data->change.url)) {
+  if(!RTMP_SetupURL(r, data->change.url)) {
     RTMP_Free(r);
     return CURLE_URL_MALFORMAT;
   }
@@ -203,8 +212,9 @@ static CURLcode rtmp_setup_connection(struct connectdata *conn)
   return CURLE_OK;
 }
 
-static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
+static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
   SET_RCVTIMEO(tv, 10);
 
@@ -213,7 +223,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
   /* We have to know if it's a write before we send the
    * connect request packet
    */
-  if(conn->data->set.upload)
+  if(data->set.upload)
     r->Link.protocol |= RTMP_FEATURE_WRITE;
 
   /* For plain streams, use the buffer toggle trick to keep data flowing */
@@ -237,15 +247,15 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode rtmp_do(struct connectdata *conn, bool *done)
+static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
 
   if(!RTMP_ConnectStream(r, 0))
     return CURLE_FAILED_INIT;
 
-  if(conn->data->set.upload) {
+  if(data->set.upload) {
     Curl_pgrsSetUploadSize(data, data->state.infilesize);
     Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
   }
@@ -255,20 +265,22 @@ static CURLcode rtmp_do(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
+static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status,
                           bool premature)
 {
-  (void)conn; /* unused */
+  (void)data; /* unused */
   (void)status; /* unused */
   (void)premature; /* unused */
 
   return CURLE_OK;
 }
 
-static CURLcode rtmp_disconnect(struct connectdata *conn,
+static CURLcode rtmp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection)
 {
   RTMP *r = conn->proto.rtmp;
+  (void)data;
   (void)dead_connection;
   if(r) {
     conn->proto.rtmp = NULL;
@@ -278,9 +290,10 @@ static CURLcode rtmp_disconnect(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
+static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
                          size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
   ssize_t nread;
 
@@ -289,8 +302,8 @@ static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
   nread = RTMP_Read(r, buf, curlx_uztosi(len));
   if(nread < 0) {
     if(r->m_read.status == RTMP_READ_COMPLETE ||
-        r->m_read.status == RTMP_READ_EOF) {
-      conn->data->req.size = conn->data->req.bytecount;
+       r->m_read.status == RTMP_READ_EOF) {
+      data->req.size = data->req.bytecount;
       nread = 0;
     }
     else
@@ -299,9 +312,10 @@ static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
   return nread;
 }
 
-static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
+static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
                          const void *buf, size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
   ssize_t num;
 
index 86a0138..f45fa71 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2010 - 2019, Howard Chu, <hyc@highlandsun.com>
+ * Copyright (C) 2010 - 2020, Howard Chu, <hyc@highlandsun.com>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 83fe896..ffeb751 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -194,7 +194,7 @@ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
  *
  * This is the ONLY way to change SASL state!
  */
-static void state(struct SASL *sasl, struct connectdata *conn,
+static void state(struct SASL *sasl, struct Curl_easy *data,
                   saslstate newstate)
 {
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -221,10 +221,10 @@ static void state(struct SASL *sasl, struct connectdata *conn,
   };
 
   if(sasl->state != newstate)
-    infof(conn->data, "SASL %p state change from %s to %s\n",
+    infof(data, "SASL %p state change from %s to %s\n",
           (void *)sasl, names[sasl->state], names[newstate]);
 #else
-  (void) conn;
+  (void) data;
 #endif
 
   sasl->state = newstate;
@@ -253,11 +253,11 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
  *
  * Calculate the required login details for SASL authentication.
  */
-CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
+                         struct connectdata *conn,
                          bool force_ir, saslprogress *progress)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   unsigned int enabledmechs;
   const char *mech = NULL;
   char *resp = NULL;
@@ -398,10 +398,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
       resp = NULL;
     }
 
-    result = sasl->params->sendauth(conn, mech, resp);
+    result = sasl->params->sendauth(data, conn, mech, resp);
     if(!result) {
       *progress = SASL_INPROGRESS;
-      state(sasl, conn, resp ? state2 : state1);
+      state(sasl, data, resp ? state2 : state1);
     }
   }
 
@@ -415,11 +415,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
  *
  * Continue the authentication.
  */
-CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
+                            struct connectdata *conn,
                             int code, saslprogress *progress)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   saslstate newstate = SASL_FINAL;
   char *resp = NULL;
 #ifndef CURL_DISABLE_PROXY
@@ -450,14 +450,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     if(code != sasl->params->finalcode)
       result = CURLE_LOGIN_DENIED;
     *progress = SASL_DONE;
-    state(sasl, conn, SASL_STOP);
+    state(sasl, data, SASL_STOP);
     return result;
   }
 
   if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
      code != sasl->params->contcode) {
     *progress = SASL_DONE;
-    state(sasl, conn, SASL_STOP);
+    state(sasl, data, SASL_STOP);
     return CURLE_LOGIN_DENIED;
   }
 
@@ -587,7 +587,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     if(code == sasl->params->finalcode) {
       /* Final response was received so we are done */
       *progress = SASL_DONE;
-      state(sasl, conn, SASL_STOP);
+      state(sasl, data, SASL_STOP);
       return result;
     }
     else if(code == sasl->params->contcode) {
@@ -600,7 +600,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     }
     else {
       *progress = SASL_DONE;
-      state(sasl, conn, SASL_STOP);
+      state(sasl, data, SASL_STOP);
       return CURLE_LOGIN_DENIED;
     }
 
@@ -609,7 +609,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     sasl->authmechs ^= sasl->authused;
 
     /* Start an alternative SASL authentication */
-    result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress);
+    result = Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
     newstate = sasl->state;   /* Use state from Curl_sasl_start() */
     break;
   default:
@@ -621,12 +621,12 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
   switch(result) {
   case CURLE_BAD_CONTENT_ENCODING:
     /* Cancel dialog */
-    result = sasl->params->sendcont(conn, "*");
+    result = sasl->params->sendcont(data, conn, "*");
     newstate = SASL_CANCEL;
     break;
   case CURLE_OK:
     if(resp)
-      result = sasl->params->sendcont(conn, resp);
+      result = sasl->params->sendcont(data, conn, resp);
     break;
   default:
     newstate = SASL_STOP;    /* Stop on error */
@@ -636,7 +636,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
 
   free(resp);
 
-  state(sasl, conn, newstate);
+  state(sasl, data, newstate);
 
   return result;
 }
index 7647a48..75a9575 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -88,10 +88,12 @@ struct SASLproto {
   int contcode;            /* Code to receive when continuation is expected */
   int finalcode;           /* Code to receive upon authentication success */
   size_t maxirlen;         /* Maximum initial response length */
-  CURLcode (*sendauth)(struct connectdata *conn,
+  CURLcode (*sendauth)(struct Curl_easy *data,
+                       struct connectdata *conn,
                        const char *mech, const char *ir);
                            /* Send authentication command */
-  CURLcode (*sendcont)(struct connectdata *conn, const char *contauth);
+  CURLcode (*sendcont)(struct Curl_easy *data,
+                       struct connectdata *conn, const char *contauth);
                            /* Send authentication continuation */
   void (*getmessage)(char *buffer, char **outptr);
                            /* Get SASL response message */
@@ -133,11 +135,13 @@ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);
 bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
 
 /* Calculate the required login details for SASL authentication  */
-CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
+                         struct connectdata *conn,
                          bool force_ir, saslprogress *progress);
 
 /* Continue an SASL authentication  */
-CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
+                            struct connectdata *conn,
                             int code, saslprogress *progress);
 
 #endif /* HEADER_CURL_SASL_H */
index 45a093f..ef43b2b 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -38,8 +38,7 @@
  * Define WIN32 when build target is Win32 API
  */
 
-#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \
-    !defined(__SYMBIAN32__)
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
 #define WIN32
 #endif
 
 #  include "config-amigaos.h"
 #endif
 
-#ifdef __SYMBIAN32__
-#  include "config-symbian.h"
-#endif
-
 #ifdef __OS400__
 #  include "config-os400.h"
 #endif
  * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64,
  * performing this task will result in a synthesized IPv6 address.
  */
-#ifdef  __APPLE__
+#if defined(__APPLE__) && !defined(USE_ARES)
 #define USE_RESOLVE_ON_IPS 1
 #endif
 
 #  include <exec/execbase.h>
 #  include <proto/exec.h>
 #  include <proto/dos.h>
+#  include <unistd.h>
 #  ifdef HAVE_PROTO_BSDSOCKET_H
 #    include <proto/bsdsocket.h> /* ensure bsdsocket.library use */
 #    define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0)
 #  endif
+/*
+ * In clib2 arpa/inet.h warns that some prototypes may clash
+ * with bsdsocket.library. This avoids the definition of those.
+ */
+#  define __NO_NET_API
 #endif
 
 #include <stdio.h>
 /* ---------------------------------------------------------------- */
 
 /*
- * When using WINSOCK, TELNET protocol requires WINSOCK2 API.
- */
-
-#if defined(USE_WINSOCK) && (USE_WINSOCK != 2)
-#  define CURL_DISABLE_TELNET 1
-#endif
-
-/*
  * msvc 6.0 does not have struct sockaddr_storage and
  * does not define IPPROTO_ESP in winsock2.h. But both
  * are available if PSDK is properly installed.
@@ -652,13 +645,12 @@ int netware_init(void);
 
 /* Single point where USE_NTLM definition might be defined */
 #if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH)
-#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) ||                \
+#if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                     \
   defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) ||  \
   defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
-  defined(USE_MBEDTLS) ||                                               \
   (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
 
-#define USE_NTLM
+#define USE_CURL_NTLM_CORE
 
 #  if defined(USE_MBEDTLS)
 /* Get definition of MBEDTLS_MD4_C */
@@ -666,6 +658,10 @@ int netware_init(void);
 #  endif
 
 #endif
+
+#if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI)
+#define USE_NTLM
+#endif
 #endif
 
 #ifdef CURL_WANTS_CA_BUNDLE_ENV
@@ -717,7 +713,7 @@ int netware_init(void);
      defined(HAVE_WINSOCK_H) || \
      defined(HAVE_WINSOCK2_H) || \
      defined(HAVE_WS2TCPIP_H)
-#    error "Winsock and lwIP TCP/IP stack definitions shall not coexist!"
+#    error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
 #  endif
 #endif
 
index e7c00de..ef60bc7 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 35d286c..b4579d7 100644 (file)
@@ -12,7 +12,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -24,6 +24,9 @@
  ***************************************************************************/
 
 #ifndef CURL_DISABLE_CRYPTO_AUTH
+#include "curl_hmac.h"
+
+extern const struct HMAC_params Curl_HMAC_SHA256[1];
 
 #define SHA256_DIGEST_LENGTH 32
 
index 512ce24..06841dd 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index c09026e..881384d 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index b5f10a2..4146144 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
 
 #if defined(USE_THREADS_POSIX)
 
-struct curl_actual_call {
+struct Curl_actual_call {
   unsigned int (*func)(void *);
   void *arg;
 };
 
 static void *curl_thread_create_thunk(void *arg)
 {
-  struct curl_actual_call *ac = arg;
+  struct Curl_actual_call *ac = arg;
   unsigned int (*func)(void *) = ac->func;
   void *real_arg = ac->arg;
 
@@ -62,7 +62,7 @@ static void *curl_thread_create_thunk(void *arg)
 curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg)
 {
   curl_thread_t t = malloc(sizeof(pthread_t));
-  struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call));
+  struct Curl_actual_call *ac = malloc(sizeof(struct Curl_actual_call));
   if(!(ac && t))
     goto err;
 
index 65d1a79..e10b7a1 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 98e51bf..9f21f60 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index f529b48..4319dad 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -57,6 +57,7 @@
 #include "escape.h"
 #include "progress.h"
 #include "dict.h"
+#include "curl_printf.h"
 #include "strcase.h"
 #include "curl_memory.h"
 /* The last #include file should be: */
@@ -66,7 +67,7 @@
  * Forward declarations.
  */
 
-static CURLcode dict_do(struct connectdata *conn, bool *done);
+static CURLcode dict_do(struct Curl_easy *data, bool *done);
 
 /*
  * DICT protocol handler.
@@ -90,7 +91,8 @@ const struct Curl_handler Curl_handler_dict = {
   ZERO_NULL,                            /* connection_check */
   PORT_DICT,                            /* defport */
   CURLPROTO_DICT,                       /* protocol */
-  PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
+  CURLPROTO_DICT,                       /* family */
+  PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
 };
 
 static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
@@ -126,7 +128,51 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
   return dictp;
 }
 
-static CURLcode dict_do(struct connectdata *conn, bool *done)
+/* sendf() sends formatted data to the server */
+static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
+                      const char *fmt, ...)
+{
+  ssize_t bytes_written;
+  size_t write_len;
+  CURLcode result = CURLE_OK;
+  char *s;
+  char *sptr;
+  va_list ap;
+  va_start(ap, fmt);
+  s = vaprintf(fmt, ap); /* returns an allocated string */
+  va_end(ap);
+  if(!s)
+    return CURLE_OUT_OF_MEMORY; /* failure */
+
+  bytes_written = 0;
+  write_len = strlen(s);
+  sptr = s;
+
+  for(;;) {
+    /* Write the buffer to the socket */
+    result = Curl_write(data, sockfd, sptr, write_len, &bytes_written);
+
+    if(result)
+      break;
+
+    Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written);
+
+    if((size_t)bytes_written != write_len) {
+      /* if not all was written at once, we must advance the pointer, decrease
+         the size left and try again! */
+      write_len -= bytes_written;
+      sptr += bytes_written;
+    }
+    else
+      break;
+  }
+
+  free(s); /* free the output string */
+
+  return result;
+}
+
+static CURLcode dict_do(struct Curl_easy *data, bool *done)
 {
   char *word;
   char *eword;
@@ -136,7 +182,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
   char *nthdef = NULL; /* This is not part of the protocol, but required
                           by RFC 2229 */
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
   char *path = data->state.up.path;
@@ -183,18 +229,16 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
     if(!eword)
       return CURLE_OUT_OF_MEMORY;
 
-    result = Curl_sendf(sockfd, conn,
-                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
-                        "MATCH "
-                        "%s "    /* database */
-                        "%s "    /* strategy */
-                        "%s\r\n" /* word */
-                        "QUIT\r\n",
-
-                        database,
-                        strategy,
-                        eword
-                        );
+    result = sendf(sockfd, data,
+                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                   "MATCH "
+                   "%s "    /* database */
+                   "%s "    /* strategy */
+                   "%s\r\n" /* word */
+                   "QUIT\r\n",
+                   database,
+                   strategy,
+                   eword);
 
     free(eword);
 
@@ -233,14 +277,14 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
     if(!eword)
       return CURLE_OUT_OF_MEMORY;
 
-    result = Curl_sendf(sockfd, conn,
-                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
-                        "DEFINE "
-                        "%s "     /* database */
-                        "%s\r\n"  /* word */
-                        "QUIT\r\n",
-                        database,
-                        eword);
+    result = sendf(sockfd, data,
+                   "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                   "DEFINE "
+                   "%s "     /* database */
+                   "%s\r\n"  /* word */
+                   "QUIT\r\n",
+                   database,
+                   eword);
 
     free(eword);
 
@@ -261,10 +305,10 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
         if(ppath[i] == ':')
           ppath[i] = ' ';
       }
-      result = Curl_sendf(sockfd, conn,
-                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
-                          "%s\r\n"
-                          "QUIT\r\n", ppath);
+      result = sendf(sockfd, data,
+                     "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                     "%s\r\n"
+                     "QUIT\r\n", ppath);
       if(result) {
         failf(data, "Failed sending DICT request");
         return result;
index 38a55ac..6a6c772 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 8bc3428..004244c 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -57,12 +57,13 @@ static const char * const errors[]={
   "Unexpected TYPE",
   "Unexpected CLASS",
   "No content",
-  "Bad ID"
+  "Bad ID",
+  "Name too long"
 };
 
 static const char *doh_strerror(DOHcode code)
 {
-  if((code >= DOH_OK) && (code <= DOH_DNS_BAD_ID))
+  if((code >= DOH_OK) && (code <= DOH_DNS_NAME_TOO_LONG))
     return errors[code];
   return "bad error code";
 }
@@ -186,19 +187,20 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
 }
 
 /* called from multi.c when this DOH transfer is complete */
-static int Curl_doh_done(struct Curl_easy *doh, CURLcode result)
+static int doh_done(struct Curl_easy *doh, CURLcode result)
 {
   struct Curl_easy *data = doh->set.dohfor;
+  struct dohdata *dohp = data->req.doh;
   /* so one of the DOH request done for the 'data' transfer is now complete! */
-  data->req.doh.pending--;
-  infof(data, "a DOH request is completed, %u to go\n", data->req.doh.pending);
+  dohp->pending--;
+  infof(data, "a DOH request is completed, %u to go\n", dohp->pending);
   if(result)
     infof(data, "DOH request %s\n", curl_easy_strerror(result));
 
-  if(!data->req.doh.pending) {
+  if(!dohp->pending) {
     /* DOH completed */
-    curl_slist_free_all(data->req.doh.headers);
-    data->req.doh.headers = NULL;
+    curl_slist_free_all(dohp->headers);
+    dohp->headers = NULL;
     Curl_expire(data, 0, EXPIRE_RUN_NOW);
   }
   return 0;
@@ -224,7 +226,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
   DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
                          &p->dohlen);
   if(d) {
-    failf(data, "Failed to encode DOH packet [%d]\n", d);
+    failf(data, "Failed to encode DOH packet [%d]", d);
     return CURLE_OUT_OF_MEMORY;
   }
 
@@ -348,8 +350,12 @@ static CURLcode dohprobe(struct Curl_easy *data,
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
     if(data->set.ssl.fsslctxp)
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
+    if(data->set.str[STRING_SSL_EC_CURVES]) {
+      ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
+        data->set.str[STRING_SSL_EC_CURVES]);
+    }
 
-    doh->set.fmultidone = Curl_doh_done;
+    doh->set.fmultidone = doh_done;
     doh->set.dohfor = data; /* identify for which transfer this is done */
     p->easy = doh;
 
@@ -373,58 +379,64 @@ static CURLcode dohprobe(struct Curl_easy *data,
  * 'Curl_addrinfo *' with the address information.
  */
 
-struct Curl_addrinfo *Curl_doh(struct connectdata *conn,
+struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                                const char *hostname,
                                int port,
                                int *waitp)
 {
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   int slot;
+  struct dohdata *dohp;
+  struct connectdata *conn = data->conn;
   *waitp = TRUE; /* this never returns synchronously */
-  (void)conn;
   (void)hostname;
   (void)port;
 
+  DEBUGASSERT(!data->req.doh);
+  DEBUGASSERT(conn);
+
   /* start clean, consider allocating this struct on demand */
-  memset(&data->req.doh, 0, sizeof(struct dohdata));
+  dohp = data->req.doh = calloc(sizeof(struct dohdata), 1);
+  if(!dohp)
+    return NULL;
 
   conn->bits.doh = TRUE;
-  data->req.doh.host = hostname;
-  data->req.doh.port = port;
-  data->req.doh.headers =
+  dohp->host = hostname;
+  dohp->port = port;
+  dohp->headers =
     curl_slist_append(NULL,
                       "Content-Type: application/dns-message");
-  if(!data->req.doh.headers)
+  if(!dohp->headers)
     goto error;
 
   if(conn->ip_version != CURL_IPRESOLVE_V6) {
     /* create IPv4 DOH request */
-    result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4],
+    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
                       DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
-                      data->multi, data->req.doh.headers);
+                      data->multi, dohp->headers);
     if(result)
       goto error;
-    data->req.doh.pending++;
+    dohp->pending++;
   }
 
   if(conn->ip_version != CURL_IPRESOLVE_V4) {
     /* create IPv6 DOH request */
-    result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6],
+    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
                       DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
-                      data->multi, data->req.doh.headers);
+                      data->multi, dohp->headers);
     if(result)
       goto error;
-    data->req.doh.pending++;
+    dohp->pending++;
   }
   return NULL;
 
   error:
-  curl_slist_free_all(data->req.doh.headers);
-  data->req.doh.headers = NULL;
+  curl_slist_free_all(dohp->headers);
+  data->req.doh->headers = NULL;
   for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-    Curl_close(&data->req.doh.probe[slot].easy);
+    Curl_close(&dohp->probe[slot].easy);
   }
+  Curl_safefree(data->req.doh);
   return NULL;
 }
 
@@ -463,7 +475,7 @@ static unsigned int get32bit(const unsigned char *doh, int index)
       the pointer first. */
    doh += index;
 
-   /* avoid undefined behaviour by casting to unsigned before shifting
+   /* avoid undefined behavior by casting to unsigned before shifting
       24 bits, possibly into the sign bit. codegen is same, but
       ub sanitizer won't be upset */
   return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3];
@@ -899,20 +911,22 @@ UNITTEST void de_cleanup(struct dohentry *d)
   }
 }
 
-CURLcode Curl_doh_is_resolved(struct connectdata *conn,
+CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                               struct Curl_dns_entry **dnsp)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
+  struct dohdata *dohp = data->req.doh;
   *dnsp = NULL; /* defaults to no response */
+  if(!dohp)
+    return CURLE_OUT_OF_MEMORY;
 
-  if(!data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
-     !data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
-    failf(data, "Could not DOH-resolve: %s", conn->async.hostname);
-    return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
+  if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
+     !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
+    failf(data, "Could not DOH-resolve: %s", data->state.async.hostname);
+    return data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
       CURLE_COULDNT_RESOLVE_HOST;
   }
-  else if(!data->req.doh.pending) {
+  else if(!dohp->pending) {
     DOHcode rc[DOH_PROBE_SLOTS] = {
       DOH_OK, DOH_OK
     };
@@ -920,13 +934,13 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
     int slot;
     /* remove DOH handles from multi handle and close them */
     for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-      curl_multi_remove_handle(data->multi, data->req.doh.probe[slot].easy);
-      Curl_close(&data->req.doh.probe[slot].easy);
+      curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
+      Curl_close(&dohp->probe[slot].easy);
     }
     /* parse the responses, create the struct and return it! */
     de_init(&de);
     for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-      struct dnsprobe *p = &data->req.doh.probe[slot];
+      struct dnsprobe *p = &dohp->probe[slot];
       if(!p->dnstype)
         continue;
       rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
@@ -936,7 +950,7 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
       Curl_dyn_free(&p->serverdoh);
       if(rc[slot]) {
         infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]),
-              type2name(p->dnstype), data->req.doh.host);
+              type2name(p->dnstype), dohp->host);
       }
     } /* next slot */
 
@@ -946,10 +960,10 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
       struct Curl_dns_entry *dns;
       struct Curl_addrinfo *ai;
 
-      infof(data, "DOH Host name: %s\n", data->req.doh.host);
+      infof(data, "DOH Host name: %s\n", dohp->host);
       showdoh(data, &de);
 
-      ai = doh2ai(&de, data->req.doh.host, data->req.doh.port);
+      ai = doh2ai(&de, dohp->host, dohp->port);
       if(!ai) {
         de_cleanup(&de);
         return CURLE_OUT_OF_MEMORY;
@@ -959,7 +973,7 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
         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, data->req.doh.host, data->req.doh.port);
+      dns = Curl_cache_addr(data, ai, dohp->host, dohp->port);
 
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -969,7 +983,7 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
         Curl_freeaddrinfo(ai);
       }
       else {
-        conn->async.dns = dns;
+        data->state.async.dns = dns;
         *dnsp = dns;
         result = CURLE_OK;      /* address resolution OK */
       }
@@ -979,9 +993,10 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
 
     /* All done */
     de_cleanup(&de);
+    Curl_safefree(data->req.doh);
     return result;
 
-  } /* !data->req.doh.pending */
+  } /* !dohp->pending */
 
   /* else wait for pending DOH transactions to complete */
   return CURLE_OK;
index bbd4c1a..b3584d1 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
  * and returns a 'Curl_addrinfo *' with the address information.
  */
 
-struct Curl_addrinfo *Curl_doh(struct connectdata *conn,
+struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                                const char *hostname,
                                int port,
                                int *waitp);
 
-CURLcode Curl_doh_is_resolved(struct connectdata *conn,
+CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                               struct Curl_dns_entry **dns);
 
 int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);
index ce9a052..3a1435f 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index f70b1db..ac1ea36 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 38d370b..ada7e0c 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
  ***************************************************************************/
 
 #include "curl_setup.h"
-#include "strdup.h"
 #include "dynbuf.h"
-
-/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
+#ifdef BUILDING_LIBCURL
 #include "curl_memory.h"
+#endif
 #include "memdebug.h"
 
 #define MIN_FIRST_ALLOC 32
@@ -94,11 +93,15 @@ static CURLcode dyn_nappend(struct dynbuf *s,
   }
 
   if(a != s->allc) {
-    s->bufr = Curl_saferealloc(s->bufr, a);
-    if(!s->bufr) {
+    /* this logic is not using Curl_saferealloc() to make the tool not have to
+       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;
       return CURLE_OUT_OF_MEMORY;
     }
+    s->bufr = p;
     s->allc = a;
   }
 
@@ -143,6 +146,7 @@ CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
   else {
     memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
     s->leng = trail;
+    s->bufr[s->leng] = 0;
   }
   return CURLE_OK;
 
@@ -173,15 +177,22 @@ CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
 }
 
 /*
- * Append a string printf()-style
+ * Append a string vprintf()-style
  */
-CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
 {
+#ifdef BUILDING_LIBCURL
+  int rc;
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  rc = Curl_dyn_vprintf(s, fmt, ap);
+
+  if(!rc)
+    return CURLE_OK;
+#else
   char *str;
-  va_list ap;
-  va_start(ap, fmt);
   str = vaprintf(fmt, ap); /* this allocs a new string to append */
-  va_end(ap);
 
   if(str) {
     CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str));
@@ -190,10 +201,27 @@ CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
   }
   /* If we failed, we cleanup the whole buffer and return error */
   Curl_dyn_free(s);
+#endif
   return CURLE_OUT_OF_MEMORY;
 }
 
 /*
+ * Append a string printf()-style
+ */
+CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+{
+  CURLcode result;
+  va_list ap;
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  DEBUGASSERT(!s->leng || s->bufr);
+  va_start(ap, fmt);
+  result = Curl_dyn_vaddf(s, fmt, ap);
+  va_end(ap);
+  return result;
+}
+
+/*
  * Returns a pointer to the buffer.
  */
 char *Curl_dyn_ptr(const struct dynbuf *s)
index ecc9957..484e40c 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
  *
  ***************************************************************************/
 
+#ifndef BUILDING_LIBCURL
+/* this renames the functions so that the tool code can use the same code
+   without getting symbol collisions */
+#define Curl_dyn_init(a,b) curlx_dyn_init(a,b)
+#define Curl_dyn_add(a,b) curlx_dyn_add(a,b)
+#define Curl_dyn_addn(a,b,c) curlx_dyn_addn(a,b,c)
+#define Curl_dyn_addf curlx_dyn_addf
+#define Curl_dyn_vaddf curlx_dyn_vaddf
+#define Curl_dyn_free(a) curlx_dyn_free(a)
+#define Curl_dyn_ptr(a) curlx_dyn_ptr(a)
+#define Curl_dyn_uptr(a) curlx_dyn_uptr(a)
+#define Curl_dyn_len(a) curlx_dyn_len(a)
+#define Curl_dyn_reset(a) curlx_dyn_reset(a)
+#define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b)
+#define curlx_dynbuf dynbuf /* for the struct name */
+#endif
+
 struct dynbuf {
   char *bufr;    /* point to a null-terminated allocated buffer */
   size_t leng;   /* number of bytes *EXCLUDING* the zero terminator */
@@ -40,12 +57,18 @@ CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
   WARN_UNUSED_RESULT;
 CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
   WARN_UNUSED_RESULT;
+CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
+  WARN_UNUSED_RESULT;
 void Curl_dyn_reset(struct dynbuf *s);
 CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail);
 char *Curl_dyn_ptr(const struct dynbuf *s);
 unsigned char *Curl_dyn_uptr(const struct dynbuf *s);
 size_t Curl_dyn_len(const struct dynbuf *s);
 
+/* returns 0 on success, -1 on error */
+/* The implementation of this function exists in mprintf.c */
+int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
+
 /* Dynamic buffer max sizes */
 #define DYN_DOH_RESPONSE    3000
 #define DYN_DOH_CNAME       256
@@ -60,4 +83,6 @@ size_t Curl_dyn_len(const struct dynbuf *s);
 #define DYN_PROXY_CONNECT_HEADERS 16384
 #define DYN_QLOG_NAME       1024
 #define DYN_H1_TRAILER      4096
+#define DYN_PINGPPONG_CMD   (64*1024)
+#define DYN_IMAP_CMD        (64*1024)
 #endif
index a69eb9e..0fb255a 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -78,6 +78,8 @@
 #include "system_win32.h"
 #include "http2.h"
 #include "dynbuf.h"
+#include "altsvc.h"
+#include "hsts.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -105,7 +107,6 @@ static long          init_flags;
 #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
 #endif
 
-#ifndef __SYMBIAN32__
 /*
  * If a memory-using function (like curl_getenv) is used before
  * curl_global_init() is called, we need to have these pointers set already.
@@ -118,22 +119,15 @@ curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
 #if defined(WIN32) && defined(UNICODE)
 curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
 #endif
-#else
-/*
- * Symbian OS doesn't support initialization to code in writable static data.
- * Initialization will occur in the curl_global_init() call.
- */
-curl_malloc_callback Curl_cmalloc;
-curl_free_callback Curl_cfree;
-curl_realloc_callback Curl_crealloc;
-curl_strdup_callback Curl_cstrdup;
-curl_calloc_callback Curl_ccalloc;
-#endif
 
 #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
 #  pragma warning(default:4232) /* MSVC extension, dllimport identity */
 #endif
 
+#ifdef DEBUGBUILD
+static char *leakpointer;
+#endif
+
 /**
  * curl_global_init() globally initializes curl given a bitwise set of the
  * different features of what to initialize.
@@ -200,6 +194,12 @@ static CURLcode global_init(long flags, bool memoryfuncs)
 
   init_flags = flags;
 
+#ifdef DEBUGBUILD
+  if(getenv("CURL_GLOBAL_INIT"))
+    /* alloc data that will leak if *cleanup() is not called! */
+    leakpointer = malloc(1);
+#endif
+
   return CURLE_OK;
 
   fail:
@@ -275,6 +275,9 @@ void curl_global_cleanup(void)
 #ifdef USE_WOLFSSH
   (void)wolfSSH_Cleanup();
 #endif
+#ifdef DEBUGBUILD
+  free(leakpointer);
+#endif
 
   init_flags  = 0;
 }
@@ -883,10 +886,30 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
       goto fail;
   }
 
+#ifdef USE_ALTSVC
+  if(data->asi) {
+    outcurl->asi = Curl_altsvc_init();
+    if(!outcurl->asi)
+      goto fail;
+    if(outcurl->set.str[STRING_ALTSVC])
+      (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
+  }
+#endif
+#ifdef USE_HSTS
+  if(data->hsts) {
+    outcurl->hsts = Curl_hsts_init();
+    if(!outcurl->hsts)
+      goto fail;
+    if(outcurl->set.str[STRING_HSTS])
+      (void)Curl_hsts_loadfile(outcurl,
+                               outcurl->hsts, outcurl->set.str[STRING_HSTS]);
+    (void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
+  }
+#endif
   /* Clone the resolver handle, if present, for the new handle */
   if(Curl_resolver_duphandle(outcurl,
-                             &outcurl->state.resolver,
-                             data->state.resolver))
+                             &outcurl->state.async.resolver,
+                             data->state.async.resolver))
     goto fail;
 
 #ifdef USE_ARES
@@ -930,6 +953,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
     Curl_dyn_free(&outcurl->state.headerb);
     Curl_safefree(outcurl->change.url);
     Curl_safefree(outcurl->change.referer);
+    Curl_altsvc_cleanup(&outcurl->asi);
+    Curl_hsts_cleanup(&outcurl->hsts);
     Curl_freeset(outcurl);
     free(outcurl);
   }
@@ -958,6 +983,7 @@ void curl_easy_reset(struct Curl_easy *data)
 
   data->progress.flags |= PGRS_HIDE;
   data->state.current_speed = -1; /* init to negative == impossible */
+  data->state.retrycount = 0;     /* reset the retry counter */
 
   /* zero out authentication data: */
   memset(&data->state.authhost, 0, sizeof(struct auth));
@@ -1046,7 +1072,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
         /* even if one function returns error, this loops through and frees
            all buffers */
         if(!result)
-          result = Curl_client_write(conn, writebuf[i].type,
+          result = Curl_client_write(data, writebuf[i].type,
                                      Curl_dyn_ptr(&writebuf[i].b),
                                      Curl_dyn_len(&writebuf[i].b));
         Curl_dyn_free(&writebuf[i].b);
@@ -1067,9 +1093,13 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
      (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
     Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
 
-    /* force a recv/send check of this connection, as the data might've been
-       read off the socket already */
-    data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
+    /* reset the too-slow time keeper */
+    data->state.keeps_speed.tv_sec = 0;
+
+    if(!data->state.tempcount)
+      /* if not pausing again, force a recv/send check of this connection as
+         the data might've been read off the socket already */
+      data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
     if(data->multi)
       Curl_update_timer(data->multi);
   }
@@ -1126,8 +1156,13 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
   if(result)
     return result;
 
+  if(!data->conn)
+    /* on first invoke, the transfer has been detached from the connection and
+       needs to be reattached */
+    Curl_attach_connnection(data, c);
+
   *n = 0;
-  result = Curl_read(c, sfd, buffer, buflen, &n1);
+  result = Curl_read(data, sfd, buffer, buflen, &n1);
 
   if(result)
     return result;
@@ -1156,8 +1191,13 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
   if(result)
     return result;
 
+  if(!data->conn)
+    /* on first invoke, the transfer has been detached from the connection and
+       needs to be reattached */
+    Curl_attach_connnection(data, c);
+
   *n = 0;
-  result = Curl_write(c, sfd, buffer, buflen, &n1);
+  result = Curl_write(data, sfd, buffer, buflen, &n1);
 
   if(n1 == -1)
     return CURLE_SEND_ERROR;
@@ -1176,16 +1216,16 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
  *
  * Returns always 0.
  */
-static int conn_upkeep(struct connectdata *conn,
+static int conn_upkeep(struct Curl_easy *data,
+                       struct connectdata *conn,
                        void *param)
 {
   /* Param is unused. */
   (void)param;
 
-  if(conn->handler->connection_check) {
+  if(conn->handler->connection_check)
     /* Do a protocol-specific keepalive check on the connection. */
-    conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
-  }
+    conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
 
   return 0; /* continue iteration */
 }
diff --git a/Utilities/cmcurl/lib/easygetopt.c b/Utilities/cmcurl/lib/easygetopt.c
new file mode 100644 (file)
index 0000000..7b2213f
--- /dev/null
@@ -0,0 +1,96 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ | |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             ___|___/|_| ______|
+ *
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel.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.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "strcase.h"
+#include "easyoptions.h"
+
+#ifndef CURL_DISABLE_GETOPTIONS
+
+/* Lookups easy options at runtime */
+static struct curl_easyoption *lookup(const char *name, CURLoption id)
+{
+  DEBUGASSERT(name || id);
+  DEBUGASSERT(!Curl_easyopts_check());
+  if(name || id) {
+    struct curl_easyoption *o = &Curl_easyopts[0];
+    do {
+      if(name) {
+        if(strcasecompare(o->name, name))
+          return o;
+      }
+      else {
+        if((o->id == id) && !(o->flags & CURLOT_FLAG_ALIAS))
+          /* don't match alias options */
+          return o;
+      }
+      o++;
+    } while(o->name);
+  }
+  return NULL;
+}
+
+const struct curl_easyoption *curl_easy_option_by_name(const char *name)
+{
+  /* when name is used, the id argument is ignored */
+  return lookup(name, CURLOPT_LASTENTRY);
+}
+
+const struct curl_easyoption *curl_easy_option_by_id(CURLoption id)
+{
+  return lookup(NULL, id);
+}
+
+/* Iterates over available options */
+const struct curl_easyoption *
+curl_easy_option_next(const struct curl_easyoption *prev)
+{
+  if(prev && prev->name) {
+    prev++;
+    if(prev->name)
+      return prev;
+  }
+  else if(!prev)
+    return &Curl_easyopts[0];
+  return NULL;
+}
+
+#else
+const struct curl_easyoption *curl_easy_option_by_name(const char *name)
+{
+  (void)name;
+  return NULL;
+}
+
+const struct curl_easyoption *curl_easy_option_by_id (CURLoption id)
+{
+  (void)id;
+  return NULL;
+}
+
+const struct curl_easyoption *
+curl_easy_option_next(const struct curl_easyoption *prev)
+{
+  (void)prev;
+  return NULL;
+}
+#endif
index eda0d62..3364418 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
diff --git a/Utilities/cmcurl/lib/easyoptions.c b/Utilities/cmcurl/lib/easyoptions.c
new file mode 100644 (file)
index 0000000..b54829b
--- /dev/null
@@ -0,0 +1,354 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ | |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             ___|___/|_| ______|
+ *
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel.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.
+ *
+ ***************************************************************************/
+
+/* This source code is generated by optiontable.pl - DO NOT EDIT BY HAND */
+
+#include "curl_setup.h"
+#include "easyoptions.h"
+
+/* all easy setopt options listed in alphabetical order */
+struct curl_easyoption Curl_easyopts[] = {
+  {"ABSTRACT_UNIX_SOCKET", CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOT_STRING, 0},
+  {"ACCEPTTIMEOUT_MS", CURLOPT_ACCEPTTIMEOUT_MS, CURLOT_LONG, 0},
+  {"ACCEPT_ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, 0},
+  {"ADDRESS_SCOPE", CURLOPT_ADDRESS_SCOPE, CURLOT_LONG, 0},
+  {"ALTSVC", CURLOPT_ALTSVC, CURLOT_STRING, 0},
+  {"ALTSVC_CTRL", CURLOPT_ALTSVC_CTRL, CURLOT_LONG, 0},
+  {"APPEND", CURLOPT_APPEND, CURLOT_LONG, 0},
+  {"AUTOREFERER", CURLOPT_AUTOREFERER, CURLOT_LONG, 0},
+  {"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
+  {"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
+  {"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
+  {"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
+  {"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
+  {"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
+  {"CHUNK_DATA", CURLOPT_CHUNK_DATA, CURLOT_CBPTR, 0},
+  {"CHUNK_END_FUNCTION", CURLOPT_CHUNK_END_FUNCTION, CURLOT_FUNCTION, 0},
+  {"CLOSESOCKETDATA", CURLOPT_CLOSESOCKETDATA, CURLOT_CBPTR, 0},
+  {"CLOSESOCKETFUNCTION", CURLOPT_CLOSESOCKETFUNCTION, CURLOT_FUNCTION, 0},
+  {"CONNECTTIMEOUT", CURLOPT_CONNECTTIMEOUT, CURLOT_LONG, 0},
+  {"CONNECTTIMEOUT_MS", CURLOPT_CONNECTTIMEOUT_MS, CURLOT_LONG, 0},
+  {"CONNECT_ONLY", CURLOPT_CONNECT_ONLY, CURLOT_LONG, 0},
+  {"CONNECT_TO", CURLOPT_CONNECT_TO, CURLOT_SLIST, 0},
+  {"CONV_FROM_NETWORK_FUNCTION", CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"CONV_FROM_UTF8_FUNCTION", CURLOPT_CONV_FROM_UTF8_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"CONV_TO_NETWORK_FUNCTION", CURLOPT_CONV_TO_NETWORK_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"COOKIE", CURLOPT_COOKIE, CURLOT_STRING, 0},
+  {"COOKIEFILE", CURLOPT_COOKIEFILE, CURLOT_STRING, 0},
+  {"COOKIEJAR", CURLOPT_COOKIEJAR, CURLOT_STRING, 0},
+  {"COOKIELIST", CURLOPT_COOKIELIST, CURLOT_STRING, 0},
+  {"COOKIESESSION", CURLOPT_COOKIESESSION, CURLOT_LONG, 0},
+  {"COPYPOSTFIELDS", CURLOPT_COPYPOSTFIELDS, CURLOT_OBJECT, 0},
+  {"CRLF", CURLOPT_CRLF, CURLOT_LONG, 0},
+  {"CRLFILE", CURLOPT_CRLFILE, CURLOT_STRING, 0},
+  {"CURLU", CURLOPT_CURLU, CURLOT_OBJECT, 0},
+  {"CUSTOMREQUEST", CURLOPT_CUSTOMREQUEST, CURLOT_STRING, 0},
+  {"DEBUGDATA", CURLOPT_DEBUGDATA, CURLOT_CBPTR, 0},
+  {"DEBUGFUNCTION", CURLOPT_DEBUGFUNCTION, CURLOT_FUNCTION, 0},
+  {"DEFAULT_PROTOCOL", CURLOPT_DEFAULT_PROTOCOL, CURLOT_STRING, 0},
+  {"DIRLISTONLY", CURLOPT_DIRLISTONLY, CURLOT_LONG, 0},
+  {"DISALLOW_USERNAME_IN_URL", CURLOPT_DISALLOW_USERNAME_IN_URL,
+   CURLOT_LONG, 0},
+  {"DNS_CACHE_TIMEOUT", CURLOPT_DNS_CACHE_TIMEOUT, CURLOT_LONG, 0},
+  {"DNS_INTERFACE", CURLOPT_DNS_INTERFACE, CURLOT_STRING, 0},
+  {"DNS_LOCAL_IP4", CURLOPT_DNS_LOCAL_IP4, CURLOT_STRING, 0},
+  {"DNS_LOCAL_IP6", CURLOPT_DNS_LOCAL_IP6, CURLOT_STRING, 0},
+  {"DNS_SERVERS", CURLOPT_DNS_SERVERS, CURLOT_STRING, 0},
+  {"DNS_SHUFFLE_ADDRESSES", CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOT_LONG, 0},
+  {"DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOT_LONG, 0},
+  {"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
+  {"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
+  {"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0},
+  {"EXPECT_100_TIMEOUT_MS", CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOT_LONG, 0},
+  {"FAILONERROR", CURLOPT_FAILONERROR, CURLOT_LONG, 0},
+  {"FILE", CURLOPT_WRITEDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"FILETIME", CURLOPT_FILETIME, CURLOT_LONG, 0},
+  {"FNMATCH_DATA", CURLOPT_FNMATCH_DATA, CURLOT_CBPTR, 0},
+  {"FNMATCH_FUNCTION", CURLOPT_FNMATCH_FUNCTION, CURLOT_FUNCTION, 0},
+  {"FOLLOWLOCATION", CURLOPT_FOLLOWLOCATION, CURLOT_LONG, 0},
+  {"FORBID_REUSE", CURLOPT_FORBID_REUSE, CURLOT_LONG, 0},
+  {"FRESH_CONNECT", CURLOPT_FRESH_CONNECT, CURLOT_LONG, 0},
+  {"FTPAPPEND", CURLOPT_APPEND, CURLOT_LONG, CURLOT_FLAG_ALIAS},
+  {"FTPLISTONLY", CURLOPT_DIRLISTONLY, CURLOT_LONG, CURLOT_FLAG_ALIAS},
+  {"FTPPORT", CURLOPT_FTPPORT, CURLOT_STRING, 0},
+  {"FTPSSLAUTH", CURLOPT_FTPSSLAUTH, CURLOT_VALUES, 0},
+  {"FTP_ACCOUNT", CURLOPT_FTP_ACCOUNT, CURLOT_STRING, 0},
+  {"FTP_ALTERNATIVE_TO_USER", CURLOPT_FTP_ALTERNATIVE_TO_USER,
+   CURLOT_STRING, 0},
+  {"FTP_CREATE_MISSING_DIRS", CURLOPT_FTP_CREATE_MISSING_DIRS,
+   CURLOT_LONG, 0},
+  {"FTP_FILEMETHOD", CURLOPT_FTP_FILEMETHOD, CURLOT_VALUES, 0},
+  {"FTP_RESPONSE_TIMEOUT", CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOT_LONG, 0},
+  {"FTP_SKIP_PASV_IP", CURLOPT_FTP_SKIP_PASV_IP, CURLOT_LONG, 0},
+  {"FTP_SSL", CURLOPT_USE_SSL, CURLOT_VALUES, CURLOT_FLAG_ALIAS},
+  {"FTP_SSL_CCC", CURLOPT_FTP_SSL_CCC, CURLOT_LONG, 0},
+  {"FTP_USE_EPRT", CURLOPT_FTP_USE_EPRT, CURLOT_LONG, 0},
+  {"FTP_USE_EPSV", CURLOPT_FTP_USE_EPSV, CURLOT_LONG, 0},
+  {"FTP_USE_PRET", CURLOPT_FTP_USE_PRET, CURLOT_LONG, 0},
+  {"GSSAPI_DELEGATION", CURLOPT_GSSAPI_DELEGATION, CURLOT_VALUES, 0},
+  {"HAPPY_EYEBALLS_TIMEOUT_MS", CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
+   CURLOT_LONG, 0},
+  {"HAPROXYPROTOCOL", CURLOPT_HAPROXYPROTOCOL, CURLOT_LONG, 0},
+  {"HEADER", CURLOPT_HEADER, CURLOT_LONG, 0},
+  {"HEADERDATA", CURLOPT_HEADERDATA, CURLOT_CBPTR, 0},
+  {"HEADERFUNCTION", CURLOPT_HEADERFUNCTION, CURLOT_FUNCTION, 0},
+  {"HEADEROPT", CURLOPT_HEADEROPT, CURLOT_VALUES, 0},
+  {"HSTS", CURLOPT_HSTS, CURLOT_STRING, 0},
+  {"HSTSREADDATA", CURLOPT_HSTSREADDATA, CURLOT_CBPTR, 0},
+  {"HSTSREADFUNCTION", CURLOPT_HSTSREADFUNCTION, CURLOT_FUNCTION, 0},
+  {"HSTSWRITEDATA", CURLOPT_HSTSWRITEDATA, CURLOT_CBPTR, 0},
+  {"HSTSWRITEFUNCTION", CURLOPT_HSTSWRITEFUNCTION, CURLOT_FUNCTION, 0},
+  {"HSTS_CTRL", CURLOPT_HSTS_CTRL, CURLOT_LONG, 0},
+  {"HTTP09_ALLOWED", CURLOPT_HTTP09_ALLOWED, CURLOT_LONG, 0},
+  {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0},
+  {"HTTPAUTH", CURLOPT_HTTPAUTH, CURLOT_VALUES, 0},
+  {"HTTPGET", CURLOPT_HTTPGET, CURLOT_LONG, 0},
+  {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0},
+  {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0},
+  {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0},
+  {"HTTP_CONTENT_DECODING", CURLOPT_HTTP_CONTENT_DECODING, CURLOT_LONG, 0},
+  {"HTTP_TRANSFER_DECODING", CURLOPT_HTTP_TRANSFER_DECODING, CURLOT_LONG, 0},
+  {"HTTP_VERSION", CURLOPT_HTTP_VERSION, CURLOT_VALUES, 0},
+  {"IGNORE_CONTENT_LENGTH", CURLOPT_IGNORE_CONTENT_LENGTH, CURLOT_LONG, 0},
+  {"INFILE", CURLOPT_READDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"INFILESIZE", CURLOPT_INFILESIZE, CURLOT_LONG, 0},
+  {"INFILESIZE_LARGE", CURLOPT_INFILESIZE_LARGE, CURLOT_OFF_T, 0},
+  {"INTERFACE", CURLOPT_INTERFACE, CURLOT_STRING, 0},
+  {"INTERLEAVEDATA", CURLOPT_INTERLEAVEDATA, CURLOT_CBPTR, 0},
+  {"INTERLEAVEFUNCTION", CURLOPT_INTERLEAVEFUNCTION, CURLOT_FUNCTION, 0},
+  {"IOCTLDATA", CURLOPT_IOCTLDATA, CURLOT_CBPTR, 0},
+  {"IOCTLFUNCTION", CURLOPT_IOCTLFUNCTION, CURLOT_FUNCTION, 0},
+  {"IPRESOLVE", CURLOPT_IPRESOLVE, CURLOT_VALUES, 0},
+  {"ISSUERCERT", CURLOPT_ISSUERCERT, CURLOT_STRING, 0},
+  {"ISSUERCERT_BLOB", CURLOPT_ISSUERCERT_BLOB, CURLOT_BLOB, 0},
+  {"KEEP_SENDING_ON_ERROR", CURLOPT_KEEP_SENDING_ON_ERROR, CURLOT_LONG, 0},
+  {"KEYPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, 0},
+  {"KRB4LEVEL", CURLOPT_KRBLEVEL, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"KRBLEVEL", CURLOPT_KRBLEVEL, CURLOT_STRING, 0},
+  {"LOCALPORT", CURLOPT_LOCALPORT, CURLOT_LONG, 0},
+  {"LOCALPORTRANGE", CURLOPT_LOCALPORTRANGE, CURLOT_LONG, 0},
+  {"LOGIN_OPTIONS", CURLOPT_LOGIN_OPTIONS, CURLOT_STRING, 0},
+  {"LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT, CURLOT_LONG, 0},
+  {"LOW_SPEED_TIME", CURLOPT_LOW_SPEED_TIME, CURLOT_LONG, 0},
+  {"MAIL_AUTH", CURLOPT_MAIL_AUTH, CURLOT_STRING, 0},
+  {"MAIL_FROM", CURLOPT_MAIL_FROM, CURLOT_STRING, 0},
+  {"MAIL_RCPT", CURLOPT_MAIL_RCPT, CURLOT_SLIST, 0},
+  {"MAIL_RCPT_ALLLOWFAILS", CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOT_LONG, 0},
+  {"MAXAGE_CONN", CURLOPT_MAXAGE_CONN, CURLOT_LONG, 0},
+  {"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0},
+  {"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0},
+  {"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0},
+  {"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0},
+  {"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 0},
+  {"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0},
+  {"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0},
+  {"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0},
+  {"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0},
+  {"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 0},
+  {"NEW_FILE_PERMS", CURLOPT_NEW_FILE_PERMS, CURLOT_LONG, 0},
+  {"NOBODY", CURLOPT_NOBODY, CURLOT_LONG, 0},
+  {"NOPROGRESS", CURLOPT_NOPROGRESS, CURLOT_LONG, 0},
+  {"NOPROXY", CURLOPT_NOPROXY, CURLOT_STRING, 0},
+  {"NOSIGNAL", CURLOPT_NOSIGNAL, CURLOT_LONG, 0},
+  {"OPENSOCKETDATA", CURLOPT_OPENSOCKETDATA, CURLOT_CBPTR, 0},
+  {"OPENSOCKETFUNCTION", CURLOPT_OPENSOCKETFUNCTION, CURLOT_FUNCTION, 0},
+  {"PASSWORD", CURLOPT_PASSWORD, CURLOT_STRING, 0},
+  {"PATH_AS_IS", CURLOPT_PATH_AS_IS, CURLOT_LONG, 0},
+  {"PINNEDPUBLICKEY", CURLOPT_PINNEDPUBLICKEY, CURLOT_STRING, 0},
+  {"PIPEWAIT", CURLOPT_PIPEWAIT, CURLOT_LONG, 0},
+  {"PORT", CURLOPT_PORT, CURLOT_LONG, 0},
+  {"POST", CURLOPT_POST, CURLOT_LONG, 0},
+  {"POST301", CURLOPT_POSTREDIR, CURLOT_VALUES, CURLOT_FLAG_ALIAS},
+  {"POSTFIELDS", CURLOPT_POSTFIELDS, CURLOT_OBJECT, 0},
+  {"POSTFIELDSIZE", CURLOPT_POSTFIELDSIZE, CURLOT_LONG, 0},
+  {"POSTFIELDSIZE_LARGE", CURLOPT_POSTFIELDSIZE_LARGE, CURLOT_OFF_T, 0},
+  {"POSTQUOTE", CURLOPT_POSTQUOTE, CURLOT_SLIST, 0},
+  {"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0},
+  {"PREQUOTE", CURLOPT_PREQUOTE, CURLOT_SLIST, 0},
+  {"PRE_PROXY", CURLOPT_PRE_PROXY, CURLOT_STRING, 0},
+  {"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0},
+  {"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"PROGRESSFUNCTION", CURLOPT_PROGRESSFUNCTION, CURLOT_FUNCTION, 0},
+  {"PROTOCOLS", CURLOPT_PROTOCOLS, CURLOT_LONG, 0},
+  {"PROXY", CURLOPT_PROXY, CURLOT_STRING, 0},
+  {"PROXYAUTH", CURLOPT_PROXYAUTH, CURLOT_VALUES, 0},
+  {"PROXYHEADER", CURLOPT_PROXYHEADER, CURLOT_SLIST, 0},
+  {"PROXYPASSWORD", CURLOPT_PROXYPASSWORD, CURLOT_STRING, 0},
+  {"PROXYPORT", CURLOPT_PROXYPORT, CURLOT_LONG, 0},
+  {"PROXYTYPE", CURLOPT_PROXYTYPE, CURLOT_VALUES, 0},
+  {"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0},
+  {"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0},
+  {"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0},
+  {"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0},
+  {"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0},
+  {"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0},
+  {"PROXY_ISSUERCERT_BLOB", CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOT_BLOB, 0},
+  {"PROXY_KEYPASSWD", CURLOPT_PROXY_KEYPASSWD, CURLOT_STRING, 0},
+  {"PROXY_PINNEDPUBLICKEY", CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOT_STRING, 0},
+  {"PROXY_SERVICE_NAME", CURLOPT_PROXY_SERVICE_NAME, CURLOT_STRING, 0},
+  {"PROXY_SSLCERT", CURLOPT_PROXY_SSLCERT, CURLOT_STRING, 0},
+  {"PROXY_SSLCERTTYPE", CURLOPT_PROXY_SSLCERTTYPE, CURLOT_STRING, 0},
+  {"PROXY_SSLCERT_BLOB", CURLOPT_PROXY_SSLCERT_BLOB, CURLOT_BLOB, 0},
+  {"PROXY_SSLKEY", CURLOPT_PROXY_SSLKEY, CURLOT_STRING, 0},
+  {"PROXY_SSLKEYTYPE", CURLOPT_PROXY_SSLKEYTYPE, CURLOT_STRING, 0},
+  {"PROXY_SSLKEY_BLOB", CURLOPT_PROXY_SSLKEY_BLOB, CURLOT_BLOB, 0},
+  {"PROXY_SSLVERSION", CURLOPT_PROXY_SSLVERSION, CURLOT_VALUES, 0},
+  {"PROXY_SSL_CIPHER_LIST", CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOT_STRING, 0},
+  {"PROXY_SSL_OPTIONS", CURLOPT_PROXY_SSL_OPTIONS, CURLOT_LONG, 0},
+  {"PROXY_SSL_VERIFYHOST", CURLOPT_PROXY_SSL_VERIFYHOST, CURLOT_LONG, 0},
+  {"PROXY_SSL_VERIFYPEER", CURLOPT_PROXY_SSL_VERIFYPEER, CURLOT_LONG, 0},
+  {"PROXY_TLS13_CIPHERS", CURLOPT_PROXY_TLS13_CIPHERS, CURLOT_STRING, 0},
+  {"PROXY_TLSAUTH_PASSWORD", CURLOPT_PROXY_TLSAUTH_PASSWORD,
+   CURLOT_STRING, 0},
+  {"PROXY_TLSAUTH_TYPE", CURLOPT_PROXY_TLSAUTH_TYPE, CURLOT_STRING, 0},
+  {"PROXY_TLSAUTH_USERNAME", CURLOPT_PROXY_TLSAUTH_USERNAME,
+   CURLOT_STRING, 0},
+  {"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0},
+  {"PUT", CURLOPT_PUT, CURLOT_LONG, 0},
+  {"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0},
+  {"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0},
+  {"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0},
+  {"READDATA", CURLOPT_READDATA, CURLOT_CBPTR, 0},
+  {"READFUNCTION", CURLOPT_READFUNCTION, CURLOT_FUNCTION, 0},
+  {"REDIR_PROTOCOLS", CURLOPT_REDIR_PROTOCOLS, CURLOT_LONG, 0},
+  {"REFERER", CURLOPT_REFERER, CURLOT_STRING, 0},
+  {"REQUEST_TARGET", CURLOPT_REQUEST_TARGET, CURLOT_STRING, 0},
+  {"RESOLVE", CURLOPT_RESOLVE, CURLOT_SLIST, 0},
+  {"RESOLVER_START_DATA", CURLOPT_RESOLVER_START_DATA, CURLOT_CBPTR, 0},
+  {"RESOLVER_START_FUNCTION", CURLOPT_RESOLVER_START_FUNCTION,
+   CURLOT_FUNCTION, 0},
+  {"RESUME_FROM", CURLOPT_RESUME_FROM, CURLOT_LONG, 0},
+  {"RESUME_FROM_LARGE", CURLOPT_RESUME_FROM_LARGE, CURLOT_OFF_T, 0},
+  {"RTSPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, CURLOT_FLAG_ALIAS},
+  {"RTSP_CLIENT_CSEQ", CURLOPT_RTSP_CLIENT_CSEQ, CURLOT_LONG, 0},
+  {"RTSP_REQUEST", CURLOPT_RTSP_REQUEST, CURLOT_VALUES, 0},
+  {"RTSP_SERVER_CSEQ", CURLOPT_RTSP_SERVER_CSEQ, CURLOT_LONG, 0},
+  {"RTSP_SESSION_ID", CURLOPT_RTSP_SESSION_ID, CURLOT_STRING, 0},
+  {"RTSP_STREAM_URI", CURLOPT_RTSP_STREAM_URI, CURLOT_STRING, 0},
+  {"RTSP_TRANSPORT", CURLOPT_RTSP_TRANSPORT, CURLOT_STRING, 0},
+  {"SASL_AUTHZID", CURLOPT_SASL_AUTHZID, CURLOT_STRING, 0},
+  {"SASL_IR", CURLOPT_SASL_IR, CURLOT_LONG, 0},
+  {"SEEKDATA", CURLOPT_SEEKDATA, CURLOT_CBPTR, 0},
+  {"SEEKFUNCTION", CURLOPT_SEEKFUNCTION, CURLOT_FUNCTION, 0},
+  {"SERVER_RESPONSE_TIMEOUT", CURLOPT_FTP_RESPONSE_TIMEOUT,
+   CURLOT_LONG, CURLOT_FLAG_ALIAS},
+  {"SERVICE_NAME", CURLOPT_SERVICE_NAME, CURLOT_STRING, 0},
+  {"SHARE", CURLOPT_SHARE, CURLOT_OBJECT, 0},
+  {"SOCKOPTDATA", CURLOPT_SOCKOPTDATA, CURLOT_CBPTR, 0},
+  {"SOCKOPTFUNCTION", CURLOPT_SOCKOPTFUNCTION, CURLOT_FUNCTION, 0},
+  {"SOCKS5_AUTH", CURLOPT_SOCKS5_AUTH, CURLOT_LONG, 0},
+  {"SOCKS5_GSSAPI_NEC", CURLOPT_SOCKS5_GSSAPI_NEC, CURLOT_LONG, 0},
+  {"SOCKS5_GSSAPI_SERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOT_STRING, 0},
+  {"SSH_AUTH_TYPES", CURLOPT_SSH_AUTH_TYPES, CURLOT_VALUES, 0},
+  {"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
+  {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
+   CURLOT_STRING, 0},
+  {"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0},
+  {"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
+  {"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
+  {"SSH_PRIVATE_KEYFILE", CURLOPT_SSH_PRIVATE_KEYFILE, CURLOT_STRING, 0},
+  {"SSH_PUBLIC_KEYFILE", CURLOPT_SSH_PUBLIC_KEYFILE, CURLOT_STRING, 0},
+  {"SSLCERT", CURLOPT_SSLCERT, CURLOT_STRING, 0},
+  {"SSLCERTPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"SSLCERTTYPE", CURLOPT_SSLCERTTYPE, CURLOT_STRING, 0},
+  {"SSLCERT_BLOB", CURLOPT_SSLCERT_BLOB, CURLOT_BLOB, 0},
+  {"SSLENGINE", CURLOPT_SSLENGINE, CURLOT_STRING, 0},
+  {"SSLENGINE_DEFAULT", CURLOPT_SSLENGINE_DEFAULT, CURLOT_LONG, 0},
+  {"SSLKEY", CURLOPT_SSLKEY, CURLOT_STRING, 0},
+  {"SSLKEYPASSWD", CURLOPT_KEYPASSWD, CURLOT_STRING, CURLOT_FLAG_ALIAS},
+  {"SSLKEYTYPE", CURLOPT_SSLKEYTYPE, CURLOT_STRING, 0},
+  {"SSLKEY_BLOB", CURLOPT_SSLKEY_BLOB, CURLOT_BLOB, 0},
+  {"SSLVERSION", CURLOPT_SSLVERSION, CURLOT_VALUES, 0},
+  {"SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST, CURLOT_STRING, 0},
+  {"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA, CURLOT_CBPTR, 0},
+  {"SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, CURLOT_FUNCTION, 0},
+  {"SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CURLOT_STRING, 0},
+  {"SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN, CURLOT_LONG, 0},
+  {"SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN, CURLOT_LONG, 0},
+  {"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0},
+  {"SSL_OPTIONS", CURLOPT_SSL_OPTIONS, CURLOT_VALUES, 0},
+  {"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE, CURLOT_LONG, 0},
+  {"SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST, CURLOT_LONG, 0},
+  {"SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER, CURLOT_LONG, 0},
+  {"SSL_VERIFYSTATUS", CURLOPT_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
+  {"STDERR", CURLOPT_STDERR, CURLOT_OBJECT, 0},
+  {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0},
+  {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0},
+  {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0},
+  {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS,
+   CURLOT_LONG, 0},
+  {"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0},
+  {"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0},
+  {"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0},
+  {"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0},
+  {"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0},
+  {"TELNETOPTIONS", CURLOPT_TELNETOPTIONS, CURLOT_SLIST, 0},
+  {"TFTP_BLKSIZE", CURLOPT_TFTP_BLKSIZE, CURLOT_LONG, 0},
+  {"TFTP_NO_OPTIONS", CURLOPT_TFTP_NO_OPTIONS, CURLOT_LONG, 0},
+  {"TIMECONDITION", CURLOPT_TIMECONDITION, CURLOT_VALUES, 0},
+  {"TIMEOUT", CURLOPT_TIMEOUT, CURLOT_LONG, 0},
+  {"TIMEOUT_MS", CURLOPT_TIMEOUT_MS, CURLOT_LONG, 0},
+  {"TIMEVALUE", CURLOPT_TIMEVALUE, CURLOT_LONG, 0},
+  {"TIMEVALUE_LARGE", CURLOPT_TIMEVALUE_LARGE, CURLOT_OFF_T, 0},
+  {"TLS13_CIPHERS", CURLOPT_TLS13_CIPHERS, CURLOT_STRING, 0},
+  {"TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD, CURLOT_STRING, 0},
+  {"TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE, CURLOT_STRING, 0},
+  {"TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME, CURLOT_STRING, 0},
+  {"TRAILERDATA", CURLOPT_TRAILERDATA, CURLOT_CBPTR, 0},
+  {"TRAILERFUNCTION", CURLOPT_TRAILERFUNCTION, CURLOT_FUNCTION, 0},
+  {"TRANSFERTEXT", CURLOPT_TRANSFERTEXT, CURLOT_LONG, 0},
+  {"TRANSFER_ENCODING", CURLOPT_TRANSFER_ENCODING, CURLOT_LONG, 0},
+  {"UNIX_SOCKET_PATH", CURLOPT_UNIX_SOCKET_PATH, CURLOT_STRING, 0},
+  {"UNRESTRICTED_AUTH", CURLOPT_UNRESTRICTED_AUTH, CURLOT_LONG, 0},
+  {"UPKEEP_INTERVAL_MS", CURLOPT_UPKEEP_INTERVAL_MS, CURLOT_LONG, 0},
+  {"UPLOAD", CURLOPT_UPLOAD, CURLOT_LONG, 0},
+  {"UPLOAD_BUFFERSIZE", CURLOPT_UPLOAD_BUFFERSIZE, CURLOT_LONG, 0},
+  {"URL", CURLOPT_URL, CURLOT_STRING, 0},
+  {"USERAGENT", CURLOPT_USERAGENT, CURLOT_STRING, 0},
+  {"USERNAME", CURLOPT_USERNAME, CURLOT_STRING, 0},
+  {"USERPWD", CURLOPT_USERPWD, CURLOT_STRING, 0},
+  {"USE_SSL", CURLOPT_USE_SSL, CURLOT_VALUES, 0},
+  {"VERBOSE", CURLOPT_VERBOSE, CURLOT_LONG, 0},
+  {"WILDCARDMATCH", CURLOPT_WILDCARDMATCH, CURLOT_LONG, 0},
+  {"WRITEDATA", CURLOPT_WRITEDATA, CURLOT_CBPTR, 0},
+  {"WRITEFUNCTION", CURLOPT_WRITEFUNCTION, CURLOT_FUNCTION, 0},
+  {"WRITEHEADER", CURLOPT_HEADERDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
+  {"XFERINFODATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, 0},
+  {"XFERINFOFUNCTION", CURLOPT_XFERINFOFUNCTION, CURLOT_FUNCTION, 0},
+  {"XOAUTH2_BEARER", CURLOPT_XOAUTH2_BEARER, CURLOT_STRING, 0},
+  {NULL, CURLOPT_LASTENTRY, 0, 0} /* end of table */
+};
+
+#ifdef DEBUGBUILD
+/*
+ * Curl_easyopts_check() is a debug-only function that returns non-zero
+ * if this source file is not in sync with the options listed in curl/curl.h
+ */
+int Curl_easyopts_check(void)
+{
+  return ((CURLOPT_LASTENTRY%10000) != (305 + 1));
+}
+#endif
diff --git a/Utilities/cmcurl/lib/easyoptions.h b/Utilities/cmcurl/lib/easyoptions.h
new file mode 100644 (file)
index 0000000..91e1190
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_EASYOPTIONS_H
+#define HEADER_CURL_EASYOPTIONS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2020, 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.
+ *
+ ***************************************************************************/
+
+/* should probably go into the public header */
+
+#include <curl/curl.h>
+
+/* generated table with all easy options */
+extern struct curl_easyoption Curl_easyopts[];
+
+#ifdef DEBUGBUILD
+int Curl_easyopts_check(void);
+#endif
+#endif
index 2bea145..683b6fc 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -86,7 +86,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
   if(inlength < 0)
     return NULL;
 
-  Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH);
+  Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH * 3);
 
   length = (inlength?(size_t)inlength:strlen(string));
   if(!length)
index 586db7e..46cb590 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index cd3e49c..dd8a1fd 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -67,8 +67,7 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \
-  defined(__SYMBIAN32__)
+#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
 #define DOS_FILESYSTEM 1
 #endif
 
  * Forward declarations.
  */
 
-static CURLcode file_do(struct connectdata *, bool *done);
-static CURLcode file_done(struct connectdata *conn,
+static CURLcode file_do(struct Curl_easy *data, bool *done);
+static CURLcode file_done(struct Curl_easy *data,
                           CURLcode status, bool premature);
-static CURLcode file_connect(struct connectdata *conn, bool *done);
-static CURLcode file_disconnect(struct connectdata *conn,
+static CURLcode file_connect(struct Curl_easy *data, bool *done);
+static CURLcode file_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection);
-static CURLcode file_setup_connection(struct connectdata *conn);
+static CURLcode file_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
 
 /*
  * FILE scheme handler.
@@ -112,15 +113,18 @@ const struct Curl_handler Curl_handler_file = {
   ZERO_NULL,                            /* connection_check */
   0,                                    /* defport */
   CURLPROTO_FILE,                       /* protocol */
+  CURLPROTO_FILE,                       /* family */
   PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
 };
 
 
-static CURLcode file_setup_connection(struct connectdata *conn)
+static CURLcode file_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
+  (void)conn;
   /* allocate the FILE specific struct */
-  conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO));
-  if(!conn->data->req.protop)
+  data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
+  if(!data->req.p.file)
     return CURLE_OUT_OF_MEMORY;
 
   return CURLE_OK;
@@ -131,11 +135,10 @@ static CURLcode file_setup_connection(struct connectdata *conn)
  * do protocol-specific actions at connect-time.  We emulate a
  * connect-then-transfer protocol and "connect" to the file here
  */
-static CURLcode file_connect(struct connectdata *conn, bool *done)
+static CURLcode file_connect(struct Curl_easy *data, bool *done)
 {
-  struct Curl_easy *data = conn->data;
   char *real_path;
-  struct FILEPROTO *file = data->req.protop;
+  struct FILEPROTO *file = data->req.p.file;
   int fd;
 #ifdef DOS_FILESYSTEM
   size_t i;
@@ -198,7 +201,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
   file->fd = fd;
   if(!data->set.upload && (fd == -1)) {
     failf(data, "Couldn't open file %s", data->state.up.path);
-    file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
+    file_done(data, CURLE_FILE_COULDNT_READ_FILE, FALSE);
     return CURLE_FILE_COULDNT_READ_FILE;
   }
   *done = TRUE;
@@ -206,10 +209,10 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode file_done(struct connectdata *conn,
-                               CURLcode status, bool premature)
+static CURLcode file_done(struct Curl_easy *data,
+                          CURLcode status, bool premature)
 {
-  struct FILEPROTO *file = conn->data->req.protop;
+  struct FILEPROTO *file = data->req.p.file;
   (void)status; /* not used */
   (void)premature; /* not used */
 
@@ -224,21 +227,13 @@ static CURLcode file_done(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static CURLcode file_disconnect(struct connectdata *conn,
+static CURLcode file_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection)
 {
-  struct FILEPROTO *file = conn->data->req.protop;
   (void)dead_connection; /* not used */
-
-  if(file) {
-    Curl_safefree(file->freepath);
-    file->path = NULL;
-    if(file->fd != -1)
-      close(file->fd);
-    file->fd = -1;
-  }
-
-  return CURLE_OK;
+  (void)conn;
+  return file_done(data, 0, 0);
 }
 
 #ifdef DOS_FILESYSTEM
@@ -247,14 +242,13 @@ static CURLcode file_disconnect(struct connectdata *conn,
 #define DIRSEP '/'
 #endif
 
-static CURLcode file_upload(struct connectdata *conn)
+static CURLcode file_upload(struct Curl_easy *data)
 {
-  struct FILEPROTO *file = conn->data->req.protop;
+  struct FILEPROTO *file = data->req.p.file;
   const char *dir = strchr(file->path, DIRSEP);
   int fd;
   int mode;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
   curl_off_t bytecount = 0;
   struct_stat file_stat;
@@ -264,7 +258,7 @@ static CURLcode file_upload(struct connectdata *conn)
    * Since FILE: doesn't do the full init, we need to provide some extra
    * assignments here.
    */
-  conn->data->req.upload_fromhere = buf;
+  data->req.upload_fromhere = buf;
 
   if(!dir)
     return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
@@ -283,7 +277,7 @@ static CURLcode file_upload(struct connectdata *conn)
   else
     mode = MODE_DEFAULT|O_TRUNC;
 
-  fd = open(file->path, mode, conn->data->set.new_file_perms);
+  fd = open(file->path, mode, data->set.new_file_perms);
   if(fd < 0) {
     failf(data, "Can't open %s for writing", file->path);
     return CURLE_WRITE_ERROR;
@@ -307,7 +301,7 @@ static CURLcode file_upload(struct connectdata *conn)
     size_t nread;
     size_t nwrite;
     size_t readcount;
-    result = Curl_fillreadbuffer(conn, data->set.buffer_size, &readcount);
+    result = Curl_fillreadbuffer(data, data->set.buffer_size, &readcount);
     if(result)
       break;
 
@@ -343,12 +337,12 @@ static CURLcode file_upload(struct connectdata *conn)
 
     Curl_pgrsSetUploadCounter(data, bytecount);
 
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
       result = Curl_speedcheck(data, Curl_now());
   }
-  if(!result && Curl_pgrsUpdate(conn))
+  if(!result && Curl_pgrsUpdate(data))
     result = CURLE_ABORTED_BY_CALLBACK;
 
   close(fd);
@@ -364,7 +358,7 @@ static CURLcode file_upload(struct connectdata *conn)
  * opposed to sockets) we instead perform the whole do-operation in this
  * function.
  */
-static CURLcode file_do(struct connectdata *conn, bool *done)
+static CURLcode file_do(struct Curl_easy *data, bool *done)
 {
   /* This implementation ignores the host name in conformance with
      RFC 1738. Only local files (reachable via the standard file system)
@@ -375,10 +369,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
                           Windows version to have a different struct without
                           having to redefine the simple word 'stat' */
-  curl_off_t expected_size = 0;
+  curl_off_t expected_size = -1;
   bool size_known;
   bool fstated = FALSE;
-  struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
   curl_off_t bytecount = 0;
   int fd;
@@ -389,17 +382,17 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   Curl_pgrsStartNow(data);
 
   if(data->set.upload)
-    return file_upload(conn);
+    return file_upload(data);
 
-  file = conn->data->req.protop;
+  file = data->req.p.file;
 
   /* get the fd from the connection phase */
   fd = file->fd;
 
   /* VMS: This only works reliable for STREAMLF files */
   if(-1 != fstat(fd, &statbuf)) {
-    /* we could stat it, then read out the size */
-    expected_size = statbuf.st_size;
+    if(!S_ISDIR(statbuf.st_mode))
+      expected_size = statbuf.st_size;
     /* and store the modification time */
     data->info.filetime = statbuf.st_mtime;
     fstated = TRUE;
@@ -417,14 +410,16 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
     struct tm buffer;
     const struct tm *tm = &buffer;
     char header[80];
-    msnprintf(header, sizeof(header),
-              "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
-              expected_size);
-    result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
-    if(result)
-      return result;
+    if(expected_size >= 0) {
+      msnprintf(header, sizeof(header),
+                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
+                expected_size);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
+      if(result)
+        return result;
+    }
 
-    result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+    result = Curl_client_write(data, CLIENTWRITE_HEADER,
                                (char *)"Accept-ranges: bytes\r\n", 0);
     if(result)
       return result;
@@ -445,7 +440,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
               tm->tm_min,
               tm->tm_sec,
               data->set.opt_no_body ? "": "\r\n");
-    result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
     if(result)
       return result;
     /* set the file size to make it available post transfer */
@@ -455,7 +450,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   }
 
   /* Check whether file range has been specified */
-  result = Curl_range(conn);
+  result = Curl_range(data);
   if(result)
     return result;
 
@@ -524,18 +519,18 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
     if(size_known)
       expected_size -= nread;
 
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
     if(result)
       return result;
 
     Curl_pgrsSetDownloadCounter(data, bytecount);
 
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
       result = Curl_speedcheck(data, Curl_now());
   }
-  if(Curl_pgrsUpdate(conn))
+  if(Curl_pgrsUpdate(data))
     result = CURLE_ABORTED_BY_CALLBACK;
 
   return result;
index f6b74a7..338f92e 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 2630c9e..b7e9f0f 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2010 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index f4d8f3b..5ae23ad 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2010 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -27,7 +27,7 @@
 
 struct fileinfo {
   struct curl_fileinfo info;
-  struct curl_llist_element list;
+  struct Curl_llist_element list;
 };
 
 struct fileinfo *Curl_fileinfo_alloc(void);
index 1cab2c5..769f06a 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 3766d38..09c6e9c 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 /* used by FormAdd for temporary storage */
 struct FormInfo {
   char *name;
-  bool name_alloc;
   size_t namelength;
   char *value;
-  bool value_alloc;
   curl_off_t contentslength;
   char *contenttype;
-  bool contenttype_alloc;
   long flags;
   char *buffer;      /* pointer to existing buffer used for file upload */
   size_t bufferlength;
   char *showfilename; /* The file name to show. If not set, the actual
                          file name will be used */
-  bool showfilename_alloc;
   char *userp;        /* pointer for the read callback */
   struct curl_slist *contentheader;
   struct FormInfo *more;
+  bool name_alloc;
+  bool value_alloc;
+  bool contenttype_alloc;
+  bool showfilename_alloc;
 };
 
 CURLcode Curl_getformdata(struct Curl_easy *data,
index 7d805fa..f8f970c 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -59,7 +59,7 @@
 #include "fileinfo.h"
 #include "ftplistparser.h"
 #include "curl_range.h"
-#include "curl_sec.h"
+#include "curl_krb5.h"
 #include "strtoofft.h"
 #include "strcase.h"
 #include "vtls/vtls.h"
 
 /* Local API functions */
 #ifndef DEBUGBUILD
-static void _state(struct connectdata *conn,
+static void _state(struct Curl_easy *data,
                    ftpstate newstate);
 #define state(x,y) _state(x,y)
 #else
-static void _state(struct connectdata *conn,
+static void _state(struct Curl_easy *data,
                    ftpstate newstate,
                    int lineno);
 #define state(x,y) _state(x,y,__LINE__)
 #endif
 
-static CURLcode ftp_sendquote(struct connectdata *conn,
+static CURLcode ftp_sendquote(struct Curl_easy *data,
+                              struct connectdata *conn,
                               struct curl_slist *quote);
-static CURLcode ftp_quit(struct connectdata *conn);
-static CURLcode ftp_parse_url_path(struct connectdata *conn);
-static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn);
+static CURLcode ftp_parse_url_path(struct Curl_easy *data);
+static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done);
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-static void ftp_pasv_verbose(struct connectdata *conn,
+static void ftp_pasv_verbose(struct Curl_easy *data,
                              struct Curl_addrinfo *ai,
                              char *newhost, /* ascii version */
                              int port);
 #endif
-static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
-static CURLcode ftp_state_mdtm(struct connectdata *conn);
-static CURLcode ftp_state_quote(struct connectdata *conn,
+static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data);
+static CURLcode ftp_state_mdtm(struct Curl_easy *data);
+static CURLcode ftp_state_quote(struct Curl_easy *data,
                                 bool init, ftpstate instate);
-static CURLcode ftp_nb_type(struct connectdata *conn,
+static CURLcode ftp_nb_type(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool ascii, ftpstate newstate);
 static int ftp_need_type(struct connectdata *conn,
                          bool ascii);
-static CURLcode ftp_do(struct connectdata *conn, bool *done);
-static CURLcode ftp_done(struct connectdata *conn,
+static CURLcode ftp_do(struct Curl_easy *data, bool *done);
+static CURLcode ftp_done(struct Curl_easy *data,
                          CURLcode, bool premature);
-static CURLcode ftp_connect(struct connectdata *conn, bool *done);
-static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
-static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
-static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
-static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks);
-static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks);
-static CURLcode ftp_doing(struct connectdata *conn,
+static CURLcode ftp_connect(struct Curl_easy *data, bool *done);
+static CURLcode ftp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead_connection);
+static CURLcode ftp_do_more(struct Curl_easy *data, int *completed);
+static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done);
+static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn,
+                       curl_socket_t *socks);
+static int ftp_domore_getsock(struct Curl_easy *data,
+                              struct connectdata *conn, curl_socket_t *socks);
+static CURLcode ftp_doing(struct Curl_easy *data,
                           bool *dophase_done);
-static CURLcode ftp_setup_connection(struct connectdata *conn);
-
-static CURLcode init_wc_data(struct connectdata *conn);
-static CURLcode wc_statemach(struct connectdata *conn);
-
+static CURLcode ftp_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn);
+static CURLcode init_wc_data(struct Curl_easy *data);
+static CURLcode wc_statemach(struct Curl_easy *data);
 static void wc_data_dtor(void *ptr);
-
-static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
-
-static CURLcode ftp_readresp(curl_socket_t sockfd,
+static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize);
+static CURLcode ftp_readresp(struct Curl_easy *data,
+                             curl_socket_t sockfd,
                              struct pingpong *pp,
                              int *ftpcode,
                              size_t *size);
-static CURLcode ftp_dophase_done(struct connectdata *conn,
+static CURLcode ftp_dophase_done(struct Curl_easy *data,
                                  bool connected);
 
-/* easy-to-use macro: */
-#define PPSENDF(x,y,z)  result = Curl_pp_sendf(x,y,z); \
-                        if(result)                     \
-                          return result
-
-
 /*
  * FTP protocol handler.
  */
@@ -180,6 +177,7 @@ const struct Curl_handler Curl_handler_ftp = {
   ZERO_NULL,                       /* connection_check */
   PORT_FTP,                        /* defport */
   CURLPROTO_FTP,                   /* protocol */
+  CURLPROTO_FTP,                   /* family */
   PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
   PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
   PROTOPT_WILDCARD /* flags */
@@ -209,15 +207,17 @@ const struct Curl_handler Curl_handler_ftps = {
   ZERO_NULL,                       /* connection_check */
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTPS,                  /* protocol */
+  CURLPROTO_FTP,                   /* family */
   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
   PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
 };
 #endif
 
-static void close_secondarysocket(struct connectdata *conn)
+static void close_secondarysocket(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
-    Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+    Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
   }
   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
@@ -264,9 +264,9 @@ static void freedirs(struct ftp_conn *ftpc)
  * called to accept the connection and close the listening socket
  *
  */
-static CURLcode AcceptServerConnect(struct connectdata *conn)
+static CURLcode AcceptServerConnect(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
   curl_socket_t s = CURL_SOCKET_BAD;
 #ifdef ENABLE_IPV6
@@ -281,7 +281,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
 
     s = accept(sock, (struct sockaddr *) &add, &size);
   }
-  Curl_closesocket(conn, sock); /* close the first socket */
+  Curl_closesocket(data, conn, sock); /* close the first socket */
 
   if(CURL_SOCKET_BAD == s) {
     failf(data, "Error accept()ing server connect");
@@ -307,7 +307,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
     Curl_set_in_callback(data, false);
 
     if(error) {
-      close_secondarysocket(conn);
+      close_secondarysocket(data, conn);
       return CURLE_ABORTED_BY_CALLBACK;
     }
   }
@@ -363,9 +363,9 @@ static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
  * connection for a negative response regarding a failure in connecting
  *
  */
-static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
+static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
   curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
   struct ftp_conn *ftpc = &conn->proto.ftpc;
@@ -389,7 +389,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
   if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
     /* Data connection could not be established, let's return */
     infof(data, "There is negative response in cache while serv connect\n");
-    (void)Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
     return CURLE_FTP_ACCEPT_FAILED;
   }
 
@@ -411,7 +411,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
     }
     else if(result & CURL_CSELECT_IN) {
       infof(data, "Ctrl conn has data while waiting for data conn\n");
-      (void)Curl_GetFTPResponse(&nread, conn, &ftpcode);
+      (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
 
       if(ftpcode/100 > 3)
         return CURLE_FTP_ACCEPT_FAILED;
@@ -434,16 +434,16 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
  * setup transfer parameters and initiate the data transfer.
  *
  */
-static CURLcode InitiateTransfer(struct connectdata *conn)
+static CURLcode InitiateTransfer(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   if(conn->bits.ftp_use_data_ssl) {
     /* since we only have a plaintext TCP connection here, we must now
      * do the TLS stuff */
     infof(data, "Doing the SSL/TLS handshake on the data stream\n");
-    result = Curl_ssl_connect(conn, SECONDARYSOCKET);
+    result = Curl_ssl_connect(data, conn, SECONDARYSOCKET);
     if(result)
       return result;
   }
@@ -465,7 +465,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
   }
 
   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
-  state(conn, FTP_STOP);
+  state(data, FTP_STOP);
 
   return CURLE_OK;
 }
@@ -479,9 +479,8 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
  * accepted.
  *
  */
-static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
+static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
 {
-  struct Curl_easy *data = conn->data;
   timediff_t timeout_ms;
   CURLcode result = CURLE_OK;
 
@@ -499,16 +498,16 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
   }
 
   /* see if the connection request is already here */
-  result = ReceivedServerConnect(conn, connected);
+  result = ReceivedServerConnect(data, connected);
   if(result)
     return result;
 
   if(*connected) {
-    result = AcceptServerConnect(conn);
+    result = AcceptServerConnect(data);
     if(result)
       return result;
 
-    result = InitiateTransfer(conn);
+    result = InitiateTransfer(data);
     if(result)
       return result;
   }
@@ -531,9 +530,10 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
 /* macro to check for the last line in an FTP server response */
 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
 
-static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
-                          int *code)
+static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                          char *line, size_t len, int *code)
 {
+  (void)data;
   (void)conn;
 
   if((len > 3) && LASTLINE(line)) {
@@ -544,34 +544,35 @@ static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
   return FALSE;
 }
 
-static CURLcode ftp_readresp(curl_socket_t sockfd,
+static CURLcode ftp_readresp(struct Curl_easy *data,
+                             curl_socket_t sockfd,
                              struct pingpong *pp,
                              int *ftpcode, /* return the ftp-code if done */
                              size_t *size) /* size of the response */
 {
-  struct connectdata *conn = pp->conn;
-  struct Curl_easy *data = conn->data;
-#ifdef HAVE_GSSAPI
-  char * const buf = data->state.buffer;
-#endif
   int code;
-  CURLcode result = Curl_pp_readresp(sockfd, pp, &code, size);
+  CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size);
 
-#if defined(HAVE_GSSAPI)
-  /* handle the security-oriented responses 6xx ***/
-  switch(code) {
-  case 631:
-    code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
-    break;
-  case 632:
-    code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
-    break;
-  case 633:
-    code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
-    break;
-  default:
-    /* normal ftp stuff we pass through! */
-    break;
+#ifdef HAVE_GSSAPI
+  {
+    struct connectdata *conn = data->conn;
+    char * const buf = data->state.buffer;
+
+    /* handle the security-oriented responses 6xx ***/
+    switch(code) {
+    case 631:
+      code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE);
+      break;
+    case 632:
+      code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE);
+      break;
+    case 633:
+      code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL);
+      break;
+    default:
+      /* normal ftp stuff we pass through! */
+      break;
+    }
   }
 #endif
 
@@ -590,7 +591,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
      * generically is a good idea.
      */
     infof(data, "We got a 421 - timeout!\n");
-    state(conn, FTP_STOP);
+    state(data, FTP_STOP);
     return CURLE_OPERATION_TIMEDOUT;
   }
 
@@ -605,8 +606,8 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
  *
  */
 
-CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
-                             struct connectdata *conn,
+CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
+                             ssize_t *nreadp, /* return number of bytes read */
                              int *ftpcode) /* return the ftp-code */
 {
   /*
@@ -616,8 +617,8 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
    * Alas, read as much as possible, split up into lines, use the ending
    * line in a response or continue reading.  */
 
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
@@ -635,7 +636,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
 
   while(!*ftpcode && !result) {
     /* check and reset timeout value every lap */
-    timediff_t timeout = Curl_pp_state_timeout(pp, FALSE);
+    timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE);
     timediff_t interval_ms;
 
     if(timeout <= 0) {
@@ -677,7 +678,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
         return CURLE_RECV_ERROR;
 
       case 0: /* timeout */
-        if(Curl_pgrsUpdate(conn))
+        if(Curl_pgrsUpdate(data))
           return CURLE_ABORTED_BY_CALLBACK;
         continue; /* just continue in our loop for the timeout duration */
 
@@ -685,7 +686,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
         break;
       }
     }
-    result = ftp_readresp(sockfd, pp, ftpcode, &nread);
+    result = ftp_readresp(data, sockfd, pp, ftpcode, &nread);
     if(result)
       break;
 
@@ -749,13 +750,14 @@ static const char * const ftp_state_names[]={
 #endif
 
 /* This is the ONLY way to change FTP state! */
-static void _state(struct connectdata *conn,
+static void _state(struct Curl_easy *data,
                    ftpstate newstate
 #ifdef DEBUGBUILD
                    , int lineno
 #endif
   )
 {
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
 #if defined(DEBUGBUILD)
@@ -764,7 +766,7 @@ static void _state(struct connectdata *conn,
   (void) lineno;
 #else
   if(ftpc->state != newstate)
-    infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
+    infof(data, "FTP %p (line %d) state change from %s to %s\n",
           (void *)ftpc, lineno, ftp_state_names[ftpc->state],
           ftp_state_names[newstate]);
 #endif
@@ -773,40 +775,43 @@ static void _state(struct connectdata *conn,
   ftpc->state = newstate;
 }
 
-static CURLcode ftp_state_user(struct connectdata *conn)
+static CURLcode ftp_state_user(struct Curl_easy *data,
+                               struct connectdata *conn)
 {
-  CURLcode result;
-  /* send USER */
-  PPSENDF(&conn->proto.ftpc.pp, "USER %s", conn->user?conn->user:"");
-
-  state(conn, FTP_USER);
-  conn->data->state.ftp_trying_alternative = FALSE;
-
-  return CURLE_OK;
+  CURLcode result = Curl_pp_sendf(data,
+                                  &conn->proto.ftpc.pp, "USER %s",
+                                  conn->user?conn->user:"");
+  if(!result) {
+    state(data, FTP_USER);
+    data->state.ftp_trying_alternative = FALSE;
+  }
+  return result;
 }
 
-static CURLcode ftp_state_pwd(struct connectdata *conn)
+static CURLcode ftp_state_pwd(struct Curl_easy *data,
+                              struct connectdata *conn)
 {
-  CURLcode result;
-
-  /* send PWD to discover our entry point */
-  PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
-  state(conn, FTP_PWD);
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD");
+  if(!result)
+    state(data, FTP_PWD);
 
-  return CURLE_OK;
+  return result;
 }
 
 /* For the FTP "protocol connect" and "doing" phases only */
-static int ftp_getsock(struct connectdata *conn,
+static int ftp_getsock(struct Curl_easy *data,
+                       struct connectdata *conn,
                        curl_socket_t *socks)
 {
-  return Curl_pp_getsock(&conn->proto.ftpc.pp, socks);
+  return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
 }
 
 /* For the FTP "DO_MORE" phase only */
-static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int ftp_domore_getsock(struct Curl_easy *data,
+                              struct connectdata *conn, curl_socket_t *socks)
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
+  (void)data;
 
   /* When in DO_MORE state, we could be either waiting for us to connect to a
    * remote site, or we could wait for that site to connect to us. Or just
@@ -824,7 +829,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
        connect on the secondary connection */
     socks[0] = conn->sock[FIRSTSOCKET];
 
-    if(!conn->data->set.ftp_use_port) {
+    if(!data->set.ftp_use_port) {
       int s;
       int i;
       /* PORT is used to tell the server to connect to us, and during that we
@@ -844,7 +849,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
 
     return bits;
   }
-  return Curl_pp_getsock(&conn->proto.ftpc.pp, socks);
+  return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
 }
 
 /* This is called after the FTP_QUOTE state is passed.
@@ -853,17 +858,18 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
    the correct directory. It may also need to send MKD commands to create
    missing ones, if that option is enabled.
 */
-static CURLcode ftp_state_cwd(struct connectdata *conn)
+static CURLcode ftp_state_cwd(struct Curl_easy *data,
+                              struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if(ftpc->cwddone)
     /* already done and fine */
-    result = ftp_state_mdtm(conn);
+    result = ftp_state_mdtm(data);
   else {
     /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */
-    DEBUGASSERT((conn->data->set.ftp_filemethod != FTPFILE_NOCWD) ||
+    DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) ||
                 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/'));
 
     ftpc->count2 = 0; /* count2 counts failed CWDs */
@@ -871,7 +877,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
     /* count3 is set to allow a MKD to fail once. In the case when first CWD
        fails and then MKD fails (due to another session raced it to create the
        dir) this then allows for a second try to CWD to it */
-    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
+    ftpc->count3 = (data->set.ftp_create_missing_dirs == 2)?1:0;
 
     if(conn->bits.reuse && ftpc->entrypath &&
        /* no need to go to entrypath when we have an absolute path */
@@ -881,20 +887,23 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
          where we ended up after login: */
       ftpc->cwdcount = 0; /* we count this as the first path, then we add one
                              for all upcoming ones in the ftp->dirs[] array */
-      PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
-      state(conn, FTP_CWD);
+      result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath);
+      if(!result)
+        state(data, FTP_CWD);
     }
     else {
       if(ftpc->dirdepth) {
         ftpc->cwdcount = 1;
         /* issue the first CWD, the rest is sent when the CWD responses are
            received... */
-        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]);
-        state(conn, FTP_CWD);
+        result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
+                               ftpc->dirs[ftpc->cwdcount -1]);
+        if(!result)
+          state(data, FTP_CWD);
       }
       else {
         /* No CWD necessary */
-        result = ftp_state_mdtm(conn);
+        result = ftp_state_mdtm(data);
       }
     }
   }
@@ -907,13 +916,12 @@ typedef enum {
   DONE
 } ftpport;
 
-static CURLcode ftp_state_use_port(struct connectdata *conn,
+static CURLcode ftp_state_use_port(struct Curl_easy *data,
                                    ftpport fcmd) /* start with this */
-
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
-  struct Curl_easy *data = conn->data;
   curl_socket_t portsock = CURL_SOCKET_BAD;
   char myhost[MAX_IPADR_LEN + 1] = "";
 
@@ -1070,9 +1078,9 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   }
 
   /* resolv ip/host to ip */
-  rc = Curl_resolv(conn, host, 0, FALSE, &h);
+  rc = Curl_resolv(data, host, 0, FALSE, &h);
   if(rc == CURLRESOLV_PENDING)
-    (void)Curl_resolver_wait_resolv(conn, &h);
+    (void)Curl_resolver_wait_resolv(data, &h);
   if(h) {
     res = h->addr;
     /* when we return from this function, we can forget about this entry
@@ -1096,7 +1104,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   portsock = CURL_SOCKET_BAD;
   error = 0;
   for(ai = res; ai; ai = ai->ai_next) {
-    result = Curl_socket(conn, ai, NULL, &portsock);
+    result = Curl_socket(data, ai, NULL, &portsock);
     if(result) {
       error = SOCKERRNO;
       continue;
@@ -1136,7 +1144,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
         if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
           failf(data, "getsockname() failed: %s",
                 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
-          Curl_closesocket(conn, portsock);
+          Curl_closesocket(data, conn, portsock);
           return CURLE_FTP_PORT_FAILED;
         }
         port = port_min;
@@ -1146,7 +1154,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       if(error != EADDRINUSE && error != EACCES) {
         failf(data, "bind(port=%hu) failed: %s", port,
               Curl_strerror(error, buffer, sizeof(buffer)));
-        Curl_closesocket(conn, portsock);
+        Curl_closesocket(data, conn, portsock);
         return CURLE_FTP_PORT_FAILED;
       }
     }
@@ -1159,7 +1167,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   /* maybe all ports were in use already*/
   if(port > port_max) {
     failf(data, "bind() failed, we ran out of ports!");
-    Curl_closesocket(conn, portsock);
+    Curl_closesocket(data, conn, portsock);
     return CURLE_FTP_PORT_FAILED;
   }
 
@@ -1169,7 +1177,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
     failf(data, "getsockname() failed: %s",
           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
-    Curl_closesocket(conn, portsock);
+    Curl_closesocket(data, conn, portsock);
     return CURLE_FTP_PORT_FAILED;
   }
 
@@ -1178,7 +1186,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   if(listen(portsock, 1)) {
     failf(data, "socket failure: %s",
           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
-    Curl_closesocket(conn, portsock);
+    Curl_closesocket(data, conn, portsock);
     return CURLE_FTP_PORT_FAILED;
   }
 
@@ -1227,17 +1235,17 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
        * EPRT |2|1080::8:800:200C:417A|5282|
        */
 
-      result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
                              sa->sa_family == AF_INET?1:2,
                              myhost, port);
       if(result) {
         failf(data, "Failure sending EPRT command: %s",
               curl_easy_strerror(result));
-        Curl_closesocket(conn, portsock);
+        Curl_closesocket(data, conn, portsock);
         /* don't retry using PORT */
         ftpc->count1 = PORT;
         /* bail out */
-        state(conn, FTP_STOP);
+        state(data, FTP_STOP);
         return result;
       }
       break;
@@ -1260,13 +1268,13 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       *dest = 0;
       msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
 
-      result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], target);
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target);
       if(result) {
         failf(data, "Failure sending PORT command: %s",
               curl_easy_strerror(result));
-        Curl_closesocket(conn, portsock);
+        Curl_closesocket(data, conn, portsock);
         /* bail out */
-        state(conn, FTP_STOP);
+        state(data, FTP_STOP);
         return result;
       }
       break;
@@ -1276,7 +1284,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   /* store which command was sent */
   ftpc->count1 = fcmd;
 
-  close_secondarysocket(conn);
+  close_secondarysocket(data, conn);
 
   /* we set the secondary socket variable to this for now, it is only so that
      the cleanup function will close it in case we fail before the true
@@ -1292,11 +1300,12 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   */
   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
 
-  state(conn, FTP_PORT);
+  state(data, FTP_PORT);
   return result;
 }
 
-static CURLcode ftp_state_use_pasv(struct connectdata *conn)
+static CURLcode ftp_state_use_pasv(struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result = CURLE_OK;
@@ -1326,12 +1335,12 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn)
 
   modeoff = conn->bits.ftp_use_epsv?0:1;
 
-  PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
-
-  ftpc->count1 = modeoff;
-  state(conn, FTP_PASV);
-  infof(conn->data, "Connect data stream passively\n");
-
+  result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]);
+  if(!result) {
+    ftpc->count1 = modeoff;
+    state(data, FTP_PASV);
+    infof(data, "Connect data stream passively\n");
+  }
   return result;
 }
 
@@ -1342,53 +1351,54 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn)
  * request is made. Thus, if an actual transfer is to be made this is where we
  * take off for real.
  */
-static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
+static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct FTP *ftp = conn->data->req.protop;
-  struct Curl_easy *data = conn->data;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
 
   if(ftp->transfer != FTPTRANSFER_BODY) {
     /* doesn't transfer any data */
 
     /* still possibly do PRE QUOTE jobs */
-    state(conn, FTP_RETR_PREQUOTE);
-    result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+    state(data, FTP_RETR_PREQUOTE);
+    result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
   }
   else if(data->set.ftp_use_port) {
     /* We have chosen to use the PORT (or similar) command */
-    result = ftp_state_use_port(conn, EPRT);
+    result = ftp_state_use_port(data, EPRT);
   }
   else {
     /* We have chosen (this is default) to use the PASV (or similar) command */
     if(data->set.ftp_use_pret) {
       /* The user has requested that we send a PRET command
          to prepare the server for the upcoming PASV */
-      if(!conn->proto.ftpc.file) {
-        PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
-                data->set.str[STRING_CUSTOMREQUEST]?
-                data->set.str[STRING_CUSTOMREQUEST]:
-                (data->set.ftp_list_only?"NLST":"LIST"));
-      }
-      else if(data->set.upload) {
-        PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
-      }
-      else {
-        PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
-      }
-      state(conn, FTP_PRET);
-    }
-    else {
-      result = ftp_state_use_pasv(conn);
+      struct ftp_conn *ftpc = &conn->proto.ftpc;
+      if(!conn->proto.ftpc.file)
+        result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
+                               data->set.str[STRING_CUSTOMREQUEST]?
+                               data->set.str[STRING_CUSTOMREQUEST]:
+                               (data->set.ftp_list_only?"NLST":"LIST"));
+      else if(data->set.upload)
+        result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
+                               conn->proto.ftpc.file);
+      else
+        result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s",
+                               conn->proto.ftpc.file);
+      if(!result)
+        state(data, FTP_PRET);
     }
+    else
+      result = ftp_state_use_pasv(data, conn);
   }
   return result;
 }
 
-static CURLcode ftp_state_rest(struct connectdata *conn)
+static CURLcode ftp_state_rest(struct Curl_easy *data,
+                               struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct FTP *ftp = conn->data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
@@ -1396,41 +1406,42 @@ static CURLcode ftp_state_rest(struct connectdata *conn)
 
     /* Determine if server can respond to REST command and therefore
        whether it supports range */
-    PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
-
-    state(conn, FTP_REST);
+    result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0);
+    if(!result)
+      state(data, FTP_REST);
   }
   else
-    result = ftp_state_prepare_transfer(conn);
+    result = ftp_state_prepare_transfer(data);
 
   return result;
 }
 
-static CURLcode ftp_state_size(struct connectdata *conn)
+static CURLcode ftp_state_size(struct Curl_easy *data,
+                               struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct FTP *ftp = conn->data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
     /* if a "head"-like request is being made (on a file) */
 
     /* we know ftpc->file is a valid pointer to a file name */
-    PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
-
-    state(conn, FTP_SIZE);
+    result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
+    if(!result)
+      state(data, FTP_SIZE);
   }
   else
-    result = ftp_state_rest(conn);
+    result = ftp_state_rest(data, conn);
 
   return result;
 }
 
-static CURLcode ftp_state_list(struct connectdata *conn)
+static CURLcode ftp_state_list(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct FTP *ftp = data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
 
   /* If this output is to be machine-parsed, the NLST command might be better
      to use, since the LIST command output is not specified or standard in any
@@ -1482,34 +1493,32 @@ static CURLcode ftp_state_list(struct connectdata *conn)
   if(!cmd)
     return CURLE_OUT_OF_MEMORY;
 
-  result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
+  result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", cmd);
   free(cmd);
 
-  if(result)
-    return result;
-
-  state(conn, FTP_LIST);
+  if(!result)
+    state(data, FTP_LIST);
 
   return result;
 }
 
-static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
+static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
 {
   /* We've sent the TYPE, now we must send the list of prequote strings */
-  return ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+  return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
 }
 
-static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
+static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
 {
   /* We've sent the TYPE, now we must send the list of prequote strings */
-  return ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
+  return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
 }
 
-static CURLcode ftp_state_type(struct connectdata *conn)
+static CURLcode ftp_state_type(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct FTP *ftp = conn->data->req.protop;
-  struct Curl_easy *data = conn->data;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   /* If we have selected NOBODY and HEADER, it means that we only want file
@@ -1526,22 +1535,22 @@ static CURLcode ftp_state_type(struct connectdata *conn)
 
     /* Some servers return different sizes for different modes, and thus we
        must set the proper type before we check the size */
-    result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
+    result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_TYPE);
     if(result)
       return result;
   }
   else
-    result = ftp_state_size(conn);
+    result = ftp_state_size(data, conn);
 
   return result;
 }
 
 /* This is called after the CWD commands have been done in the beginning of
    the DO phase */
-static CURLcode ftp_state_mdtm(struct connectdata *conn)
+static CURLcode ftp_state_mdtm(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   /* Requested time of file or time-depended transfer? */
@@ -1549,24 +1558,25 @@ static CURLcode ftp_state_mdtm(struct connectdata *conn)
 
     /* we have requested to get the modified-time of the file, this is a white
        spot as the MDTM is not mentioned in RFC959 */
-    PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
+    result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file);
 
-    state(conn, FTP_MDTM);
+    if(!result)
+      state(data, FTP_MDTM);
   }
   else
-    result = ftp_state_type(conn);
+    result = ftp_state_type(data);
 
   return result;
 }
 
 
 /* This is called after the TYPE and possible quote commands have been sent */
-static CURLcode ftp_state_ul_setup(struct connectdata *conn,
+static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
                                    bool sizechecked)
 {
   CURLcode result = CURLE_OK;
-  struct FTP *ftp = conn->data->req.protop;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
+  struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if((data->state.resume_from && !sizechecked) ||
@@ -1587,8 +1597,9 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
 
     if(data->state.resume_from < 0) {
       /* Got no given size to start from, figure it out */
-      PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
-      state(conn, FTP_STOR_SIZE);
+      result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
+      if(!result)
+        state(data, FTP_STOR_SIZE);
       return result;
     }
 
@@ -1643,28 +1654,29 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
          * ftp_done() because we didn't transfer anything! */
         ftp->transfer = FTPTRANSFER_NONE;
 
-        state(conn, FTP_STOP);
+        state(data, FTP_STOP);
         return CURLE_OK;
       }
     }
     /* we've passed, proceed as normal */
   } /* resume_from */
 
-  PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
-          ftpc->file);
-
-  state(conn, FTP_STOR);
+  result = Curl_pp_sendf(data, &ftpc->pp,
+                         data->set.ftp_append?"APPE %s":"STOR %s",
+                         ftpc->file);
+  if(!result)
+    state(data, FTP_STOR);
 
   return result;
 }
 
-static CURLcode ftp_state_quote(struct connectdata *conn,
+static CURLcode ftp_state_quote(struct Curl_easy *data,
                                 bool init,
                                 ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct FTP *ftp = data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   bool quote = FALSE;
   struct curl_slist *item;
@@ -1711,8 +1723,10 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
       else
         ftpc->count2 = 0; /* failure means cancel operation */
 
-      PPSENDF(&ftpc->pp, "%s", cmd);
-      state(conn, instate);
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
+      if(result)
+        return result;
+      state(data, instate);
       quote = TRUE;
     }
   }
@@ -1722,15 +1736,15 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
     switch(instate) {
     case FTP_QUOTE:
     default:
-      result = ftp_state_cwd(conn);
+      result = ftp_state_cwd(data, conn);
       break;
     case FTP_RETR_PREQUOTE:
       if(ftp->transfer != FTPTRANSFER_BODY)
-        state(conn, FTP_STOP);
+        state(data, FTP_STOP);
       else {
         if(ftpc->known_filesize != -1) {
           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
-          result = ftp_state_retr(conn, ftpc->known_filesize);
+          result = ftp_state_retr(data, ftpc->known_filesize);
         }
         else {
           if(data->set.ignorecl) {
@@ -1740,18 +1754,20 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
                the server terminates it, otherwise the client stops if the
                received byte count exceeds the reported file size.  Set option
                CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
-            PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
-            state(conn, FTP_RETR);
+            result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
+            if(!result)
+              state(data, FTP_RETR);
           }
           else {
-            PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
-            state(conn, FTP_RETR_SIZE);
+            result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
+            if(!result)
+              state(data, FTP_RETR_SIZE);
           }
         }
       }
       break;
     case FTP_STOR_PREQUOTE:
-      result = ftp_state_ul_setup(conn, FALSE);
+      result = ftp_state_ul_setup(data, FALSE);
       break;
     case FTP_POSTQUOTE:
       break;
@@ -1763,7 +1779,8 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
 
 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
    problems */
-static CURLcode ftp_epsv_disable(struct connectdata *conn)
+static CURLcode ftp_epsv_disable(struct Curl_easy *data,
+                                 struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
 
@@ -1773,19 +1790,21 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn)
 #endif
     ) {
     /* We can't disable EPSV when doing IPv6, so this is instead a fail */
-    failf(conn->data, "Failed EPSV attempt, exiting\n");
+    failf(data, "Failed EPSV attempt, exiting");
     return CURLE_WEIRD_SERVER_REPLY;
   }
 
-  infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
+  infof(data, "Failed EPSV attempt. Disabling EPSV\n");
   /* disable it for next transfer */
   conn->bits.ftp_use_epsv = FALSE;
-  conn->data->state.errorbuf = FALSE; /* allow error message to get
+  data->state.errorbuf = FALSE; /* allow error message to get
                                          rewritten */
-  PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
-  conn->proto.ftpc.count1++;
-  /* remain in/go to the FTP_PASV state */
-  state(conn, FTP_PASV);
+  result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV");
+  if(!result) {
+    conn->proto.ftpc.count1++;
+    /* remain in/go to the FTP_PASV state */
+    state(data, FTP_PASV);
+  }
   return result;
 }
 
@@ -1800,15 +1819,15 @@ static char *control_address(struct connectdata *conn)
   if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
     return conn->host.name;
 #endif
-  return conn->ip_addr_str;
+  return conn->primary_ip;
 }
 
-static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
+static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
                                     int ftpcode)
 {
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   struct Curl_dns_entry *addr = NULL;
   enum resolve_t rc;
   unsigned short connectport; /* the local port connect() should use! */
@@ -1864,8 +1883,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
   else if((ftpc->count1 == 1) &&
           (ftpcode == 227)) {
     /* positive PASV response */
-    unsigned int ip[4];
-    unsigned int port[2];
+    unsigned int ip[4] = {0, 0, 0, 0};
+    unsigned int port[2] = {0, 0};
 
     /*
      * Scan for a sequence of six comma-separated numbers and use them as
@@ -1909,7 +1928,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
   }
   else if(ftpc->count1 == 0) {
     /* EPSV failed, move on to PASV */
-    return ftp_epsv_disable(conn);
+    return ftp_epsv_disable(data, conn);
   }
   else {
     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
@@ -1925,11 +1944,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
      */
     const char * const host_name = conn->bits.socksproxy ?
       conn->socks_proxy.host.name : conn->http_proxy.host.name;
-    rc = Curl_resolv(conn, host_name, (int)conn->port, FALSE, &addr);
+    rc = Curl_resolv(data, host_name, (int)conn->port, FALSE, &addr);
     if(rc == CURLRESOLV_PENDING)
       /* BLOCKING, ignores the return code but 'addr' will be NULL in
          case of failure */
-      (void)Curl_resolver_wait_resolv(conn, &addr);
+      (void)Curl_resolver_wait_resolv(data, &addr);
 
     connectport =
       (unsigned short)conn->port; /* we connect to the proxy's port */
@@ -1943,10 +1962,21 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 #endif
   {
     /* normal, direct, ftp connection */
-    rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, FALSE, &addr);
+    DEBUGASSERT(ftpc->newhost);
+
+    /* postponed address resolution in case of tcp fastopen */
+    if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
+      Curl_conninfo_remote(data, conn, conn->sock[FIRSTSOCKET]);
+      Curl_safefree(ftpc->newhost);
+      ftpc->newhost = strdup(control_address(conn));
+      if(!ftpc->newhost)
+        return CURLE_OUT_OF_MEMORY;
+    }
+
+    rc = Curl_resolv(data, ftpc->newhost, ftpc->newport, FALSE, &addr);
     if(rc == CURLRESOLV_PENDING)
       /* BLOCKING */
-      (void)Curl_resolver_wait_resolv(conn, &addr);
+      (void)Curl_resolver_wait_resolv(data, &addr);
 
     connectport = ftpc->newport; /* we connect to the remote port */
 
@@ -1957,12 +1987,12 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
   }
 
   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
-  result = Curl_connecthost(conn, addr);
+  result = Curl_connecthost(data, conn, addr);
 
   if(result) {
     Curl_resolv_unlock(data, addr); /* we're done using this address */
     if(ftpc->count1 == 0 && ftpcode == 229)
-      return ftp_epsv_disable(conn);
+      return ftp_epsv_disable(data, conn);
 
     return result;
   }
@@ -1976,7 +2006,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 
   if(data->set.verbose)
     /* this just dumps information about this second connection */
-    ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
+    ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);
 
   Curl_resolv_unlock(data, addr); /* we're done using this address */
 
@@ -1987,15 +2017,15 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
     return CURLE_OUT_OF_MEMORY;
 
   conn->bits.do_more = TRUE;
-  state(conn, FTP_STOP); /* this phase is completed */
+  state(data, FTP_STOP); /* this phase is completed */
 
   return result;
 }
 
-static CURLcode ftp_state_port_resp(struct connectdata *conn,
+static CURLcode ftp_state_port_resp(struct Curl_easy *data,
                                     int ftpcode)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   ftpport fcmd = (ftpport)ftpc->count1;
   CURLcode result = CURLE_OK;
@@ -2017,23 +2047,23 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn,
     }
     else
       /* try next */
-      result = ftp_state_use_port(conn, fcmd);
+      result = ftp_state_use_port(data, fcmd);
   }
   else {
     infof(data, "Connect data stream actively\n");
-    state(conn, FTP_STOP); /* end of DO phase */
-    result = ftp_dophase_done(conn, FALSE);
+    state(data, FTP_STOP); /* end of DO phase */
+    result = ftp_dophase_done(data, FALSE);
   }
 
   return result;
 }
 
-static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
+static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
                                     int ftpcode)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct FTP *ftp = data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   switch(ftpcode) {
@@ -2080,7 +2110,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
                   tm->tm_hour,
                   tm->tm_min,
                   tm->tm_sec);
-        result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
+        result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf, 0);
         if(result)
           return result;
       } /* end of a ridiculous amount of conditionals */
@@ -2092,7 +2122,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
     break;
   case 550: /* "No such file or directory" */
     failf(data, "Given file does not exist");
-    result = CURLE_FTP_COULDNT_RETR_FILE;
+    result = CURLE_REMOTE_FILE_NOT_FOUND;
     break;
   }
 
@@ -2105,7 +2135,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
           infof(data, "The requested document is not new enough\n");
           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
           data->info.timecond = TRUE;
-          state(conn, FTP_STOP);
+          state(data, FTP_STOP);
           return CURLE_OK;
         }
         break;
@@ -2114,7 +2144,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
           infof(data, "The requested document is not old enough\n");
           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
           data->info.timecond = TRUE;
-          state(conn, FTP_STOP);
+          state(data, FTP_STOP);
           return CURLE_OK;
         }
         break;
@@ -2126,17 +2156,17 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
   }
 
   if(!result)
-    result = ftp_state_type(conn);
+    result = ftp_state_type(data);
 
   return result;
 }
 
-static CURLcode ftp_state_type_resp(struct connectdata *conn,
+static CURLcode ftp_state_type_resp(struct Curl_easy *data,
                                     int ftpcode,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   if(ftpcode/100 != 2) {
     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
@@ -2150,23 +2180,23 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn,
           ftpcode);
 
   if(instate == FTP_TYPE)
-    result = ftp_state_size(conn);
+    result = ftp_state_size(data, conn);
   else if(instate == FTP_LIST_TYPE)
-    result = ftp_state_list(conn);
+    result = ftp_state_list(data);
   else if(instate == FTP_RETR_TYPE)
-    result = ftp_state_retr_prequote(conn);
+    result = ftp_state_retr_prequote(data);
   else if(instate == FTP_STOR_TYPE)
-    result = ftp_state_stor_prequote(conn);
+    result = ftp_state_stor_prequote(data);
 
   return result;
 }
 
-static CURLcode ftp_state_retr(struct connectdata *conn,
-                                         curl_off_t filesize)
+static CURLcode ftp_state_retr(struct Curl_easy *data,
+                               curl_off_t filesize)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct FTP *ftp = data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
@@ -2221,7 +2251,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
       /* Set ->transfer so that we won't get any error in ftp_done()
        * because we didn't transfer the any file */
       ftp->transfer = FTPTRANSFER_NONE;
-      state(conn, FTP_STOP);
+      state(data, FTP_STOP);
       return CURLE_OK;
     }
 
@@ -2229,26 +2259,26 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
     infof(data, "Instructs server to resume from offset %"
           CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
 
-    PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
-            data->state.resume_from);
-
-    state(conn, FTP_RETR_REST);
+    result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
+                           data->state.resume_from);
+    if(!result)
+      state(data, FTP_RETR_REST);
   }
   else {
     /* no resume */
-    PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
-    state(conn, FTP_RETR);
+    result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
+    if(!result)
+      state(data, FTP_RETR);
   }
 
   return result;
 }
 
-static CURLcode ftp_state_size_resp(struct connectdata *conn,
+static CURLcode ftp_state_size_resp(struct Curl_easy *data,
                                     int ftpcode,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   curl_off_t filesize = -1;
   char *buf = data->state.buffer;
 
@@ -2272,6 +2302,10 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
     (void)curlx_strtoofft(fdigit, NULL, 0, &filesize);
 
   }
+  else if(ftpcode == 550) { /* "No such file or directory" */
+    failf(data, "The file does not exist");
+    return CURLE_REMOTE_FILE_NOT_FOUND;
+  }
 
   if(instate == FTP_SIZE) {
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
@@ -2279,27 +2313,28 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
       char clbuf[128];
       msnprintf(clbuf, sizeof(clbuf),
                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
-      result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
+      result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, 0);
       if(result)
         return result;
     }
 #endif
     Curl_pgrsSetDownloadSize(data, filesize);
-    result = ftp_state_rest(conn);
+    result = ftp_state_rest(data, data->conn);
   }
   else if(instate == FTP_RETR_SIZE) {
     Curl_pgrsSetDownloadSize(data, filesize);
-    result = ftp_state_retr(conn, filesize);
+    result = ftp_state_retr(data, filesize);
   }
   else if(instate == FTP_STOR_SIZE) {
     data->state.resume_from = filesize;
-    result = ftp_state_ul_setup(conn, TRUE);
+    result = ftp_state_ul_setup(data, TRUE);
   }
 
   return result;
 }
 
-static CURLcode ftp_state_rest_resp(struct connectdata *conn,
+static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
+                                    struct connectdata *conn,
                                     int ftpcode,
                                     ftpstate instate)
 {
@@ -2312,22 +2347,23 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn,
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
     if(ftpcode == 350) {
       char buffer[24]= { "Accept-ranges: bytes\r\n" };
-      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
+      result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer, 0);
       if(result)
         return result;
     }
 #endif
-    result = ftp_state_prepare_transfer(conn);
+    result = ftp_state_prepare_transfer(data);
     break;
 
   case FTP_RETR_REST:
     if(ftpcode != 350) {
-      failf(conn->data, "Couldn't use REST");
+      failf(data, "Couldn't use REST");
       result = CURLE_FTP_COULDNT_USE_REST;
     }
     else {
-      PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
-      state(conn, FTP_RETR);
+      result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
+      if(!result)
+        state(data, FTP_RETR);
     }
     break;
   }
@@ -2335,15 +2371,15 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn,
   return result;
 }
 
-static CURLcode ftp_state_stor_resp(struct connectdata *conn,
+static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
                                     int ftpcode, ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   if(ftpcode >= 400) {
     failf(data, "Failed FTP upload: %0d", ftpcode);
-    state(conn, FTP_STOP);
+    state(data, FTP_STOP);
     /* oops, we never close the sockets! */
     return CURLE_UPLOAD_FAILED;
   }
@@ -2354,9 +2390,9 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
   if(data->set.ftp_use_port) {
     bool connected;
 
-    state(conn, FTP_STOP); /* no longer in STOR state */
+    state(data, FTP_STOP); /* no longer in STOR state */
 
-    result = AllowServerConnect(conn, &connected);
+    result = AllowServerConnect(data, &connected);
     if(result)
       return result;
 
@@ -2368,17 +2404,17 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
 
     return CURLE_OK;
   }
-  return InitiateTransfer(conn);
+  return InitiateTransfer(data);
 }
 
 /* for LIST and RETR responses */
-static CURLcode ftp_state_get_resp(struct connectdata *conn,
-                                    int ftpcode,
-                                    ftpstate instate)
+static CURLcode ftp_state_get_resp(struct Curl_easy *data,
+                                   int ftpcode,
+                                   ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct FTP *ftp = data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
 
   if((ftpcode == 150) || (ftpcode == 125)) {
 
@@ -2468,25 +2504,25 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
     if(data->set.ftp_use_port) {
       bool connected;
 
-      result = AllowServerConnect(conn, &connected);
+      result = AllowServerConnect(data, &connected);
       if(result)
         return result;
 
       if(!connected) {
         struct ftp_conn *ftpc = &conn->proto.ftpc;
         infof(data, "Data conn was not available immediately\n");
-        state(conn, FTP_STOP);
+        state(data, FTP_STOP);
         ftpc->wait_data_conn = TRUE;
       }
     }
     else
-      return InitiateTransfer(conn);
+      return InitiateTransfer(data);
   }
   else {
     if((instate == FTP_LIST) && (ftpcode == 450)) {
       /* simply no matching files in the dir listing */
       ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
-      state(conn, FTP_STOP); /* this phase is over */
+      state(data, FTP_STOP); /* this phase is over */
     }
     else {
       failf(data, "RETR response: %03d", ftpcode);
@@ -2500,11 +2536,12 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
 }
 
 /* after USER, PASS and ACCT */
-static CURLcode ftp_state_loggedin(struct connectdata *conn)
+static CURLcode ftp_state_loggedin(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
-  if(conn->ssl[FIRSTSOCKET].use) {
+  if(conn->bits.ftp_use_control_ssl) {
     /* PBSZ = PROTECTION BUFFER SIZE.
 
     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
@@ -2519,22 +2556,23 @@ static CURLcode ftp_state_loggedin(struct connectdata *conn)
     parameter of '0' to indicate that no buffering is taking place
     and the data connection should not be encapsulated.
     */
-    PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
-    state(conn, FTP_PBSZ);
+    result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0);
+    if(!result)
+      state(data, FTP_PBSZ);
   }
   else {
-    result = ftp_state_pwd(conn);
+    result = ftp_state_pwd(data, conn);
   }
   return result;
 }
 
 /* for USER and PASS responses */
-static CURLcode ftp_state_user_resp(struct connectdata *conn,
+static CURLcode ftp_state_user_resp(struct Curl_easy *data,
                                     int ftpcode,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   (void)instate; /* no use for this yet */
 
@@ -2542,18 +2580,22 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn,
   if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
     /* 331 Password required for ...
        (the server requires to send the user's password too) */
-    PPSENDF(&ftpc->pp, "PASS %s", conn->passwd?conn->passwd:"");
-    state(conn, FTP_PASS);
+    result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
+                           conn->passwd?conn->passwd:"");
+    if(!result)
+      state(data, FTP_PASS);
   }
   else if(ftpcode/100 == 2) {
     /* 230 User ... logged in.
        (the user logged in with or without password) */
-    result = ftp_state_loggedin(conn);
+    result = ftp_state_loggedin(data);
   }
   else if(ftpcode == 332) {
     if(data->set.str[STRING_FTP_ACCOUNT]) {
-      PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
-      state(conn, FTP_ACCT);
+      result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s",
+                             data->set.str[STRING_FTP_ACCOUNT]);
+      if(!result)
+        state(data, FTP_ACCT);
     }
     else {
       failf(data, "ACCT requested but none available");
@@ -2566,14 +2608,16 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn,
     530 User ... access denied
     (the server denies to log the specified user) */
 
-    if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
-        !conn->data->state.ftp_trying_alternative) {
+    if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
+        !data->state.ftp_trying_alternative) {
       /* Ok, USER failed.  Let's try the supplied command. */
-      PPSENDF(&conn->proto.ftpc.pp, "%s",
-              conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
-      conn->data->state.ftp_trying_alternative = TRUE;
-      state(conn, FTP_USER);
-      result = CURLE_OK;
+      result =
+        Curl_pp_sendf(data, &ftpc->pp, "%s",
+                      data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+      if(!result) {
+        data->state.ftp_trying_alternative = TRUE;
+        state(data, FTP_USER);
+      }
     }
     else {
       failf(data, "Access denied: %03d", ftpcode);
@@ -2584,27 +2628,26 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn,
 }
 
 /* for ACCT response */
-static CURLcode ftp_state_acct_resp(struct connectdata *conn,
+static CURLcode ftp_state_acct_resp(struct Curl_easy *data,
                                     int ftpcode)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   if(ftpcode != 230) {
     failf(data, "ACCT rejected by server: %03d", ftpcode);
     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
   }
   else
-    result = ftp_state_loggedin(conn);
+    result = ftp_state_loggedin(data);
 
   return result;
 }
 
 
-static CURLcode ftp_statemach_act(struct connectdata *conn)
+static CURLcode ftp_statemachine(struct Curl_easy *data,
+                                 struct connectdata *conn)
 {
   CURLcode result;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data = conn->data;
   int ftpcode;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
@@ -2612,9 +2655,9 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
   size_t nread = 0;
 
   if(pp->sendleft)
-    return Curl_pp_flushsend(pp);
+    return Curl_pp_flushsend(data, pp);
 
-  result = ftp_readresp(sock, pp, &ftpcode, &nread);
+  result = ftp_readresp(data, sock, pp, &ftpcode, &nread);
   if(result)
     return result;
 
@@ -2624,7 +2667,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
     case FTP_WAIT220:
       if(ftpcode == 230)
         /* 230 User logged in - already! */
-        return ftp_state_user_resp(conn, ftpcode, ftpc->state);
+        return ftp_state_user_resp(data, ftpcode, ftpc->state);
       else if(ftpcode != 220) {
         failf(data, "Got a %03d ftp-server response when 220 was expected",
               ftpcode);
@@ -2642,21 +2685,15 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
            set a valid level */
         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
 
-        if(Curl_sec_login(conn))
+        if(Curl_sec_login(data, conn))
           infof(data, "Logging in with password in cleartext!\n");
         else
           infof(data, "Authentication successful\n");
       }
 #endif
 
-      if(data->set.use_ssl &&
-         (!conn->ssl[FIRSTSOCKET].use
-#ifndef CURL_DISABLE_PROXY
-          || (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
-              !conn->proxy_ssl[FIRSTSOCKET].use)
-#endif
-           )) {
-        /* We don't have a SSL/TLS connection yet, but FTPS is
+      if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
+        /* We don't have a SSL/TLS control connection yet, but FTPS is
            requested. Try a FTPS connection now */
 
         ftpc->count3 = 0;
@@ -2675,15 +2712,13 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
                 (int)data->set.ftpsslauth);
           return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
         }
-        PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
-        state(conn, FTP_AUTH);
-      }
-      else {
-        result = ftp_state_user(conn);
-        if(result)
-          return result;
+        result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
+                               ftpauth[ftpc->count1]);
+        if(!result)
+          state(data, FTP_AUTH);
       }
-
+      else
+        result = ftp_state_user(data, conn);
       break;
 
     case FTP_AUTH:
@@ -2698,16 +2733,18 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 
       if((ftpcode == 234) || (ftpcode == 334)) {
         /* Curl_ssl_connect is BLOCKING */
-        result = Curl_ssl_connect(conn, FIRSTSOCKET);
+        result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
         if(!result) {
           conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
-          result = ftp_state_user(conn);
+          conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */
+          result = ftp_state_user(data, conn);
         }
       }
       else if(ftpc->count3 < 1) {
         ftpc->count3++;
         ftpc->count1 += ftpc->count2; /* get next attempt */
-        result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
+        result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
+                               ftpauth[ftpc->count1]);
         /* remain in this same state */
       }
       else {
@@ -2716,27 +2753,25 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
           result = CURLE_USE_SSL_FAILED;
         else
           /* ignore the failure and continue */
-          result = ftp_state_user(conn);
+          result = ftp_state_user(data, conn);
       }
-
-      if(result)
-        return result;
       break;
 
     case FTP_USER:
     case FTP_PASS:
-      result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
+      result = ftp_state_user_resp(data, ftpcode, ftpc->state);
       break;
 
     case FTP_ACCT:
-      result = ftp_state_acct_resp(conn, ftpcode);
+      result = ftp_state_acct_resp(data, ftpcode);
       break;
 
     case FTP_PBSZ:
-      PPSENDF(&ftpc->pp, "PROT %c",
-              data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
-      state(conn, FTP_PROT);
-
+      result =
+        Curl_pp_sendf(data, &ftpc->pp, "PROT %c",
+                      data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
+      if(!result)
+        state(data, FTP_PROT);
       break;
 
     case FTP_PROT:
@@ -2753,31 +2788,25 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       if(data->set.ftp_ccc) {
         /* CCC - Clear Command Channel
          */
-        PPSENDF(&ftpc->pp, "%s", "CCC");
-        state(conn, FTP_CCC);
-      }
-      else {
-        result = ftp_state_pwd(conn);
-        if(result)
-          return result;
+        result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC");
+        if(!result)
+          state(data, FTP_CCC);
       }
+      else
+        result = ftp_state_pwd(data, conn);
       break;
 
     case FTP_CCC:
       if(ftpcode < 500) {
         /* First shut down the SSL layer (note: this call will block) */
-        result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
+        result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET);
 
-        if(result) {
-          failf(conn->data, "Failed to clear the command channel (CCC)");
-          return result;
-        }
+        if(result)
+          failf(data, "Failed to clear the command channel (CCC)");
       }
-
-      /* Then continue as normal */
-      result = ftp_state_pwd(conn);
-      if(result)
-        return result;
+      if(!result)
+        /* Then continue as normal */
+        result = ftp_state_pwd(data, conn);
       break;
 
     case FTP_PWD:
@@ -2843,8 +2872,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
              systems. */
 
           if(!ftpc->server_os && dir[0] != '/') {
-
-            result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
+            result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST");
             if(result) {
               free(dir);
               return result;
@@ -2854,7 +2882,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
             infof(data, "Entry path is '%s'\n", ftpc->entrypath);
             /* also save it where getinfo can access it: */
             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
-            state(conn, FTP_SYST);
+            state(data, FTP_SYST);
             break;
           }
 
@@ -2870,7 +2898,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
           infof(data, "Failed to figure out path\n");
         }
       }
-      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+      state(data, FTP_STOP); /* we are done with the CONNECT phase! */
       DEBUGF(infof(data, "protocol connect phase DONE\n"));
       break;
 
@@ -2897,7 +2925,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 
         if(strcasecompare(os, "OS/400")) {
           /* Force OS400 name format 1. */
-          result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
+          result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
           if(result) {
             free(os);
             return result;
@@ -2905,7 +2933,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
           /* remember target server OS */
           Curl_safefree(ftpc->server_os);
           ftpc->server_os = os;
-          state(conn, FTP_NAMEFMT);
+          state(data, FTP_NAMEFMT);
           break;
         }
         /* Nothing special for the target server. */
@@ -2917,18 +2945,18 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
         /* Cannot identify server OS. Continue anyway and cross fingers. */
       }
 
-      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+      state(data, FTP_STOP); /* we are done with the CONNECT phase! */
       DEBUGF(infof(data, "protocol connect phase DONE\n"));
       break;
 
     case FTP_NAMEFMT:
       if(ftpcode == 250) {
         /* Name format change successful: reload initial path. */
-        ftp_state_pwd(conn);
+        ftp_state_pwd(data, conn);
         break;
       }
 
-      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+      state(data, FTP_STOP); /* we are done with the CONNECT phase! */
       DEBUGF(infof(data, "protocol connect phase DONE\n"));
       break;
 
@@ -2938,45 +2966,42 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
     case FTP_STOR_PREQUOTE:
       if((ftpcode >= 400) && !ftpc->count2) {
         /* failure response code, and not allowed to fail */
-        failf(conn->data, "QUOT command failed with %03d", ftpcode);
-        return CURLE_QUOTE_ERROR;
+        failf(data, "QUOT command failed with %03d", ftpcode);
+        result = CURLE_QUOTE_ERROR;
       }
-      result = ftp_state_quote(conn, FALSE, ftpc->state);
-      if(result)
-        return result;
-
+      else
+        result = ftp_state_quote(data, FALSE, ftpc->state);
       break;
 
     case FTP_CWD:
       if(ftpcode/100 != 2) {
         /* failure to CWD there */
-        if(conn->data->set.ftp_create_missing_dirs &&
+        if(data->set.ftp_create_missing_dirs &&
            ftpc->cwdcount && !ftpc->count2) {
           /* try making it */
           ftpc->count2++; /* counter to prevent CWD-MKD loops */
-          PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]);
-          state(conn, FTP_MKD);
+          result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
+                                 ftpc->dirs[ftpc->cwdcount - 1]);
+          if(!result)
+            state(data, FTP_MKD);
         }
         else {
           /* return failure */
           failf(data, "Server denied you to change to the given directory");
           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
                                    to enter it */
-          return CURLE_REMOTE_ACCESS_DENIED;
+          result = CURLE_REMOTE_ACCESS_DENIED;
         }
       }
       else {
         /* success */
         ftpc->count2 = 0;
-        if(++ftpc->cwdcount <= ftpc->dirdepth) {
+        if(++ftpc->cwdcount <= ftpc->dirdepth)
           /* send next CWD */
-          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
-        }
-        else {
-          result = ftp_state_mdtm(conn);
-          if(result)
-            return result;
-        }
+          result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
+                                 ftpc->dirs[ftpc->cwdcount - 1]);
+        else
+          result = ftp_state_mdtm(data);
       }
       break;
 
@@ -2984,33 +3009,36 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       if((ftpcode/100 != 2) && !ftpc->count3--) {
         /* failure to MKD the dir */
         failf(data, "Failed to MKD dir: %03d", ftpcode);
-        return CURLE_REMOTE_ACCESS_DENIED;
+        result = CURLE_REMOTE_ACCESS_DENIED;
+      }
+      else {
+        state(data, FTP_CWD);
+        /* send CWD */
+        result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
+                               ftpc->dirs[ftpc->cwdcount - 1]);
       }
-      state(conn, FTP_CWD);
-      /* send CWD */
-      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
       break;
 
     case FTP_MDTM:
-      result = ftp_state_mdtm_resp(conn, ftpcode);
+      result = ftp_state_mdtm_resp(data, ftpcode);
       break;
 
     case FTP_TYPE:
     case FTP_LIST_TYPE:
     case FTP_RETR_TYPE:
     case FTP_STOR_TYPE:
-      result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
+      result = ftp_state_type_resp(data, ftpcode, ftpc->state);
       break;
 
     case FTP_SIZE:
     case FTP_RETR_SIZE:
     case FTP_STOR_SIZE:
-      result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
+      result = ftp_state_size_resp(data, ftpcode, ftpc->state);
       break;
 
     case FTP_REST:
     case FTP_RETR_REST:
-      result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
+      result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state);
       break;
 
     case FTP_PRET:
@@ -3019,31 +3047,31 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
         failf(data, "PRET command not accepted: %03d", ftpcode);
         return CURLE_FTP_PRET_FAILED;
       }
-      result = ftp_state_use_pasv(conn);
+      result = ftp_state_use_pasv(data, conn);
       break;
 
     case FTP_PASV:
-      result = ftp_state_pasv_resp(conn, ftpcode);
+      result = ftp_state_pasv_resp(data, ftpcode);
       break;
 
     case FTP_PORT:
-      result = ftp_state_port_resp(conn, ftpcode);
+      result = ftp_state_port_resp(data, ftpcode);
       break;
 
     case FTP_LIST:
     case FTP_RETR:
-      result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
+      result = ftp_state_get_resp(data, ftpcode, ftpc->state);
       break;
 
     case FTP_STOR:
-      result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
+      result = ftp_state_stor_resp(data, ftpcode, ftpc->state);
       break;
 
     case FTP_QUIT:
       /* fallthrough, just stop! */
     default:
       /* internal error */
-      state(conn, FTP_STOP);
+      state(data, FTP_STOP);
       break;
     }
   } /* if(ftpcode) */
@@ -3053,11 +3081,12 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 
 
 /* called repeatedly until done from multi.c */
-static CURLcode ftp_multi_statemach(struct connectdata *conn,
+static CURLcode ftp_multi_statemach(struct Curl_easy *data,
                                     bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
-  CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE, FALSE);
+  CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE);
 
   /* Check for the state outside of the Curl_socket_check() return code checks
      since at times we are in fact already in this state when this function
@@ -3067,14 +3096,15 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn,
   return result;
 }
 
-static CURLcode ftp_block_statemach(struct connectdata *conn)
+static CURLcode ftp_block_statemach(struct Curl_easy *data,
+                                    struct connectdata *conn)
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
   CURLcode result = CURLE_OK;
 
   while(ftpc->state != FTP_STOP) {
-    result = Curl_pp_statemach(pp, TRUE, TRUE /* disconnecting */);
+    result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */);
     if(result)
       break;
   }
@@ -3090,10 +3120,11 @@ static CURLcode ftp_block_statemach(struct connectdata *conn)
  * phase is done when this function returns, or FALSE if not.
  *
  */
-static CURLcode ftp_connect(struct connectdata *conn,
-                                 bool *done) /* see description above */
+static CURLcode ftp_connect(struct Curl_easy *data,
+                            bool *done) /* see description above */
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
 
@@ -3102,25 +3133,24 @@ static CURLcode ftp_connect(struct connectdata *conn,
   /* We always support persistent connections on ftp */
   connkeep(conn, "FTP default");
 
-  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
-  pp->statemach_act = ftp_statemach_act;
-  pp->endofresp = ftp_endofresp;
-  pp->conn = conn;
+  PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp);
 
   if(conn->handler->flags & PROTOPT_SSL) {
     /* BLOCKING */
-    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
     if(result)
       return result;
+    conn->bits.ftp_use_control_ssl = TRUE;
   }
 
-  Curl_pp_init(pp); /* init the generic pingpong data */
+  Curl_pp_setup(pp); /* once per transfer */
+  Curl_pp_init(data, pp); /* init the generic pingpong data */
 
   /* When we connect, we start in the state where we await the 220
      response */
-  state(conn, FTP_WAIT220);
+  state(data, FTP_WAIT220);
 
-  result = ftp_multi_statemach(conn, done);
+  result = ftp_multi_statemach(data, done);
 
   return result;
 }
@@ -3134,11 +3164,11 @@ static CURLcode ftp_connect(struct connectdata *conn,
  *
  * Input argument is already checked for validity.
  */
-static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
+static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
                          bool premature)
 {
-  struct Curl_easy *data = conn->data;
-  struct FTP *ftp = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
   ssize_t nread;
@@ -3241,7 +3271,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
     if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
       /* partial download completed */
-      result = Curl_pp_sendf(pp, "%s", "ABOR");
+      result = Curl_pp_sendf(data, pp, "%s", "ABOR");
       if(result) {
         failf(data, "Failure sending ABOR command: %s",
               curl_easy_strerror(result));
@@ -3253,12 +3283,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
     if(conn->ssl[SECONDARYSOCKET].use) {
       /* The secondary socket is using SSL so we must close down that part
          first before we close the socket for real */
-      Curl_ssl_close(conn, SECONDARYSOCKET);
+      Curl_ssl_close(data, conn, SECONDARYSOCKET);
 
       /* Note that we keep "use" set to TRUE since that (next) connection is
          still requested to use SSL */
     }
-    close_secondarysocket(conn);
+    close_secondarysocket(data, conn);
   }
 
   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
@@ -3274,7 +3304,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
     pp->response_time = 60*1000; /* give it only a minute for now */
     pp->response = Curl_now(); /* timeout relative now */
 
-    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    result = Curl_GetFTPResponse(data, &nread, &ftpcode);
 
     pp->response_time = old_time; /* set this back to previous value */
 
@@ -3297,9 +3327,18 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
 
     if(!ftpc->dont_check) {
       /* 226 Transfer complete, 250 Requested file action okay, completed. */
-      if((ftpcode != 226) && (ftpcode != 250)) {
+      switch(ftpcode) {
+      case 226:
+      case 250:
+        break;
+      case 552:
+        failf(data, "Exceeded storage allocation");
+        result = CURLE_REMOTE_DISK_FULL;
+        break;
+      default:
         failf(data, "server did not report OK, got %d", ftpcode);
         result = CURLE_PARTIAL_FILE;
+        break;
       }
     }
   }
@@ -3349,7 +3388,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
 
   /* Send any post-transfer QUOTE strings? */
   if(!status && !result && !premature && data->set.postquote)
-    result = ftp_sendquote(conn, data->set.postquote);
+    result = ftp_sendquote(data, conn, data->set.postquote);
   Curl_safefree(ftp->pathalloc);
   return result;
 }
@@ -3365,20 +3404,21 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
  */
 
 static
-CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
+CURLcode ftp_sendquote(struct Curl_easy *data,
+                       struct connectdata *conn, struct curl_slist *quote)
 {
   struct curl_slist *item;
-  ssize_t nread;
-  int ftpcode;
-  CURLcode result;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
 
   item = quote;
   while(item) {
     if(item->data) {
+      ssize_t nread;
       char *cmd = item->data;
       bool acceptfail = FALSE;
+      CURLcode result;
+      int ftpcode = 0;
 
       /* if a command starts with an asterisk, which a legal FTP command never
          can, the command will be allowed to fail without it causing any
@@ -3390,16 +3430,16 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
         acceptfail = TRUE;
       }
 
-      PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
-
-      pp->response = Curl_now(); /* timeout relative now */
-
-      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+      result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
+      if(!result) {
+        pp->response = Curl_now(); /* timeout relative now */
+        result = Curl_GetFTPResponse(data, &nread, &ftpcode);
+      }
       if(result)
         return result;
 
       if(!acceptfail && (ftpcode >= 400)) {
-        failf(conn->data, "QUOT string not accepted: %s", cmd);
+        failf(data, "QUOT string not accepted: %s", cmd);
         return CURLE_QUOTE_ERROR;
       }
     }
@@ -3430,7 +3470,8 @@ static int ftp_need_type(struct connectdata *conn,
  * sets one of them.
  * If the transfer type is not sent, simulate on OK response in newstate
  */
-static CURLcode ftp_nb_type(struct connectdata *conn,
+static CURLcode ftp_nb_type(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool ascii, ftpstate newstate)
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
@@ -3438,16 +3479,18 @@ static CURLcode ftp_nb_type(struct connectdata *conn,
   char want = (char)(ascii?'A':'I');
 
   if(ftpc->transfertype == want) {
-    state(conn, newstate);
-    return ftp_state_type_resp(conn, 200, newstate);
+    state(data, newstate);
+    return ftp_state_type_resp(data, 200, newstate);
   }
 
-  PPSENDF(&ftpc->pp, "TYPE %c", want);
-  state(conn, newstate);
+  result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want);
+  if(!result) {
+    state(data, newstate);
 
-  /* keep track of our current transfer type */
-  ftpc->transfertype = want;
-  return CURLE_OK;
+    /* keep track of our current transfer type */
+    ftpc->transfertype = want;
+  }
+  return result;
 }
 
 /***************************************************************************
@@ -3461,14 +3504,14 @@ static CURLcode ftp_nb_type(struct connectdata *conn,
  */
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
 static void
-ftp_pasv_verbose(struct connectdata *conn,
+ftp_pasv_verbose(struct Curl_easy *data,
                  struct Curl_addrinfo *ai,
                  char *newhost, /* ascii version */
                  int port)
 {
   char buf[256];
   Curl_printable_address(ai, buf, sizeof(buf));
-  infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
+  infof(data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
 }
 #endif
 
@@ -3483,28 +3526,28 @@ ftp_pasv_verbose(struct connectdata *conn,
  * EPSV).
  */
 
-static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
+static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
   bool complete = FALSE;
 
   /* the ftp struct is inited in ftp_connect() */
-  struct FTP *ftp = data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
 
   /* if the second connection isn't done yet, wait for it */
   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
     if(Curl_connect_ongoing(conn)) {
       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
          aren't used so we blank their arguments. */
-      result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
+      result = Curl_proxyCONNECT(data, SECONDARYSOCKET, NULL, 0);
 
       return result;
     }
 
-    result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
+    result = Curl_is_connected(data, conn, SECONDARYSOCKET, &connected);
 
     /* Ready to do more? */
     if(connected) {
@@ -3514,14 +3557,14 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
       if(result && (ftpc->count1 == 0)) {
         *completep = -1; /* go back to DOING please */
         /* this is a EPSV connect failing, try PASV instead */
-        return ftp_epsv_disable(conn);
+        return ftp_epsv_disable(data, conn);
       }
       return result;
     }
   }
 
 #ifndef CURL_DISABLE_PROXY
-  result = Curl_proxy_connect(conn, SECONDARYSOCKET);
+  result = Curl_proxy_connect(data, SECONDARYSOCKET);
   if(result)
     return result;
 
@@ -3536,7 +3579,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
   if(ftpc->state) {
     /* already in a state so skip the initial commands.
        They are only done to kickstart the do_more state */
-    result = ftp_multi_statemach(conn, &complete);
+    result = ftp_multi_statemach(data, &complete);
 
     *completep = (int)complete;
 
@@ -3558,16 +3601,16 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
     if(ftpc->wait_data_conn == TRUE) {
       bool serv_conned;
 
-      result = ReceivedServerConnect(conn, &serv_conned);
+      result = ReceivedServerConnect(data, &serv_conned);
       if(result)
         return result; /* Failed to accept data connection */
 
       if(serv_conned) {
         /* It looks data connection is established */
-        result = AcceptServerConnect(conn);
+        result = AcceptServerConnect(data);
         ftpc->wait_data_conn = FALSE;
         if(!result)
-          result = InitiateTransfer(conn);
+          result = InitiateTransfer(data);
 
         if(result)
           return result;
@@ -3577,11 +3620,11 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
       }
     }
     else if(data->set.upload) {
-      result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+      result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_STOR_TYPE);
       if(result)
         return result;
 
-      result = ftp_multi_statemach(conn, &complete);
+      result = ftp_multi_statemach(data, &complete);
       /* ftpc->wait_data_conn is always false here */
       *completep = (int)complete;
     }
@@ -3589,7 +3632,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
       /* download */
       ftp->downloadsize = -1; /* unknown as of yet */
 
-      result = Curl_range(conn);
+      result = Curl_range(data);
 
       if(result == CURLE_OK && data->req.maxdownload >= 0) {
         /* Don't check for successful transfer */
@@ -3605,19 +3648,20 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
 
         /* But only if a body transfer was requested. */
         if(ftp->transfer == FTPTRANSFER_BODY) {
-          result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
+          result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
           if(result)
             return result;
         }
         /* otherwise just fall through */
       }
       else {
-        result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
+        result = ftp_nb_type(data, conn, data->set.prefer_ascii,
+                             FTP_RETR_TYPE);
         if(result)
           return result;
       }
 
-      result = ftp_multi_statemach(conn, &complete);
+      result = ftp_multi_statemach(data, &complete);
       *completep = (int)complete;
     }
     return result;
@@ -3646,37 +3690,38 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
  */
 
 static
-CURLcode ftp_perform(struct connectdata *conn,
+CURLcode ftp_perform(struct Curl_easy *data,
                      bool *connected,  /* connect status after PASV / PORT */
                      bool *dophase_done)
 {
   /* this is FTP and no proxy */
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
-  if(conn->data->set.opt_no_body) {
+  if(data->set.opt_no_body) {
     /* requested no body means no transfer... */
-    struct FTP *ftp = conn->data->req.protop;
+    struct FTP *ftp = data->req.p.ftp;
     ftp->transfer = FTPTRANSFER_INFO;
   }
 
   *dophase_done = FALSE; /* not done yet */
 
   /* start the first command in the DO phase */
-  result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
+  result = ftp_state_quote(data, TRUE, FTP_QUOTE);
   if(result)
     return result;
 
   /* run the state-machine */
-  result = ftp_multi_statemach(conn, dophase_done);
+  result = ftp_multi_statemach(data, dophase_done);
 
   *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
 
-  infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
+  infof(data, "ftp_perform ends with SECONDARY: %d\n", *connected);
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete1\n"));
+    DEBUGF(infof(data, "DO phase is complete1\n"));
   }
 
   return result;
@@ -3690,12 +3735,12 @@ static void wc_data_dtor(void *ptr)
   free(ftpwc);
 }
 
-static CURLcode init_wc_data(struct connectdata *conn)
+static CURLcode init_wc_data(struct Curl_easy *data)
 {
   char *last_slash;
-  struct FTP *ftp = conn->data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
   char *path = ftp->path;
-  struct WildcardData *wildcard = &(conn->data->wildcard);
+  struct WildcardData *wildcard = &(data->wildcard);
   CURLcode result = CURLE_OK;
   struct ftp_wc *ftpwc = NULL;
 
@@ -3704,7 +3749,7 @@ static CURLcode init_wc_data(struct connectdata *conn)
     last_slash++;
     if(last_slash[0] == '\0') {
       wildcard->state = CURLWC_CLEAN;
-      result = ftp_parse_url_path(conn);
+      result = ftp_parse_url_path(data);
       return result;
     }
     wildcard->pattern = strdup(last_slash);
@@ -3721,7 +3766,7 @@ static CURLcode init_wc_data(struct connectdata *conn)
     }
     else { /* only list */
       wildcard->state = CURLWC_CLEAN;
-      result = ftp_parse_url_path(conn);
+      result = ftp_parse_url_path(data);
       return result;
     }
   }
@@ -3747,11 +3792,11 @@ static CURLcode init_wc_data(struct connectdata *conn)
   wildcard->dtor = wc_data_dtor;
 
   /* wildcard does not support NOCWD option (assert it?) */
-  if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
-    conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
+  if(data->set.ftp_filemethod == FTPFILE_NOCWD)
+    data->set.ftp_filemethod = FTPFILE_MULTICWD;
 
   /* try to parse ftp url */
-  result = ftp_parse_url_path(conn);
+  result = ftp_parse_url_path(data);
   if(result) {
     goto fail;
   }
@@ -3763,15 +3808,15 @@ static CURLcode init_wc_data(struct connectdata *conn)
   }
 
   /* backup old write_function */
-  ftpwc->backup.write_function = conn->data->set.fwrite_func;
+  ftpwc->backup.write_function = data->set.fwrite_func;
   /* parsing write function */
-  conn->data->set.fwrite_func = Curl_ftp_parselist;
+  data->set.fwrite_func = Curl_ftp_parselist;
   /* backup old file descriptor */
-  ftpwc->backup.file_descriptor = conn->data->set.out;
-  /* let the writefunc callback know what curl pointer is working with */
-  conn->data->set.out = conn;
+  ftpwc->backup.file_descriptor = data->set.out;
+  /* let the writefunc callback know the transfer */
+  data->set.out = data;
 
-  infof(conn->data, "Wildcard - Parsing started\n");
+  infof(data, "Wildcard - Parsing started\n");
   return CURLE_OK;
 
   fail:
@@ -3785,129 +3830,132 @@ static CURLcode init_wc_data(struct connectdata *conn)
   return result;
 }
 
-/* This is called recursively */
-static CURLcode wc_statemach(struct connectdata *conn)
+static CURLcode wc_statemach(struct Curl_easy *data)
 {
-  struct WildcardData * const wildcard = &(conn->data->wildcard);
+  struct WildcardData * const wildcard = &(data->wildcard);
+  struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
 
-  switch(wildcard->state) {
-  case CURLWC_INIT:
-    result = init_wc_data(conn);
-    if(wildcard->state == CURLWC_CLEAN)
-      /* only listing! */
-      break;
-    wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
-    break;
+  for(;;) {
+    switch(wildcard->state) {
+    case CURLWC_INIT:
+      result = init_wc_data(data);
+      if(wildcard->state == CURLWC_CLEAN)
+        /* only listing! */
+        return result;
+      wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
+      return result;
 
-  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;
-    conn->data->set.fwrite_func = ftpwc->backup.write_function;
-    conn->data->set.out = ftpwc->backup.file_descriptor;
-    ftpwc->backup.write_function = ZERO_NULL;
-    ftpwc->backup.file_descriptor = NULL;
-    wildcard->state = CURLWC_DOWNLOADING;
-
-    if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
-      /* error found in LIST parsing */
-      wildcard->state = CURLWC_CLEAN;
-      return wc_statemach(conn);
-    }
-    if(wildcard->filelist.size == 0) {
-      /* no corresponding file */
-      wildcard->state = CURLWC_CLEAN;
-      return CURLE_REMOTE_FILE_NOT_FOUND;
+    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;
+      data->set.fwrite_func = ftpwc->backup.write_function;
+      data->set.out = ftpwc->backup.file_descriptor;
+      ftpwc->backup.write_function = ZERO_NULL;
+      ftpwc->backup.file_descriptor = NULL;
+      wildcard->state = CURLWC_DOWNLOADING;
+
+      if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
+        /* error found in LIST parsing */
+        wildcard->state = CURLWC_CLEAN;
+        continue;
+      }
+      if(wildcard->filelist.size == 0) {
+        /* no corresponding file */
+        wildcard->state = CURLWC_CLEAN;
+        return CURLE_REMOTE_FILE_NOT_FOUND;
+      }
+      continue;
     }
-    return wc_statemach(conn);
-  }
 
-  case CURLWC_DOWNLOADING: {
-    /* filelist has at least one file, lets get first one */
-    struct ftp_conn *ftpc = &conn->proto.ftpc;
-    struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
-    struct FTP *ftp = conn->data->req.protop;
+    case CURLWC_DOWNLOADING: {
+      /* filelist has at least one file, lets get first one */
+      struct ftp_conn *ftpc = &conn->proto.ftpc;
+      struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+      struct FTP *ftp = data->req.p.ftp;
 
-    char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
-    if(!tmp_path)
-      return CURLE_OUT_OF_MEMORY;
+      char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
+      if(!tmp_path)
+        return CURLE_OUT_OF_MEMORY;
 
-    /* switch default ftp->path and tmp_path */
-    free(ftp->pathalloc);
-    ftp->pathalloc = ftp->path = tmp_path;
-
-    infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
-    if(conn->data->set.chunk_bgn) {
-      long userresponse;
-      Curl_set_in_callback(conn->data, true);
-      userresponse = conn->data->set.chunk_bgn(
-        finfo, wildcard->customptr, (int)wildcard->filelist.size);
-      Curl_set_in_callback(conn->data, false);
-      switch(userresponse) {
-      case CURL_CHUNK_BGN_FUNC_SKIP:
-        infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
-              finfo->filename);
-        wildcard->state = CURLWC_SKIP;
-        return wc_statemach(conn);
-      case CURL_CHUNK_BGN_FUNC_FAIL:
-        return CURLE_CHUNK_FAILED;
+      /* switch default ftp->path and tmp_path */
+      free(ftp->pathalloc);
+      ftp->pathalloc = ftp->path = tmp_path;
+
+      infof(data, "Wildcard - START of \"%s\"\n", finfo->filename);
+      if(data->set.chunk_bgn) {
+        long userresponse;
+        Curl_set_in_callback(data, true);
+        userresponse = data->set.chunk_bgn(
+          finfo, wildcard->customptr, (int)wildcard->filelist.size);
+        Curl_set_in_callback(data, false);
+        switch(userresponse) {
+        case CURL_CHUNK_BGN_FUNC_SKIP:
+          infof(data, "Wildcard - \"%s\" skipped by user\n",
+                finfo->filename);
+          wildcard->state = CURLWC_SKIP;
+          continue;
+        case CURL_CHUNK_BGN_FUNC_FAIL:
+          return CURLE_CHUNK_FAILED;
+        }
       }
-    }
 
-    if(finfo->filetype != CURLFILETYPE_FILE) {
-      wildcard->state = CURLWC_SKIP;
-      return wc_statemach(conn);
-    }
+      if(finfo->filetype != CURLFILETYPE_FILE) {
+        wildcard->state = CURLWC_SKIP;
+        continue;
+      }
 
-    if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
-      ftpc->known_filesize = finfo->size;
+      if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
+        ftpc->known_filesize = finfo->size;
 
-    result = ftp_parse_url_path(conn);
-    if(result)
-      return result;
+      result = ftp_parse_url_path(data);
+      if(result)
+        return result;
 
-    /* we don't need the Curl_fileinfo of first file anymore */
-    Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+      /* we don't need the Curl_fileinfo of first file anymore */
+      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
 
-    if(wildcard->filelist.size == 0) { /* remains only one file to down. */
-      wildcard->state = CURLWC_CLEAN;
-      /* after that will be ftp_do called once again and no transfer
-         will be done because of CURLWC_CLEAN state */
-      return CURLE_OK;
+      if(wildcard->filelist.size == 0) { /* remains only one file to down. */
+        wildcard->state = CURLWC_CLEAN;
+        /* after that will be ftp_do called once again and no transfer
+           will be done because of CURLWC_CLEAN state */
+        return CURLE_OK;
+      }
+      return result;
     }
-  } break;
 
-  case CURLWC_SKIP: {
-    if(conn->data->set.chunk_end) {
-      Curl_set_in_callback(conn->data, true);
-      conn->data->set.chunk_end(conn->data->wildcard.customptr);
-      Curl_set_in_callback(conn->data, false);
+    case CURLWC_SKIP: {
+      if(data->set.chunk_end) {
+        Curl_set_in_callback(data, true);
+        data->set.chunk_end(data->wildcard.customptr);
+        Curl_set_in_callback(data, false);
+      }
+      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+      wildcard->state = (wildcard->filelist.size == 0) ?
+        CURLWC_CLEAN : CURLWC_DOWNLOADING;
+      continue;
     }
-    Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
-    wildcard->state = (wildcard->filelist.size == 0) ?
-                      CURLWC_CLEAN : CURLWC_DOWNLOADING;
-    return wc_statemach(conn);
-  }
 
-  case CURLWC_CLEAN: {
-    struct ftp_wc *ftpwc = wildcard->protdata;
-    result = CURLE_OK;
-    if(ftpwc)
-      result = Curl_ftp_parselist_geterror(ftpwc->parser);
+    case CURLWC_CLEAN: {
+      struct ftp_wc *ftpwc = wildcard->protdata;
+      result = CURLE_OK;
+      if(ftpwc)
+        result = Curl_ftp_parselist_geterror(ftpwc->parser);
 
-    wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
-  } break;
+      wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
+      return result;
+    }
 
-  case CURLWC_DONE:
-  case CURLWC_ERROR:
-  case CURLWC_CLEAR:
-    if(wildcard->dtor)
-      wildcard->dtor(wildcard->protdata);
-    break;
+    case CURLWC_DONE:
+    case CURLWC_ERROR:
+    case CURLWC_CLEAR:
+      if(wildcard->dtor)
+        wildcard->dtor(wildcard->protdata);
+      return result;
+    }
   }
-
-  return result;
+  /* UNREACHABLE */
 }
 
 /***********************************************************************
@@ -3919,18 +3967,19 @@ static CURLcode wc_statemach(struct connectdata *conn)
  *
  * The input argument is already checked for validity.
  */
-static CURLcode ftp_do(struct connectdata *conn, bool *done)
+static CURLcode ftp_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   *done = FALSE; /* default to false */
   ftpc->wait_data_conn = FALSE; /* default to no such wait */
 
-  if(conn->data->state.wildcardmatch) {
-    result = wc_statemach(conn);
-    if(conn->data->wildcard.state == CURLWC_SKIP ||
-      conn->data->wildcard.state == CURLWC_DONE) {
+  if(data->state.wildcardmatch) {
+    result = wc_statemach(data);
+    if(data->wildcard.state == CURLWC_SKIP ||
+      data->wildcard.state == CURLWC_DONE) {
       /* do not call ftp_regular_transfer */
       return CURLE_OK;
     }
@@ -3938,70 +3987,12 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done)
       return result;
   }
   else { /* no wildcard FSM needed */
-    result = ftp_parse_url_path(conn);
+    result = ftp_parse_url_path(data);
     if(result)
       return result;
   }
 
-  result = ftp_regular_transfer(conn, done);
-
-  return result;
-}
-
-
-CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
-{
-  ssize_t bytes_written;
-#define SBUF_SIZE 1024
-  char s[SBUF_SIZE];
-  size_t write_len;
-  char *sptr = s;
-  CURLcode result = CURLE_OK;
-#ifdef HAVE_GSSAPI
-  enum protection_level data_sec = conn->data_prot;
-#endif
-
-  if(!cmd)
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-
-  write_len = strlen(cmd);
-  if(!write_len || write_len > (sizeof(s) -3))
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-
-  memcpy(&s, cmd, write_len);
-  strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
-  write_len += 2;
-  bytes_written = 0;
-
-  result = Curl_convert_to_network(conn->data, s, write_len);
-  /* Curl_convert_to_network calls failf if unsuccessful */
-  if(result)
-    return result;
-
-  for(;;) {
-#ifdef HAVE_GSSAPI
-    conn->data_prot = PROT_CMD;
-#endif
-    result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
-                        &bytes_written);
-#ifdef HAVE_GSSAPI
-    DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
-    conn->data_prot = data_sec;
-#endif
-
-    if(result)
-      break;
-
-    if(conn->data->set.verbose)
-      Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written);
-
-    if(bytes_written != (ssize_t)write_len) {
-      write_len -= bytes_written;
-      sptr += bytes_written;
-    }
-    else
-      break;
-  }
+  result = ftp_regular_transfer(data, done);
 
   return result;
 }
@@ -4016,24 +4007,24 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
  * connection.
  *
  */
-static CURLcode ftp_quit(struct connectdata *conn)
+static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
 
   if(conn->proto.ftpc.ctl_valid) {
-    result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
+    result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT");
     if(result) {
-      failf(conn->data, "Failure sending QUIT command: %s",
+      failf(data, "Failure sending QUIT command: %s",
             curl_easy_strerror(result));
       conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
       connclose(conn, "QUIT command failed"); /* mark for connection closure */
-      state(conn, FTP_STOP);
+      state(data, FTP_STOP);
       return result;
     }
 
-    state(conn, FTP_QUIT);
+    state(data, FTP_QUIT);
 
-    result = ftp_block_statemach(conn);
+    result = ftp_block_statemach(data, conn);
   }
 
   return result;
@@ -4046,7 +4037,9 @@ static CURLcode ftp_quit(struct connectdata *conn)
  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
  * resources. BLOCKING.
  */
-static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode ftp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool dead_connection)
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
@@ -4062,29 +4055,20 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
     ftpc->ctl_valid = FALSE;
 
   /* The FTP session may or may not have been allocated/setup at this point! */
-  (void)ftp_quit(conn); /* ignore errors on the QUIT */
+  (void)ftp_quit(data, conn); /* ignore errors on the QUIT */
 
   if(ftpc->entrypath) {
-    struct Curl_easy *data = conn->data;
     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
       data->state.most_recent_ftp_entrypath = NULL;
     }
-    free(ftpc->entrypath);
-    ftpc->entrypath = NULL;
+    Curl_safefree(ftpc->entrypath);
   }
 
   freedirs(ftpc);
-  free(ftpc->prevpath);
-  ftpc->prevpath = NULL;
-  free(ftpc->server_os);
-  ftpc->server_os = NULL;
-
+  Curl_safefree(ftpc->prevpath);
+  Curl_safefree(ftpc->server_os);
   Curl_pp_disconnect(pp);
-
-#ifdef HAVE_GSSAPI
   Curl_sec_end(conn);
-#endif
-
   return CURLE_OK;
 }
 
@@ -4096,11 +4080,11 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
  *
  */
 static
-CURLcode ftp_parse_url_path(struct connectdata *conn)
+CURLcode ftp_parse_url_path(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   /* the ftp struct is already inited in ftp_connect() */
-  struct FTP *ftp = data->req.protop;
+  struct FTP *ftp = data->req.p.ftp;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   const char *slashPos = NULL;
   const char *fileName = NULL;
@@ -4242,25 +4226,25 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
 }
 
 /* call this when the DO phase has completed */
-static CURLcode ftp_dophase_done(struct connectdata *conn,
-                                 bool connected)
+static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
 {
-  struct FTP *ftp = conn->data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if(connected) {
     int completed;
-    CURLcode result = ftp_do_more(conn, &completed);
+    CURLcode result = ftp_do_more(data, &completed);
 
     if(result) {
-      close_secondarysocket(conn);
+      close_secondarysocket(data, conn);
       return result;
     }
   }
 
   if(ftp->transfer != FTPTRANSFER_BODY)
     /* no data to transfer */
-    Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
+    Curl_setup_transfer(data, -1, -1, FALSE, -1);
   else if(!connected)
     /* since we didn't connect now, we want do_more to get called */
     conn->bits.do_more = TRUE;
@@ -4271,17 +4255,17 @@ static CURLcode ftp_dophase_done(struct connectdata *conn,
 }
 
 /* called from multi.c while DOing */
-static CURLcode ftp_doing(struct connectdata *conn,
+static CURLcode ftp_doing(struct Curl_easy *data,
                           bool *dophase_done)
 {
-  CURLcode result = ftp_multi_statemach(conn, dophase_done);
+  CURLcode result = ftp_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(conn->data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed\n"));
   else if(*dophase_done) {
-    result = ftp_dophase_done(conn, FALSE /* not connected */);
+    result = ftp_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(conn->data, "DO phase is complete2\n"));
+    DEBUGF(infof(data, "DO phase is complete2\n"));
   }
   return result;
 }
@@ -4299,12 +4283,12 @@ static CURLcode ftp_doing(struct connectdata *conn,
  * ftp_done() function without finding any major problem.
  */
 static
-CURLcode ftp_regular_transfer(struct connectdata *conn,
+CURLcode ftp_regular_transfer(struct Curl_easy *data,
                               bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   data->req.size = -1; /* make sure this is unknown at this point */
 
@@ -4315,7 +4299,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
 
   ftpc->ctl_valid = TRUE; /* starts good */
 
-  result = ftp_perform(conn,
+  result = ftp_perform(data,
                        &connected, /* have we connected after PASV/PORT */
                        dophase_done); /* all commands in the DO-phase done? */
 
@@ -4325,7 +4309,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
       /* the DO phase has not completed yet */
       return CURLE_OK;
 
-    result = ftp_dophase_done(conn, connected);
+    result = ftp_dophase_done(data, connected);
 
     if(result)
       return result;
@@ -4336,13 +4320,13 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
   return result;
 }
 
-static CURLcode ftp_setup_connection(struct connectdata *conn)
+static CURLcode ftp_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn)
 {
-  struct Curl_easy *data = conn->data;
   char *type;
   struct FTP *ftp;
 
-  conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
+  data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
   if(NULL == ftp)
     return CURLE_OUT_OF_MEMORY;
 
index 06421c6..1cfdac0 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -31,8 +31,7 @@ extern const struct Curl_handler Curl_handler_ftp;
 extern const struct Curl_handler Curl_handler_ftps;
 #endif
 
-CURLcode Curl_ftpsend(struct connectdata *, const char *cmd);
-CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
+CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nread,
                              int *ftpcode);
 #endif /* CURL_DISABLE_FTP */
 
@@ -117,9 +116,9 @@ struct FTP {
 struct ftp_conn {
   struct pingpong pp;
   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 */
   int dirdepth;  /* number of entries used in the 'dirs' array */
-  char *file;    /* url-decoded file name (or path) */
   bool dont_check;  /* Set to TRUE to prevent the final (post-transfer)
                        file size and 226/250 status check. It should still
                        read the line, just ignore the result. */
@@ -132,6 +131,10 @@ struct ftp_conn {
   bool cwdfail;     /* set TRUE if a CWD command fails, as then we must prevent
                        caching the current directory */
   bool wait_data_conn; /* this is set TRUE if data connection is waited */
+  /* newhost is the (allocated) IP addr or host name to connect the data
+     connection to */
+  unsigned short newport;
+  char *newhost;
   char *prevpath;   /* url-decoded conn->path from the previous transfer */
   char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
                         and others (A/I or zero) */
@@ -146,10 +149,6 @@ struct ftp_conn {
   curl_off_t known_filesize; /* file size is different from -1, if wildcard
                                 LIST parsing was done and wc_statemach set
                                 it */
-  /* newhost is the (allocated) IP addr or host name to connect the data
-     connection to */
-  char *newhost;          /* this is the pair to connect the DATA... */
-  unsigned short newport; /* connection to */
 };
 
 #define DEFAULT_ACCEPT_TIMEOUT   60000 /* milliseconds == one minute */
index f399a4c..d3720b1 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -268,13 +268,13 @@ static int ftp_pl_get_permission(const char *str)
   return permissions;
 }
 
-static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
+static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
                                     struct fileinfo *infop)
 {
   curl_fnmatch_callback compare;
-  struct WildcardData *wc = &conn->data->wildcard;
+  struct WildcardData *wc = &data->wildcard;
   struct ftp_wc *ftpwc = wc->protdata;
-  struct curl_llist *llist = &wc->filelist;
+  struct Curl_llist *llist = &wc->filelist;
   struct ftp_parselist_data *parser = ftpwc->parser;
   bool add = TRUE;
   struct curl_fileinfo *finfo = &infop->info;
@@ -293,13 +293,13 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
                           str + parser->offsets.user : NULL;
 
   /* get correct fnmatch callback */
-  compare = conn->data->set.fnmatch;
+  compare = data->set.fnmatch;
   if(!compare)
     compare = Curl_fnmatch;
 
   /* filter pattern-corresponding filenames */
-  Curl_set_in_callback(conn->data, true);
-  if(compare(conn->data->set.fnmatch_data, wc->pattern,
+  Curl_set_in_callback(data, true);
+  if(compare(data->set.fnmatch_data, wc->pattern,
              finfo->filename) == 0) {
     /* discard symlink which is containing multiple " -> " */
     if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
@@ -310,7 +310,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
   else {
     add = FALSE;
   }
-  Curl_set_in_callback(conn->data, false);
+  Curl_set_in_callback(data, false);
 
   if(add) {
     Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
@@ -327,8 +327,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
                           void *connptr)
 {
   size_t bufflen = size*nmemb;
-  struct connectdata *conn = (struct connectdata *)connptr;
-  struct ftp_wc *ftpwc = conn->data->wildcard.protdata;
+  struct Curl_easy *data = (struct Curl_easy *)connptr;
+  struct ftp_wc *ftpwc = data->wildcard.protdata;
   struct ftp_parselist_data *parser = ftpwc->parser;
   struct fileinfo *infop;
   struct curl_fileinfo *finfo;
@@ -418,8 +418,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             finfo->b_data[parser->item_length - 1] = 0;
             if(strncmp("total ", finfo->b_data, 6) == 0) {
               char *endptr = finfo->b_data + 6;
-              /* here we can deal with directory size, pass the leading white
-                 spaces and then the digits */
+              /* here we can deal with directory size, pass the leading
+                 whitespace and then the digits */
               while(ISSPACE(*endptr))
                 endptr++;
               while(ISDIGIT(*endptr))
@@ -728,7 +728,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -740,7 +740,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -835,7 +835,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           else if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -847,7 +847,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -967,7 +967,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             parser->offsets.filename = parser->item_offset;
             finfo->b_data[finfo->b_used - 1] = 0;
             parser->offsets.filename = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -979,7 +979,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
         case PL_WINNT_FILENAME_WINEOL:
           if(c == '\n') {
             parser->offsets.filename = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
index b34ae9b..e4cd820 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 9385b8f..92c5350 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 82691dc..67ea07d 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -101,6 +101,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
     if(!m) {
       if(data->set.opt_no_body)
         m = "HEAD";
+#ifndef CURL_DISABLE_HTTP
       else {
         switch(data->state.httpreq) {
         case HTTPREQ_POST:
@@ -120,6 +121,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
           break;
         }
       }
+#endif
     }
     *param_charp = m;
   }
@@ -269,6 +271,9 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
     /* Return the local port of the most recent (primary) connection */
     *param_longp = data->info.conn_local_port;
     break;
+  case CURLINFO_PROXY_ERROR:
+    *param_longp = (long)data->info.pxcode;
+    break;
   case CURLINFO_CONDITION_UNMET:
     if(data->info.httpcode == 304)
       *param_longp = 1L;
index 8d2af42..f35d1b4 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index b4811b2..a39cc7e 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -33,6 +33,7 @@
 #include "gopher.h"
 #include "select.h"
 #include "strdup.h"
+#include "vtls/vtls.h"
 #include "url.h"
 #include "escape.h"
 #include "warnless.h"
  * Forward declarations.
  */
 
-static CURLcode gopher_do(struct connectdata *conn, bool *done);
+static CURLcode gopher_do(struct Curl_easy *data, bool *done);
+#ifdef USE_SSL
+static CURLcode gopher_connect(struct Curl_easy *data, bool *done);
+static CURLcode gopher_connecting(struct Curl_easy *data, bool *done);
+#endif
 
 /*
  * Gopher protocol handler.
@@ -71,13 +76,55 @@ const struct Curl_handler Curl_handler_gopher = {
   ZERO_NULL,                            /* connection_check */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHER,                     /* protocol */
+  CURLPROTO_GOPHER,                     /* family */
   PROTOPT_NONE                          /* flags */
 };
 
-static CURLcode gopher_do(struct connectdata *conn, bool *done)
+#ifdef USE_SSL
+const struct Curl_handler Curl_handler_gophers = {
+  "GOPHERS",                            /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  gopher_do,                            /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  gopher_connect,                       /* connect_it */
+  gopher_connecting,                    /* 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 */
+  PORT_GOPHER,                          /* defport */
+  CURLPROTO_GOPHERS,                    /* protocol */
+  CURLPROTO_GOPHER,                     /* family */
+  PROTOPT_SSL                           /* flags */
+};
+
+static CURLcode gopher_connect(struct Curl_easy *data, bool *done)
+{
+  (void)data;
+  (void)done;
+  return CURLE_OK;
+}
+
+static CURLcode gopher_connecting(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
+  if(result)
+    connclose(conn, "Failed TLS connection");
+  *done = TRUE;
+  return result;
+}
+#endif
+
+static CURLcode gopher_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   char *gopherpath;
   char *path = data->state.up.path;
@@ -123,14 +170,17 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
     sel_org = sel;
   }
 
-  /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is
-     sent, which could be sizeable with long selectors. */
   k = curlx_uztosz(len);
 
   for(;;) {
-    result = Curl_write(conn, sockfd, sel, k, &amount);
+    /* Break out of the loop if the selector is empty because OpenSSL and/or
+       LibreSSL fail with errno 0 if this is the case. */
+    if(strlen(sel) < 1)
+      break;
+
+    result = Curl_write(data, sockfd, sel, k, &amount);
     if(!result) { /* Which may not have written it all! */
-      result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
       if(result)
         break;
 
@@ -142,7 +192,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
     else
       break;
 
-    timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
+    timeout_ms = Curl_timeleft(data, NULL, FALSE);
     if(timeout_ms < 0) {
       result = CURLE_OPERATION_TIMEDOUT;
       break;
@@ -170,14 +220,12 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
   free(sel_org);
 
   if(!result)
-    /* We can use Curl_sendf to send the terminal \r\n relatively safely and
-       save allocing another string/doing another _write loop. */
-    result = Curl_sendf(sockfd, conn, "\r\n");
+    result = Curl_write(data, sockfd, "\r\n", 2, &amount);
   if(result) {
     failf(data, "Failed sending Gopher request");
     return result;
   }
-  result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
+  result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
   if(result)
     return result;
 
index dec2557..6b8bd55 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -24,6 +24,9 @@
 
 #ifndef CURL_DISABLE_GOPHER
 extern const struct Curl_handler Curl_handler_gopher;
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_gophers;
+#endif
 #endif
 
 #endif /* HEADER_CURL_GOPHER_H */
index 421d68f..5d433ad 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -34,8 +34,8 @@
 static void
 hash_element_dtor(void *user, void *element)
 {
-  struct curl_hash *h = (struct curl_hash *) user;
-  struct curl_hash_element *e = (struct curl_hash_element *) element;
+  struct Curl_hash *h = (struct Curl_hash *) user;
+  struct Curl_hash_element *e = (struct Curl_hash_element *) element;
 
   if(e->ptr) {
     h->dtor(e->ptr);
@@ -54,11 +54,11 @@ hash_element_dtor(void *user, void *element)
  * @unittest: 1603
  */
 int
-Curl_hash_init(struct curl_hash *h,
+Curl_hash_init(struct Curl_hash *h,
                int slots,
                hash_function hfunc,
                comp_function comparator,
-               curl_hash_dtor dtor)
+               Curl_hash_dtor dtor)
 {
   if(!slots || !hfunc || !comparator ||!dtor) {
     return 1; /* failure */
@@ -70,22 +70,22 @@ Curl_hash_init(struct curl_hash *h,
   h->size = 0;
   h->slots = slots;
 
-  h->table = malloc(slots * sizeof(struct curl_llist));
+  h->table = malloc(slots * sizeof(struct Curl_llist));
   if(h->table) {
     int i;
     for(i = 0; i < slots; ++i)
-      Curl_llist_init(&h->table[i], (curl_llist_dtor) hash_element_dtor);
+      Curl_llist_init(&h->table[i], (Curl_llist_dtor) hash_element_dtor);
     return 0; /* fine */
   }
   h->slots = 0;
   return 1; /* failure */
 }
 
-static struct curl_hash_element *
+static struct Curl_hash_element *
 mk_hash_element(const void *key, size_t key_len, const void *p)
 {
   /* allocate the struct plus memory after it to store the key */
-  struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element) +
+  struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
                                         key_len);
   if(he) {
     /* copy the key */
@@ -106,14 +106,14 @@ mk_hash_element(const void *key, size_t key_len, const void *p)
  * @unittest: 1603
  */
 void *
-Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
+Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
 {
-  struct curl_hash_element  *he;
-  struct curl_llist_element *le;
-  struct curl_llist *l = FETCH_LIST(h, key, key_len);
+  struct Curl_hash_element  *he;
+  struct Curl_llist_element *le;
+  struct Curl_llist *l = FETCH_LIST(h, key, key_len);
 
   for(le = l->head; le; le = le->next) {
-    he = (struct curl_hash_element *) le->ptr;
+    he = (struct Curl_hash_element *) le->ptr;
     if(h->comp_func(he->key, he->key_len, key, key_len)) {
       Curl_llist_remove(l, le, (void *)h);
       --h->size;
@@ -136,13 +136,13 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
  *
  * @unittest: 1603
  */
-int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
+int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
 {
-  struct curl_llist_element *le;
-  struct curl_llist *l = FETCH_LIST(h, key, key_len);
+  struct Curl_llist_element *le;
+  struct Curl_llist *l = FETCH_LIST(h, key, key_len);
 
   for(le = l->head; le; le = le->next) {
-    struct curl_hash_element *he = le->ptr;
+    struct Curl_hash_element *he = le->ptr;
     if(h->comp_func(he->key, he->key_len, key, key_len)) {
       Curl_llist_remove(l, le, (void *) h);
       --h->size;
@@ -157,15 +157,15 @@ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
  * @unittest: 1603
  */
 void *
-Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
+Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
 {
-  struct curl_llist_element *le;
-  struct curl_llist *l;
+  struct Curl_llist_element *le;
+  struct Curl_llist *l;
 
   if(h) {
     l = FETCH_LIST(h, key, key_len);
     for(le = l->head; le; le = le->next) {
-      struct curl_hash_element *he = le->ptr;
+      struct Curl_hash_element *he = le->ptr;
       if(h->comp_func(he->key, he->key_len, key, key_len)) {
         return he->ptr;
       }
@@ -175,19 +175,19 @@ Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
   return NULL;
 }
 
-#if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST)
+#if defined(DEBUGBUILD) && defined(AGGRESSIVE_TEST)
 void
-Curl_hash_apply(curl_hash *h, void *user,
+Curl_hash_apply(Curl_hash *h, void *user,
                 void (*cb)(void *user, void *ptr))
 {
-  struct curl_llist_element  *le;
+  struct Curl_llist_element  *le;
   int                  i;
 
   for(i = 0; i < h->slots; ++i) {
     for(le = (h->table[i])->head;
         le;
         le = le->next) {
-      curl_hash_element *el = le->ptr;
+      Curl_hash_element *el = le->ptr;
       cb(user, el->ptr);
     }
   }
@@ -202,7 +202,7 @@ Curl_hash_apply(curl_hash *h, void *user,
  * @unittest: 1603
  */
 void
-Curl_hash_destroy(struct curl_hash *h)
+Curl_hash_destroy(struct Curl_hash *h)
 {
   int i;
 
@@ -220,19 +220,19 @@ Curl_hash_destroy(struct curl_hash *h)
  * @unittest: 1602
  */
 void
-Curl_hash_clean(struct curl_hash *h)
+Curl_hash_clean(struct Curl_hash *h)
 {
   Curl_hash_clean_with_criterium(h, NULL, NULL);
 }
 
 /* Cleans all entries that pass the comp function criteria. */
 void
-Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
                                int (*comp)(void *, void *))
 {
-  struct curl_llist_element *le;
-  struct curl_llist_element *lnext;
-  struct curl_llist *list;
+  struct Curl_llist_element *le;
+  struct Curl_llist_element *lnext;
+  struct Curl_llist *list;
   int i;
 
   if(!h)
@@ -242,7 +242,7 @@ Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
     list = &h->table[i];
     le = list->head; /* get first list entry */
     while(le) {
-      struct curl_hash_element *he = le->ptr;
+      struct Curl_hash_element *he = le->ptr;
       lnext = le->next;
       /* ask the callback function if we shall remove this entry or not */
       if(comp == NULL || comp(user, he->ptr)) {
@@ -277,18 +277,18 @@ size_t Curl_str_key_compare(void *k1, size_t key1_len,
   return 0;
 }
 
-void Curl_hash_start_iterate(struct curl_hash *hash,
-                             struct curl_hash_iterator *iter)
+void Curl_hash_start_iterate(struct Curl_hash *hash,
+                             struct Curl_hash_iterator *iter)
 {
   iter->hash = hash;
   iter->slot_index = 0;
   iter->current_element = NULL;
 }
 
-struct curl_hash_element *
-Curl_hash_next_element(struct curl_hash_iterator *iter)
+struct Curl_hash_element *
+Curl_hash_next_element(struct Curl_hash_iterator *iter)
 {
-  struct curl_hash *h = iter->hash;
+  struct Curl_hash *h = iter->hash;
 
   /* Get the next element in the current list, if any */
   if(iter->current_element)
@@ -307,7 +307,7 @@ Curl_hash_next_element(struct curl_hash_iterator *iter)
   }
 
   if(iter->current_element) {
-    struct curl_hash_element *he = iter->current_element->ptr;
+    struct Curl_hash_element *he = iter->current_element->ptr;
     return he;
   }
   iter->current_element = NULL;
@@ -315,11 +315,11 @@ Curl_hash_next_element(struct curl_hash_iterator *iter)
 }
 
 #if 0 /* useful function for debugging hashes and their contents */
-void Curl_hash_print(struct curl_hash *h,
+void Curl_hash_print(struct Curl_hash *h,
                      void (*func)(void *))
 {
-  struct curl_hash_iterator iter;
-  struct curl_hash_element *he;
+  struct Curl_hash_iterator iter;
+  struct Curl_hash_element *he;
   int last_index = -1;
 
   if(!h)
index 558d0f4..b7f828e 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -41,59 +41,59 @@ typedef size_t (*comp_function) (void *key1,
                                  void *key2,
                                  size_t key2_len);
 
-typedef void (*curl_hash_dtor)(void *);
+typedef void (*Curl_hash_dtor)(void *);
 
-struct curl_hash {
-  struct curl_llist *table;
+struct Curl_hash {
+  struct Curl_llist *table;
 
   /* Hash function to be used for this hash table */
   hash_function hash_func;
 
   /* Comparator function to compare keys */
   comp_function comp_func;
-  curl_hash_dtor   dtor;
+  Curl_hash_dtor   dtor;
   int slots;
   size_t size;
 };
 
-struct curl_hash_element {
-  struct curl_llist_element list;
+struct Curl_hash_element {
+  struct Curl_llist_element list;
   void   *ptr;
   size_t key_len;
   char   key[1]; /* allocated memory following the struct */
 };
 
-struct curl_hash_iterator {
-  struct curl_hash *hash;
+struct Curl_hash_iterator {
+  struct Curl_hash *hash;
   int slot_index;
-  struct curl_llist_element *current_element;
+  struct Curl_llist_element *current_element;
 };
 
-int Curl_hash_init(struct curl_hash *h,
+int Curl_hash_init(struct Curl_hash *h,
                    int slots,
                    hash_function hfunc,
                    comp_function comparator,
-                   curl_hash_dtor dtor);
+                   Curl_hash_dtor dtor);
 
-void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p);
-int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len);
-void *Curl_hash_pick(struct curl_hash *, void *key, size_t key_len);
-void Curl_hash_apply(struct curl_hash *h, void *user,
+void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
+int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
+void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
+void Curl_hash_apply(struct Curl_hash *h, void *user,
                      void (*cb)(void *user, void *ptr));
 #define Curl_hash_count(h) ((h)->size)
-void Curl_hash_destroy(struct curl_hash *h);
-void Curl_hash_clean(struct curl_hash *h);
-void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+void Curl_hash_destroy(struct Curl_hash *h);
+void Curl_hash_clean(struct Curl_hash *h);
+void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
                                     int (*comp)(void *, void *));
 size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num);
 size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2,
                             size_t key2_len);
-void Curl_hash_start_iterate(struct curl_hash *hash,
-                             struct curl_hash_iterator *iter);
-struct curl_hash_element *
-Curl_hash_next_element(struct curl_hash_iterator *iter);
+void Curl_hash_start_iterate(struct Curl_hash *hash,
+                             struct Curl_hash_iterator *iter);
+struct Curl_hash_element *
+Curl_hash_next_element(struct Curl_hash_iterator *iter);
 
-void Curl_hash_print(struct curl_hash *h,
+void Curl_hash_print(struct Curl_hash *h,
                      void (*func)(void *));
 
 
index e4fea8a..590abe6 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index ed9190f..b25de1d 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
  *
  * The storage operation locks and unlocks the DNS cache.
  */
-CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
                                 int status,
                                 struct Curl_addrinfo *ai)
 {
   struct Curl_dns_entry *dns = NULL;
   CURLcode result = CURLE_OK;
 
-  conn->async.status = status;
+  data->state.async.status = status;
 
   if(CURL_ASYNC_SUCCESS == status) {
     if(ai) {
-      struct Curl_easy *data = conn->data;
-
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
       dns = Curl_cache_addr(data, ai,
-                            conn->async.hostname,
-                            conn->async.port);
+                            data->state.async.hostname,
+                            data->state.async.port);
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
 
@@ -99,12 +97,12 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
     }
   }
 
-  conn->async.dns = dns;
+  data->state.async.dns = dns;
 
  /* Set async.done TRUE last in this function since it may be used multi-
     threaded and once this is TRUE the other thread may read fields from the
     async struct */
-  conn->async.done = TRUE;
+  data->state.async.done = TRUE;
 
   /* IPv4: The input hostent struct will be freed by ares when we return from
      this function */
@@ -117,12 +115,12 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
  * name resolve layers (selected at build-time). They all take this same set
  * of arguments
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp)
 {
-  return Curl_resolver_getaddrinfo(conn, hostname, port, waitp);
+  return Curl_resolver_getaddrinfo(data, hostname, port, waitp);
 }
 
 #endif /* CURLRES_ASYNCH */
index 9e0db05..0fef98b 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 9c18085..52155f4 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index dd5916e..8ba3fe8 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -206,7 +206,7 @@ hostcache_timestamp_remove(void *datap, void *hc)
  * Prune the DNS cache. This assumes that a lock has already been taken.
  */
 static void
-hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now)
+hostcache_prune(struct Curl_hash *hostcache, long cache_timeout, time_t now)
 {
   struct hostcache_prune_data user;
 
@@ -253,14 +253,12 @@ sigjmp_buf curl_jmpenv;
 #endif
 
 /* lookup address, returns entry if found and not stale */
-static struct Curl_dns_entry *
-fetch_addr(struct connectdata *conn,
-                const char *hostname,
-                int port)
+static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
+                                         const char *hostname,
+                                         int port)
 {
   struct Curl_dns_entry *dns = NULL;
   size_t entry_len;
-  struct Curl_easy *data = conn->data;
   char entry_id[MAX_HOSTCACHE_LEN];
 
   /* Create an entry id, based upon the hostname and port */
@@ -311,17 +309,16 @@ fetch_addr(struct connectdata *conn,
  * use, or we'll leak memory!
  */
 struct Curl_dns_entry *
-Curl_fetch_addr(struct connectdata *conn,
+Curl_fetch_addr(struct Curl_easy *data,
                 const char *hostname,
                 int port)
 {
-  struct Curl_easy *data = conn->data;
   struct Curl_dns_entry *dns = NULL;
 
   if(data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-  dns = fetch_addr(conn, hostname, port);
+  dns = fetch_addr(data, hostname, port);
 
   if(dns)
     dns->inuse++; /* we use it! */
@@ -444,7 +441,7 @@ Curl_cache_addr(struct Curl_easy *data,
   dns->addr = addr; /* this is the address(es) */
   time(&dns->timestamp);
   if(dns->timestamp == 0)
-    dns->timestamp = 1;   /* zero indicates CURLOPT_RESOLVE entry */
+    dns->timestamp = 1;   /* zero indicates permanent CURLOPT_RESOLVE entry */
 
   /* Store the resolved data in our DNS cache. */
   dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
@@ -480,16 +477,16 @@ Curl_cache_addr(struct Curl_easy *data,
  * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
  */
 
-enum resolve_t Curl_resolv(struct connectdata *conn,
+enum resolve_t Curl_resolv(struct Curl_easy *data,
                            const char *hostname,
                            int port,
                            bool allowDOH,
                            struct Curl_dns_entry **entry)
 {
   struct Curl_dns_entry *dns = NULL;
-  struct Curl_easy *data = conn->data;
   CURLcode result;
   enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
+  struct connectdata *conn = data->conn;
 
   *entry = NULL;
   conn->bits.doh = FALSE; /* default is not */
@@ -497,7 +494,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
   if(data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-  dns = fetch_addr(conn, hostname, port);
+  dns = fetch_addr(data, hostname, port);
 
   if(dns) {
     infof(data, "Hostname %s was found in DNS cache\n", hostname);
@@ -523,7 +520,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
     if(data->set.resolver_start) {
       int st;
       Curl_set_in_callback(data, true);
-      st = data->set.resolver_start(data->state.resolver, NULL,
+      st = data->set.resolver_start(data->state.async.resolver, NULL,
                                     data->set.resolver_start_client);
       Curl_set_in_callback(data, false);
       if(st)
@@ -565,17 +562,17 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
     if(!addr) {
       /* Check what IP specifics the app has requested and if we can provide
        * it. If not, bail out. */
-      if(!Curl_ipvalid(conn))
+      if(!Curl_ipvalid(data, conn))
         return CURLRESOLV_ERROR;
 
       if(allowDOH && data->set.doh && !ipnum) {
-        addr = Curl_doh(conn, hostname, port, &respwait);
+        addr = Curl_doh(data, hostname, port, &respwait);
       }
       else {
         /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
            non-zero value indicating that we need to wait for the response to
            the resolve call */
-        addr = Curl_getaddrinfo(conn,
+        addr = Curl_getaddrinfo(data,
 #ifdef DEBUGBUILD
                                 (data->set.str[STRING_DEVICE]
                                  && !strcmp(data->set.str[STRING_DEVICE],
@@ -589,7 +586,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
         /* the response to our resolve call will come asynchronously at
            a later time, good or bad */
         /* First, check that we haven't received the info by now */
-        result = Curl_resolv_check(conn, &dns);
+        result = Curl_resolv_check(data, &dns);
         if(result) /* error detected */
           return CURLRESOLV_ERROR;
         if(dns)
@@ -658,7 +655,7 @@ RETSIGTYPE alarmfunc(int sig)
  * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
  */
 
-enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
+enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
                                    const char *hostname,
                                    int port,
                                    struct Curl_dns_entry **entry,
@@ -676,7 +673,6 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 #endif /* HAVE_SIGACTION */
   volatile long timeout;
   volatile unsigned int prev_alarm = 0;
-  struct Curl_easy *data = conn->data;
 #endif /* USE_ALARM_TIMEOUT */
   enum resolve_t rc;
 
@@ -695,7 +691,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 
   if(!timeout)
     /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
-    return Curl_resolv(conn, hostname, port, TRUE, entry);
+    return Curl_resolv(data, hostname, port, TRUE, entry);
 
   if(timeout < 1000) {
     /* The alarm() function only provides integer second resolution, so if
@@ -728,7 +724,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
     keep_copysig = TRUE; /* yes, we have a copy */
     sigact.sa_handler = alarmfunc;
 #ifdef SA_RESTART
-    /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+    /* HPUX doesn't have SA_RESTART but defaults to that behavior! */
     sigact.sa_flags &= ~SA_RESTART;
 #endif
     /* now set the new struct */
@@ -748,7 +744,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 #else
 #ifndef CURLRES_ASYNCH
   if(timeoutms)
-    infof(conn->data, "timeout on name lookup is not supported\n");
+    infof(data, "timeout on name lookup is not supported\n");
 #else
   (void)timeoutms; /* timeoutms not used with an async resolver */
 #endif
@@ -757,7 +753,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
   /* Perform the actual name resolution. This might be interrupted by an
    * alarm if it takes too long.
    */
-  rc = Curl_resolv(conn, hostname, port, TRUE, entry);
+  rc = Curl_resolv(data, hostname, port, TRUE, entry);
 
 #ifdef USE_ALARM_TIMEOUT
 clean_up:
@@ -784,7 +780,7 @@ clean_up:
   if(prev_alarm) {
     /* there was an alarm() set before us, now put it back */
     timediff_t elapsed_secs = Curl_timediff(Curl_now(),
-                                            conn->created) / 1000;
+                                            data->conn->created) / 1000;
 
     /* the alarm period is counted in even number of seconds */
     unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs);
@@ -843,7 +839,7 @@ static void freednsentry(void *freethis)
 /*
  * Curl_mk_dnscache() inits a new DNS cache and returns success/failure.
  */
-int Curl_mk_dnscache(struct curl_hash *hash)
+int Curl_mk_dnscache(struct Curl_hash *hash)
 {
   return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
                         freednsentry);
@@ -857,7 +853,7 @@ int Curl_mk_dnscache(struct curl_hash *hash)
  */
 
 void Curl_hostcache_clean(struct Curl_easy *data,
-                          struct curl_hash *hash)
+                          struct Curl_hash *hash)
 {
   if(data && data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
@@ -916,17 +912,24 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       char *addr_end;
       char *port_ptr;
       char *end_ptr;
+      bool permanent = TRUE;
+      char *host_begin;
       char *host_end;
       unsigned long tmp_port;
       bool error = true;
 
-      host_end = strchr(hostp->data, ':');
+      host_begin = hostp->data;
+      if(host_begin[0] == '+') {
+        host_begin++;
+        permanent = FALSE;
+      }
+      host_end = strchr(host_begin, ':');
       if(!host_end ||
-         ((host_end - hostp->data) >= (ptrdiff_t)sizeof(hostname)))
+         ((host_end - host_begin) >= (ptrdiff_t)sizeof(hostname)))
         goto err;
 
-      memcpy(hostname, hostp->data, host_end - hostp->data);
-      hostname[host_end - hostp->data] = '\0';
+      memcpy(hostname, host_begin, host_end - host_begin);
+      hostname[host_end - host_begin] = '\0';
 
       port_ptr = host_end + 1;
       tmp_port = strtoul(port_ptr, &end_ptr, 10);
@@ -1008,18 +1011,22 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-      /* See if its already in our dns cache */
+      /* See if it's already in our dns cache */
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(dns) {
         infof(data, "RESOLVE %s:%d is - old addresses discarded!\n",
                 hostname, port);
-        /* delete old entry entry, there are two reasons for this
+        /* 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,
             but if it is close to expire, then by the time next http
             request is made, it can get expired and pruned because old
-            entry is not necessarily marked as added by CURLOPT_RESOLVE. */
+            entry is not necessarily marked as permanent.
+         3. when adding a non-permanent entry, we want it to remove and
+            replace an existing permanent entry.
+         4. when adding a non-permanent entry, we want it to get a "fresh"
+            timeout that starts _now_. */
 
         Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
       }
@@ -1027,10 +1034,11 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       /* put this new host in the cache */
       dns = Curl_cache_addr(data, head, hostname, port);
       if(dns) {
-        dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
+        if(permanent)
+          dns->timestamp = 0; /* mark as permanent */
         /* release the returned reference; the cache itself will keep the
          * entry alive: */
-            dns->inuse--;
+        dns->inuse--;
       }
 
       if(data->share)
@@ -1040,8 +1048,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         Curl_freeaddrinfo(head);
         return CURLE_OUT_OF_MEMORY;
       }
-      infof(data, "Added %s:%d:%s to DNS cache\n",
-            hostname, port, addresses);
+      infof(data, "Added %s:%d:%s to DNS cache%s\n",
+            hostname, port, addresses, permanent ? "" : " (non-permanent)");
 
       /* Wildcard hostname */
       if(hostname[0] == '*' && hostname[1] == '\0') {
@@ -1056,29 +1064,29 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
   return CURLE_OK;
 }
 
-CURLcode Curl_resolv_check(struct connectdata *conn,
+CURLcode Curl_resolv_check(struct Curl_easy *data,
                            struct Curl_dns_entry **dns)
 {
 #if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
   (void)dns;
 #endif
 
-  if(conn->bits.doh)
-    return Curl_doh_is_resolved(conn, dns);
-  return Curl_resolver_is_resolved(conn, dns);
+  if(data->conn->bits.doh)
+    return Curl_doh_is_resolved(data, dns);
+  return Curl_resolver_is_resolved(data, dns);
 }
 
-int Curl_resolv_getsock(struct connectdata *conn,
+int Curl_resolv_getsock(struct Curl_easy *data,
                         curl_socket_t *socks)
 {
 #ifdef CURLRES_ASYNCH
-  if(conn->bits.doh)
+  if(data->conn->bits.doh)
     /* nothing to wait for during DOH resolve, those handles have their own
        sockets */
     return GETSOCK_BLANK;
-  return Curl_resolver_getsock(conn, socks);
+  return Curl_resolver_getsock(data, socks);
 #else
-  (void)conn;
+  (void)data;
   (void)socks;
   return GETSOCK_BLANK;
 #endif
@@ -1089,21 +1097,19 @@ int Curl_resolv_getsock(struct connectdata *conn,
 
    Note: this function disconnects and frees the conn data in case of
    resolve failure */
-CURLcode Curl_once_resolved(struct connectdata *conn,
-                            bool *protocol_done)
+CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
 
-  if(conn->async.dns) {
-    conn->dns_entry = conn->async.dns;
-    conn->async.dns = NULL;
+  if(data->state.async.dns) {
+    conn->dns_entry = data->state.async.dns;
+    data->state.async.dns = NULL;
   }
 
-  result = Curl_setup_conn(conn, protocol_done);
+  result = Curl_setup_conn(data, protocol_done);
 
   if(result) {
-    struct Curl_easy *data = conn->data;
-    DEBUGASSERT(data);
     Curl_detach_connnection(data);
     Curl_conncache_remove_conn(data, conn, TRUE);
     Curl_disconnect(data, conn, TRUE);
index 374b06c..c495c21 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -59,13 +59,13 @@ struct connectdata;
  * Global DNS cache is general badness. Do not use. This will be removed in
  * a future version. Use the share interface instead!
  *
- * Returns a struct curl_hash pointer on success, NULL on failure.
+ * Returns a struct Curl_hash pointer on success, NULL on failure.
  */
-struct curl_hash *Curl_global_host_cache_init(void);
+struct Curl_hash *Curl_global_host_cache_init(void);
 
 struct Curl_dns_entry {
   struct Curl_addrinfo *addr;
-  /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */
+  /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
   time_t timestamp;
   /* use-counter, use Curl_resolv_unlock to release reference */
   long inuse;
@@ -85,12 +85,12 @@ enum resolve_t {
   CURLRESOLV_RESOLVED =  0,
   CURLRESOLV_PENDING  =  1
 };
-enum resolve_t Curl_resolv(struct connectdata *conn,
+enum resolve_t Curl_resolv(struct Curl_easy *data,
                            const char *hostname,
                            int port,
                            bool allowDOH,
                            struct Curl_dns_entry **dnsentry);
-enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
+enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
                                    const char *hostname, int port,
                                    struct Curl_dns_entry **dnsentry,
                                    timediff_t timeoutms);
@@ -99,7 +99,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 /*
  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
  */
-bool Curl_ipv6works(struct connectdata *conn);
+bool Curl_ipv6works(struct Curl_easy *data);
 #else
 #define Curl_ipv6works(x) FALSE
 #endif
@@ -108,7 +108,7 @@ bool Curl_ipv6works(struct connectdata *conn);
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
  */
-bool Curl_ipvalid(struct connectdata *conn);
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn);
 
 
 /*
@@ -117,7 +117,7 @@ bool Curl_ipvalid(struct connectdata *conn);
  * name resolve layers (selected at build-time). They all take this same set
  * of arguments
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp);
@@ -128,7 +128,7 @@ void Curl_resolv_unlock(struct Curl_easy *data,
                         struct Curl_dns_entry *dns);
 
 /* init a new dns cache and return success */
-int Curl_mk_dnscache(struct curl_hash *hash);
+int Curl_mk_dnscache(struct Curl_hash *hash);
 
 /* prune old entries from the DNS cache */
 void Curl_hostcache_prune(struct Curl_easy *data);
@@ -148,7 +148,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
 /* IPv4 threadsafe resolve function used for synch and asynch builds */
 struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
 
-CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
+CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_connect);
 
 /*
  * Curl_addrinfo_callback() is used when we build with any asynch specialty.
@@ -156,7 +156,7 @@ CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
  * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async
  * request completed whether successful or failed.
  */
-CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
                                 int status,
                                 struct Curl_addrinfo *ai);
 
@@ -177,7 +177,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ip,
  * use, or we'll leak memory!
  */
 struct Curl_dns_entry *
-Curl_fetch_addr(struct connectdata *conn,
+Curl_fetch_addr(struct Curl_easy *data,
                 const char *hostname,
                 int port);
 
@@ -234,16 +234,15 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
 /*
  * Clean off entries from the cache
  */
-void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash);
+void Curl_hostcache_clean(struct Curl_easy *data, struct Curl_hash *hash);
 
 /*
  * Populate the cache with specified entries from CURLOPT_RESOLVE.
  */
 CURLcode Curl_loadhostpairs(struct Curl_easy *data);
-
-CURLcode Curl_resolv_check(struct connectdata *conn,
+CURLcode Curl_resolv_check(struct Curl_easy *data,
                            struct Curl_dns_entry **dns);
-int Curl_resolv_getsock(struct connectdata *conn,
+int Curl_resolv_getsock(struct Curl_easy *data,
                         curl_socket_t *socks);
 
 #endif /* HEADER_CURL_HOSTIP_H */
index eae9416..d0754af 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -61,8 +61,9 @@
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
  */
-bool Curl_ipvalid(struct connectdata *conn)
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
 {
+  (void)data;
   if(conn->ip_version == CURL_IPRESOLVE_V6)
     /* An IPv6 address was requested and we can't get/use one */
     return FALSE;
@@ -88,7 +89,7 @@ bool Curl_ipvalid(struct connectdata *conn)
  * flavours have thread-safe versions of the plain gethostbyname() etc.
  *
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp)
@@ -96,14 +97,14 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   struct Curl_addrinfo *ai = NULL;
 
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
-  (void)conn;
+  (void)data;
 #endif
 
   *waitp = 0; /* synchronous response only */
 
   ai = Curl_ipv4_resolve_r(hostname, port);
   if(!ai)
-    infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
+    infof(data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
 
   return ai;
 }
index 1121575..53b3c67 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 /*
  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
  */
-bool Curl_ipv6works(struct connectdata *conn)
+bool Curl_ipv6works(struct Curl_easy *data)
 {
-  if(conn) {
+  if(data) {
     /* the nature of most system is that IPv6 status doesn't come and go
        during a program's lifetime so we only probe the first time and then we
        have the info kept for fast re-use */
-    DEBUGASSERT(conn);
-    DEBUGASSERT(conn->data);
-    DEBUGASSERT(conn->data->multi);
-    return conn->data->multi->ipv6_works;
+    DEBUGASSERT(data);
+    DEBUGASSERT(data->multi);
+    return data->multi->ipv6_works;
   }
   else {
     int ipv6_works = -1;
@@ -82,7 +81,7 @@ bool Curl_ipv6works(struct connectdata *conn)
       ipv6_works = 0;
     else {
       ipv6_works = 1;
-      Curl_closesocket(NULL, s);
+      sclose(s);
     }
     return (ipv6_works>0)?TRUE:FALSE;
   }
@@ -92,10 +91,10 @@ bool Curl_ipv6works(struct connectdata *conn)
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
  */
-bool Curl_ipvalid(struct connectdata *conn)
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
 {
   if(conn->ip_version == CURL_IPRESOLVE_V6)
-    return Curl_ipv6works(conn);
+    return Curl_ipv6works(data);
 
   return TRUE;
 }
@@ -128,7 +127,7 @@ static void dump_addrinfo(struct connectdata *conn,
  * memory we need to free after use. That memory *MUST* be freed with
  * Curl_freeaddrinfo(), nothing else.
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp)
@@ -142,14 +141,11 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   char addrbuf[128];
 #endif
   int pf;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  struct Curl_easy *data = conn->data;
-#endif
 
   *waitp = 0; /* synchronous response only */
 
   /* Check if a limited name resolve has been requested */
-  switch(conn->ip_version) {
+  switch(data->set.ipver) {
   case CURL_IPRESOLVE_V4:
     pf = PF_INET;
     break;
@@ -161,13 +157,13 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
     break;
   }
 
-  if((pf != PF_INET) && !Curl_ipv6works(conn))
+  if((pf != PF_INET) && !Curl_ipv6works(data))
     /* The stack seems to be a non-IPv6 one */
     pf = PF_INET;
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (conn->transport == TRNSPRT_TCP) ?
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
     SOCK_STREAM : SOCK_DGRAM;
 
 #ifndef USE_RESOLVE_ON_IPS
index 9e31008..550b43a 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
diff --git a/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c
new file mode 100644 (file)
index 0000000..0e7c19c
--- /dev/null
@@ -0,0 +1,522 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2020 - 2021, 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.
+ *
+ ***************************************************************************/
+/*
+ * The Strict-Transport-Security header is defined in RFC 6797:
+ * https://tools.ietf.org/html/rfc6797
+ */
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HSTS)
+#include <curl/curl.h>
+#include "urldata.h"
+#include "llist.h"
+#include "hsts.h"
+#include "curl_get_line.h"
+#include "strcase.h"
+#include "sendf.h"
+#include "strtoofft.h"
+#include "parsedate.h"
+#include "rand.h"
+#include "rename.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define MAX_HSTS_LINE 4095
+#define MAX_HSTS_HOSTLEN 256
+#define MAX_HSTS_HOSTLENSTR "256"
+#define MAX_HSTS_SUBLEN 4
+#define MAX_HSTS_SUBLENSTR "4"
+#define MAX_HSTS_DATELEN 64
+#define MAX_HSTS_DATELENSTR "64"
+
+#ifdef DEBUGBUILD
+/* to play well with debug builds, we can *set* a fixed time this will
+   return */
+time_t deltatime; /* allow for "adjustments" for unit test purposes */
+static time_t debugtime(void *unused)
+{
+  char *timestr = getenv("CURL_TIME");
+  (void)unused;
+  if(timestr) {
+    unsigned long val = strtol(timestr, NULL, 10) + deltatime;
+    return (time_t)val;
+  }
+  return time(NULL);
+}
+#define time(x) debugtime(x)
+#endif
+
+struct hsts *Curl_hsts_init(void)
+{
+  struct hsts *h = calloc(sizeof(struct hsts), 1);
+  if(h) {
+    Curl_llist_init(&h->list, NULL);
+  }
+  return h;
+}
+
+static void hsts_free(struct stsentry *e)
+{
+  free((char *)e->host);
+  free(e);
+}
+
+void Curl_hsts_cleanup(struct hsts **hp)
+{
+  struct hsts *h = *hp;
+  if(h) {
+    struct Curl_llist_element *e;
+    struct Curl_llist_element *n;
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      n = e->next;
+      hsts_free(sts);
+    }
+    free(h->filename);
+    free(h);
+    *hp = NULL;
+  }
+}
+
+static struct stsentry *hsts_entry(void)
+{
+  return calloc(sizeof(struct stsentry), 1);
+}
+
+static CURLcode hsts_create(struct hsts *h,
+                            const char *hostname,
+                            bool subdomains,
+                            curl_off_t expires)
+{
+  struct stsentry *sts = hsts_entry();
+  if(!sts)
+    return CURLE_OUT_OF_MEMORY;
+
+  sts->expires = expires;
+  sts->includeSubDomains = subdomains;
+  sts->host = strdup(hostname);
+  if(!sts->host) {
+    free(sts);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node);
+  return CURLE_OK;
+}
+
+CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
+                         const char *header)
+{
+  const char *p = header;
+  curl_off_t expires = 0;
+  bool gotma = FALSE;
+  bool gotinc = FALSE;
+  bool subdomains = FALSE;
+  struct stsentry *sts;
+  time_t now = time(NULL);
+
+  do {
+    while(*p && ISSPACE(*p))
+      p++;
+    if(Curl_strncasecompare("max-age=", p, 8)) {
+      bool quoted = FALSE;
+      CURLofft offt;
+      char *endp;
+
+      if(gotma)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+
+      p += 8;
+      while(*p && ISSPACE(*p))
+        p++;
+      if(*p == '\"') {
+        p++;
+        quoted = TRUE;
+      }
+      offt = curlx_strtoofft(p, &endp, 10, &expires);
+      if(offt == CURL_OFFT_FLOW)
+        expires = CURL_OFF_T_MAX;
+      else if(offt)
+        /* invalid max-age */
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      p = endp;
+      if(quoted) {
+        if(*p != '\"')
+          return CURLE_BAD_FUNCTION_ARGUMENT;
+        p++;
+      }
+      gotma = TRUE;
+    }
+    else if(Curl_strncasecompare("includesubdomains", p, 17)) {
+      if(gotinc)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+      subdomains = TRUE;
+      p += 17;
+      gotinc = TRUE;
+    }
+    else {
+      /* unknown directive, do a lame attempt to skip */
+      while(*p && (*p != ';'))
+        p++;
+    }
+
+    while(*p && ISSPACE(*p))
+      p++;
+    if(*p == ';')
+      p++;
+  } while (*p);
+
+  if(!gotma)
+    /* max-age is mandatory */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(!expires) {
+    /* remove the entry if present verbatim (without subdomain match) */
+    sts = Curl_hsts(h, hostname, FALSE);
+    if(sts) {
+      Curl_llist_remove(&h->list, &sts->node, NULL);
+      hsts_free(sts);
+    }
+    return CURLE_OK;
+  }
+
+  if(CURL_OFF_T_MAX - now < expires)
+    /* would overflow, use maximum value */
+    expires = CURL_OFF_T_MAX;
+  else
+    expires += now;
+
+  /* check if it already exists */
+  sts = Curl_hsts(h, hostname, FALSE);
+  if(sts) {
+    /* just update these fields */
+    sts->expires = expires;
+    sts->includeSubDomains = subdomains;
+  }
+  else
+    return hsts_create(h, hostname, subdomains, expires);
+
+  return CURLE_OK;
+}
+
+/*
+ * Return TRUE if the given host name is currently an HSTS one.
+ *
+ * The 'subdomain' argument tells the function if subdomain matching should be
+ * attempted.
+ */
+struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+                           bool subdomain)
+{
+  if(h) {
+    time_t now = time(NULL);
+    size_t hlen = strlen(hostname);
+    struct Curl_llist_element *e;
+    struct Curl_llist_element *n;
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      n = e->next;
+      if(sts->expires <= now) {
+        /* remove expired entries */
+        Curl_llist_remove(&h->list, &sts->node, NULL);
+        hsts_free(sts);
+        continue;
+      }
+      if(subdomain && sts->includeSubDomains) {
+        size_t ntail = strlen(sts->host);
+        if(ntail < hlen) {
+          size_t offs = hlen - ntail;
+          if((hostname[offs-1] == '.') &&
+             Curl_strncasecompare(&hostname[offs], sts->host, ntail))
+            return sts;
+        }
+      }
+      if(Curl_strcasecompare(hostname, sts->host))
+        return sts;
+    }
+  }
+  return NULL; /* no match */
+}
+
+/*
+ * Send this HSTS entry to the write callback.
+ */
+static CURLcode hsts_push(struct Curl_easy *data,
+                          struct curl_index *i,
+                          struct stsentry *sts,
+                          bool *stop)
+{
+  struct curl_hstsentry e;
+  CURLSTScode sc;
+  struct tm stamp;
+  CURLcode result;
+
+  e.name = (char *)sts->host;
+  e.namelen = strlen(sts->host);
+  e.includeSubDomains = sts->includeSubDomains;
+
+  result = Curl_gmtime(sts->expires, &stamp);
+  if(result)
+    return result;
+
+  msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d",
+            stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+            stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+
+  sc = data->set.hsts_write(data, &e, i,
+                            data->set.hsts_write_userp);
+  *stop = (sc != CURLSTS_OK);
+  return sc == CURLSTS_FAIL ? CURLE_BAD_FUNCTION_ARGUMENT : CURLE_OK;
+}
+
+/*
+ * Write this single hsts entry to a single output line
+ */
+static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
+{
+  struct tm stamp;
+  CURLcode result = Curl_gmtime(sts->expires, &stamp);
+  if(result)
+    return result;
+
+  fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n",
+          sts->includeSubDomains ? ".": "", sts->host,
+          stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+          stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+  return CURLE_OK;
+}
+
+
+/*
+ * Curl_https_save() writes the HSTS cache to file and callback.
+ */
+CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
+                        const char *file)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+  CURLcode result = CURLE_OK;
+  FILE *out;
+  char *tempstore;
+  unsigned char randsuffix[9];
+
+  if(!h)
+    /* no cache activated */
+    return CURLE_OK;
+
+  /* if no new name is given, use the one we stored from the load */
+  if(!file && h->filename)
+    file = h->filename;
+
+  if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0])
+    /* marked as read-only, no file or zero length file name */
+    goto skipsave;
+
+  if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix)))
+    return CURLE_FAILED_INIT;
+
+  tempstore = aprintf("%s.%s.tmp", file, randsuffix);
+  if(!tempstore)
+    return CURLE_OUT_OF_MEMORY;
+
+  out = fopen(tempstore, FOPEN_WRITETEXT);
+  if(!out)
+    result = CURLE_WRITE_ERROR;
+  else {
+    fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n"
+          "# This file was generated by libcurl! Edit at your own risk.\n",
+          out);
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      n = e->next;
+      result = hsts_out(sts, out);
+      if(result)
+        break;
+    }
+    fclose(out);
+    if(!result && Curl_rename(tempstore, file))
+      result = CURLE_WRITE_ERROR;
+
+    if(result)
+      unlink(tempstore);
+  }
+  free(tempstore);
+  skipsave:
+  if(data->set.hsts_write) {
+    /* if there's a write callback */
+    struct curl_index i; /* count */
+    i.total = h->list.size;
+    i.index = 0;
+    for(e = h->list.head; e; e = n) {
+      struct stsentry *sts = e->ptr;
+      bool stop;
+      n = e->next;
+      result = hsts_push(data, &i, sts, &stop);
+      if(result || stop)
+        break;
+      i.index++;
+    }
+  }
+  return result;
+}
+
+/* only returns SERIOUS errors */
+static CURLcode hsts_add(struct hsts *h, char *line)
+{
+  /* Example lines:
+     example.com "20191231 10:00:00"
+     .example.net "20191231 10:00:00"
+   */
+  char host[MAX_HSTS_HOSTLEN + 1];
+  char date[MAX_HSTS_DATELEN + 1];
+  int rc;
+
+  rc = sscanf(line,
+              "%" MAX_HSTS_HOSTLENSTR "s \"%" MAX_HSTS_DATELENSTR "[^\"]\"",
+              host, date);
+  if(2 == rc) {
+    time_t expires = Curl_getdate_capped(date);
+    CURLcode result;
+    char *p = host;
+    bool subdomain = FALSE;
+    if(p[0] == '.') {
+      p++;
+      subdomain = TRUE;
+    }
+    result = hsts_create(h, p, subdomain, expires);
+    if(result)
+      return result;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Load HSTS data from callback.
+ *
+ */
+static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
+{
+  /* if the HSTS read callback is set, use it */
+  if(data->set.hsts_read) {
+    CURLSTScode sc;
+    DEBUGASSERT(h);
+    do {
+      char buffer[257];
+      struct curl_hstsentry e;
+      e.name = buffer;
+      e.namelen = sizeof(buffer)-1;
+      e.includeSubDomains = FALSE; /* default */
+      e.expire[0] = 0;
+      e.name[0] = 0; /* just to make it clean */
+      sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp);
+      if(sc == CURLSTS_OK) {
+        time_t expires;
+        CURLcode result;
+        if(!e.name[0])
+          /* bail out if no name was stored */
+          return CURLE_BAD_FUNCTION_ARGUMENT;
+        if(e.expire[0])
+          expires = Curl_getdate_capped(e.expire);
+        else
+          expires = TIME_T_MAX; /* the end of time */
+        result = hsts_create(h, e.name, e.includeSubDomains, expires);
+        if(result)
+          return result;
+      }
+      else if(sc == CURLSTS_FAIL)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
+    } while(sc == CURLSTS_OK);
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Load the HSTS cache from the given file. The text based line-oriented file
+ * format is documented here:
+ * https://github.com/curl/curl/wiki/HSTS
+ *
+ * This function only returns error on major problems that prevent hsts
+ * handling to work completely. It will ignore individual syntactical errors
+ * etc.
+ */
+static CURLcode hsts_load(struct hsts *h, const char *file)
+{
+  CURLcode result = CURLE_OK;
+  char *line = NULL;
+  FILE *fp;
+
+  /* we need a private copy of the file name so that the hsts cache file
+     name survives an easy handle reset */
+  free(h->filename);
+  h->filename = strdup(file);
+  if(!h->filename)
+    return CURLE_OUT_OF_MEMORY;
+
+  fp = fopen(file, FOPEN_READTEXT);
+  if(fp) {
+    line = malloc(MAX_HSTS_LINE);
+    if(!line)
+      goto fail;
+    while(Curl_get_line(line, MAX_HSTS_LINE, fp)) {
+      char *lineptr = line;
+      while(*lineptr && ISBLANK(*lineptr))
+        lineptr++;
+      if(*lineptr == '#')
+        /* skip commented lines */
+        continue;
+
+      hsts_add(h, lineptr);
+    }
+    free(line); /* free the line buffer */
+    fclose(fp);
+  }
+  return result;
+
+  fail:
+  Curl_safefree(h->filename);
+  fclose(fp);
+  return CURLE_OUT_OF_MEMORY;
+}
+
+/*
+ * Curl_hsts_loadfile() loads HSTS from file
+ */
+CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
+                            struct hsts *h, const char *file)
+{
+  DEBUGASSERT(h);
+  (void)data;
+  return hsts_load(h, file);
+}
+
+/*
+ * Curl_hsts_loadcb() loads HSTS from callback
+ */
+CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
+{
+  return hsts_pull(data, h);
+}
+
+#endif /* CURL_DISABLE_HTTP || USE_HSTS */
diff --git a/Utilities/cmcurl/lib/hsts.h b/Utilities/cmcurl/lib/hsts.h
new file mode 100644 (file)
index 0000000..ae5db74
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef HEADER_CURL_HSTS_H
+#define HEADER_CURL_HSTS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2020, 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.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HSTS)
+#include <curl/curl.h>
+#include "llist.h"
+
+#ifdef DEBUGBUILD
+extern time_t deltatime;
+#endif
+
+struct stsentry {
+  struct Curl_llist_element node;
+  const char *host;
+  bool includeSubDomains;
+  time_t expires; /* the timestamp of this entry's expiry */
+};
+
+/* The HSTS cache. Needs to be able to tailmatch host names. */
+struct hsts {
+  struct Curl_llist list;
+  char *filename;
+  unsigned int flags;
+};
+
+struct hsts *Curl_hsts_init(void);
+void Curl_hsts_cleanup(struct hsts **hp);
+CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
+                         const char *sts);
+struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
+                           bool subdomain);
+CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
+                        const char *file);
+CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
+                            struct hsts *h, const char *file);
+CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
+                          struct hsts *h);
+#else
+#define Curl_hsts_cleanup(x)
+#define Curl_hsts_loadcb(x,y)
+#define Curl_hsts_save(x,y,z)
+#endif /* CURL_DISABLE_HTTP || USE_HSTS */
+#endif /* HEADER_CURL_HSTS_H */
index 8fcdd43..6f7f55d 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include <sys/param.h>
 #endif
 
+#ifdef USE_HYPER
+#include <hyper.h>
+#endif
+
 #include "urldata.h"
 #include <curl/curl.h>
 #include "transfer.h"
@@ -60,6 +64,7 @@
 #include "http_ntlm.h"
 #include "curl_ntlm_wb.h"
 #include "http_negotiate.h"
+#include "http_aws_sigv4.h"
 #include "url.h"
 #include "share.h"
 #include "hostip.h"
@@ -77,6 +82,8 @@
 #include "connect.h"
 #include "strdup.h"
 #include "altsvc.h"
+#include "hsts.h"
+#include "c-hyper.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
  * Forward declarations.
  */
 
-static int http_getsock_do(struct connectdata *conn,
+static int http_getsock_do(struct Curl_easy *data,
+                           struct connectdata *conn,
                            curl_socket_t *socks);
-static int http_should_fail(struct connectdata *conn);
+static bool http_should_fail(struct Curl_easy *data);
 
 #ifndef CURL_DISABLE_PROXY
-static CURLcode add_haproxy_protocol_header(struct connectdata *conn);
+static CURLcode add_haproxy_protocol_header(struct Curl_easy *data);
 #endif
 
 #ifdef USE_SSL
-static CURLcode https_connecting(struct connectdata *conn, bool *done);
-static int https_getsock(struct connectdata *conn,
+static CURLcode https_connecting(struct Curl_easy *data, bool *done);
+static int https_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
                          curl_socket_t *socks);
 #else
 #define https_connecting(x,y) CURLE_COULDNT_CONNECT
 #endif
-static CURLcode http_setup_conn(struct connectdata *conn);
+static CURLcode http_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn);
 
 /*
  * HTTP handler interface.
@@ -125,6 +135,7 @@ const struct Curl_handler Curl_handler_http = {
   ZERO_NULL,                            /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
+  CURLPROTO_HTTP,                       /* family */
   PROTOPT_CREDSPERREQUEST |             /* flags */
   PROTOPT_USERPWDCTRL
 };
@@ -151,25 +162,26 @@ const struct Curl_handler Curl_handler_https = {
   ZERO_NULL,                            /* connection_check */
   PORT_HTTPS,                           /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
+  CURLPROTO_HTTP,                       /* family */
   PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN | /* flags */
   PROTOPT_USERPWDCTRL
 };
 #endif
 
-static CURLcode http_setup_conn(struct connectdata *conn)
+static CURLcode http_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn)
 {
   /* allocate the HTTP-specific struct for the Curl_easy, only to survive
      during this request */
   struct HTTP *http;
-  struct Curl_easy *data = conn->data;
-  DEBUGASSERT(data->req.protop == NULL);
+  DEBUGASSERT(data->req.p.http == NULL);
 
   http = calloc(1, sizeof(struct HTTP));
   if(!http)
     return CURLE_OUT_OF_MEMORY;
 
-  Curl_mime_initpart(&http->form, conn->data);
-  data->req.protop = http;
+  Curl_mime_initpart(&http->form, data);
+  data->req.p.http = http;
 
   if(data->set.httpversion == CURL_HTTP_VERSION_3) {
     if(conn->handler->flags & PROTOPT_SSL)
@@ -196,16 +208,16 @@ static CURLcode http_setup_conn(struct connectdata *conn)
  * if proxy headers are not available, then it will lookup into http header
  * link list
  *
- * It takes a connectdata struct as input instead of the Curl_easy simply to
- * know if this is a proxy request or not, as it then might check a different
- * header list. Provide the header prefix without colon!.
+ * It takes a connectdata struct as input to see if this is a proxy request or
+ * not, as it then might check a different header list. Provide the header
+ * prefix without colon!
  */
-char *Curl_checkProxyheaders(const struct connectdata *conn,
+char *Curl_checkProxyheaders(struct Curl_easy *data,
+                             const struct connectdata *conn,
                              const char *thisheader)
 {
   struct curl_slist *head;
   size_t thislen = strlen(thisheader);
-  struct Curl_easy *data = conn->data;
 
   for(head = (conn->bits.proxy && data->set.sep_headers) ?
         data->set.proxyheaders : data->set.headers;
@@ -219,7 +231,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn,
 }
 #else
 /* disabled */
-#define Curl_checkProxyheaders(x,y) NULL
+#define Curl_checkProxyheaders(x,y,z) NULL
 #endif
 
 /*
@@ -282,11 +294,11 @@ char *Curl_copy_header_value(const char *header)
  *
  * Returns CURLcode.
  */
-static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
+static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
 {
   size_t size = 0;
   char *authorization = NULL;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   char **userp;
   const char *user;
   const char *pwd;
@@ -342,16 +354,15 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
  *
  * Returns CURLcode.
  */
-static CURLcode http_output_bearer(struct connectdata *conn)
+static CURLcode http_output_bearer(struct Curl_easy *data)
 {
   char **userp;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
   userp = &data->state.aptr.userpwd;
   free(*userp);
   *userp = aprintf("Authorization: Bearer %s\r\n",
-                   conn->data->set.str[STRING_BEARER]);
+                   data->set.str[STRING_BEARER]);
 
   if(!*userp) {
     result = CURLE_OUT_OF_MEMORY;
@@ -390,6 +401,8 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
     pick->picked = CURLAUTH_NTLM_WB;
   else if(avail & CURLAUTH_BASIC)
     pick->picked = CURLAUTH_BASIC;
+  else if(avail & CURLAUTH_AWS_SIGV4)
+    pick->picked = CURLAUTH_AWS_SIGV4;
   else {
     pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
     picked = FALSE;
@@ -422,10 +435,10 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
  *   }
  * }
  */
-static CURLcode http_perhapsrewind(struct connectdata *conn)
+static CURLcode http_perhapsrewind(struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
-  struct Curl_easy *data = conn->data;
-  struct HTTP *http = data->req.protop;
+  struct HTTP *http = data->req.p.http;
   curl_off_t bytessent;
   curl_off_t expectsend = -1; /* default is unknown */
 
@@ -542,7 +555,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
 
   if(bytessent)
     /* we rewind now at once since if we already sent something */
-    return Curl_readrewind(conn);
+    return Curl_readrewind(data);
 
   return CURLE_OK;
 }
@@ -554,9 +567,9 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
  * picked.
  */
 
-CURLcode Curl_http_auth_act(struct connectdata *conn)
+CURLcode Curl_http_auth_act(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   bool pickhost = FALSE;
   bool pickproxy = FALSE;
   CURLcode result = CURLE_OK;
@@ -582,7 +595,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
        conn->httpversion > 11) {
       infof(data, "Forcing HTTP/1.1 for NTLM");
       connclose(conn, "Force HTTP/1.1 connection");
-      conn->data->set.httpversion = CURL_HTTP_VERSION_1_1;
+      data->set.httpversion = CURL_HTTP_VERSION_1_1;
     }
   }
 #ifndef CURL_DISABLE_PROXY
@@ -600,7 +613,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
     if((data->state.httpreq != HTTPREQ_GET) &&
        (data->state.httpreq != HTTPREQ_HEAD) &&
        !conn->bits.rewindaftersend) {
-      result = http_perhapsrewind(conn);
+      result = http_perhapsrewind(data, conn);
       if(result)
         return result;
     }
@@ -627,7 +640,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
       data->state.authhost.done = TRUE;
     }
   }
-  if(http_should_fail(conn)) {
+  if(http_should_fail(data)) {
     failf(data, "The requested URL returned error: %d",
           data->req.httpcode);
     result = CURLE_HTTP_RETURNED_ERROR;
@@ -642,7 +655,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
  * and whether or not it is to a proxy.
  */
 static CURLcode
-output_auth_headers(struct connectdata *conn,
+output_auth_headers(struct Curl_easy *data,
+                    struct connectdata *conn,
                     struct auth *authstatus,
                     const char *request,
                     const char *path,
@@ -650,17 +664,24 @@ output_auth_headers(struct connectdata *conn,
 {
   const char *auth = NULL;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
 #ifdef CURL_DISABLE_CRYPTO_AUTH
   (void)request;
   (void)path;
 #endif
-
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+  if(authstatus->picked == CURLAUTH_AWS_SIGV4) {
+    auth = "AWS_SIGV4";
+    result = Curl_output_aws_sigv4(data, proxy);
+    if(result)
+      return result;
+  }
+  else
+#endif
 #ifdef USE_SPNEGO
   if(authstatus->picked == CURLAUTH_NEGOTIATE) {
     auth = "Negotiate";
-    result = Curl_output_negotiate(conn, proxy);
+    result = Curl_output_negotiate(data, conn, proxy);
     if(result)
       return result;
   }
@@ -669,7 +690,7 @@ output_auth_headers(struct connectdata *conn,
 #ifdef USE_NTLM
   if(authstatus->picked == CURLAUTH_NTLM) {
     auth = "NTLM";
-    result = Curl_output_ntlm(conn, proxy);
+    result = Curl_output_ntlm(data, proxy);
     if(result)
       return result;
   }
@@ -678,7 +699,7 @@ output_auth_headers(struct connectdata *conn,
 #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
   if(authstatus->picked == CURLAUTH_NTLM_WB) {
     auth = "NTLM_WB";
-    result = Curl_output_ntlm_wb(conn, proxy);
+    result = Curl_output_ntlm_wb(data, conn, proxy);
     if(result)
       return result;
   }
@@ -687,7 +708,8 @@ output_auth_headers(struct connectdata *conn,
 #ifndef CURL_DISABLE_CRYPTO_AUTH
   if(authstatus->picked == CURLAUTH_DIGEST) {
     auth = "Digest";
-    result = Curl_output_digest(conn,
+    result = Curl_output_digest(data,
+                                conn,
                                 proxy,
                                 (const unsigned char *)request,
                                 (const unsigned char *)path);
@@ -701,12 +723,12 @@ output_auth_headers(struct connectdata *conn,
     if(
 #ifndef CURL_DISABLE_PROXY
       (proxy && conn->bits.proxy_user_passwd &&
-       !Curl_checkProxyheaders(conn, "Proxy-authorization")) ||
+       !Curl_checkProxyheaders(data, conn, "Proxy-authorization")) ||
 #endif
       (!proxy && conn->bits.user_passwd &&
-       !Curl_checkheaders(conn, "Authorization"))) {
+       !Curl_checkheaders(data, "Authorization"))) {
       auth = "Basic";
-      result = http_output_basic(conn, proxy);
+      result = http_output_basic(data, proxy);
       if(result)
         return result;
     }
@@ -718,9 +740,9 @@ output_auth_headers(struct connectdata *conn,
   if(authstatus->picked == CURLAUTH_BEARER) {
     /* Bearer */
     if((!proxy && data->set.str[STRING_BEARER] &&
-        !Curl_checkheaders(conn, "Authorization:"))) {
+        !Curl_checkheaders(data, "Authorization:"))) {
       auth = "Bearer";
-      result = http_output_bearer(conn);
+      result = http_output_bearer(data);
       if(result)
         return result;
     }
@@ -751,7 +773,7 @@ output_auth_headers(struct connectdata *conn,
 /**
  * Curl_http_output_auth() setups the authentication headers for the
  * host/proxy and the correct authentication
- * method. conn->data->state.authdone is set to TRUE when authentication is
+ * method. data->state.authdone is set to TRUE when authentication is
  * done.
  *
  * @param conn all information about the current connection
@@ -763,14 +785,15 @@ output_auth_headers(struct connectdata *conn,
  * @returns CURLcode
  */
 CURLcode
-Curl_http_output_auth(struct connectdata *conn,
+Curl_http_output_auth(struct Curl_easy *data,
+                      struct connectdata *conn,
                       const char *request,
+                      Curl_HttpReq httpreq,
                       const char *path,
                       bool proxytunnel) /* TRUE if this is the request setting
                                            up the proxy tunnel */
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct auth *authhost;
   struct auth *authproxy;
 
@@ -807,7 +830,7 @@ Curl_http_output_auth(struct connectdata *conn,
   /* Send proxy authentication header if needed */
   if(conn->bits.httpproxy &&
      (conn->bits.tunnel_proxy == (bit)proxytunnel)) {
-    result = output_auth_headers(conn, authproxy, request, path, TRUE);
+    result = output_auth_headers(data, conn, authproxy, request, path, TRUE);
     if(result)
       return result;
   }
@@ -826,11 +849,22 @@ Curl_http_output_auth(struct connectdata *conn,
      !data->state.first_host ||
      data->set.allow_auth_to_other_hosts ||
      strcasecompare(data->state.first_host, conn->host.name)) {
-    result = output_auth_headers(conn, authhost, request, path, FALSE);
+    result = output_auth_headers(data, conn, authhost, request, path, FALSE);
   }
   else
     authhost->done = TRUE;
 
+  if(((authhost->multipass && !authhost->done) ||
+      (authproxy->multipass && !authproxy->done)) &&
+     (httpreq != HTTPREQ_GET) &&
+     (httpreq != HTTPREQ_HEAD)) {
+    /* Auth is required and we are not authenticated yet. Make a PUT or POST
+       with content-length zero as a "probe". */
+    conn->bits.authneg = TRUE;
+  }
+  else
+    conn->bits.authneg = FALSE;
+
   return result;
 }
 
@@ -856,14 +890,13 @@ Curl_http_output_auth(struct connectdata *conn,
  * proxy CONNECT loop.
  */
 
-CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
+CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
                               const char *auth) /* the first non-space */
 {
   /*
    * This resource requires authentication
    */
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
 #ifdef USE_SPNEGO
   curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
                                     &conn->http_negotiate_state;
@@ -871,6 +904,8 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
   unsigned long *availp;
   struct auth *authp;
 
+  (void) conn; /* In case conditionals make it unused. */
+
   if(proxy) {
     availp = &data->info.proxyauthavail;
     authp = &data->state.authproxy;
@@ -905,7 +940,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
         authp->avail |= CURLAUTH_NEGOTIATE;
 
         if(authp->picked == CURLAUTH_NEGOTIATE) {
-          CURLcode result = Curl_input_negotiate(conn, proxy, auth);
+          CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
           if(!result) {
             DEBUGASSERT(!data->req.newurl);
             data->req.newurl = strdup(data->change.url);
@@ -934,7 +969,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
           if(authp->picked == CURLAUTH_NTLM ||
              authp->picked == CURLAUTH_NTLM_WB) {
             /* NTLM authentication is picked and activated */
-            CURLcode result = Curl_input_ntlm(conn, proxy, auth);
+            CURLcode result = Curl_input_ntlm(data, proxy, auth);
             if(!result) {
               data->state.authproblem = FALSE;
 #ifdef NTLM_WB_ENABLED
@@ -944,7 +979,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
                 *availp |= CURLAUTH_NTLM_WB;
                 authp->avail |= CURLAUTH_NTLM_WB;
 
-                result = Curl_input_ntlm_wb(conn, proxy, auth);
+                result = Curl_input_ntlm_wb(data, conn, proxy, auth);
                 if(result) {
                   infof(data, "Authentication problem. Ignoring this.\n");
                   data->state.authproblem = TRUE;
@@ -975,7 +1010,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
              * authentication isn't activated yet, as we need to store the
              * incoming data from this header in case we are going to use
              * Digest */
-            result = Curl_input_digest(conn, proxy, auth);
+            result = Curl_input_digest(data, proxy, auth);
             if(result) {
               infof(data, "Authentication problem. Ignoring this.\n");
               data->state.authproblem = TRUE;
@@ -1027,18 +1062,15 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
  *
  * @param conn all information about the current connection
  *
- * @retval 0 communications should continue
+ * @retval FALSE communications should continue
  *
- * @retval 1 communications should not continue
+ * @retval TRUE communications should not continue
  */
-static int http_should_fail(struct connectdata *conn)
+static bool http_should_fail(struct Curl_easy *data)
 {
-  struct Curl_easy *data;
   int httpcode;
-
-  DEBUGASSERT(conn);
-  data = conn->data;
   DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
 
   httpcode = data->req.httpcode;
 
@@ -1047,20 +1079,20 @@ static int http_should_fail(struct connectdata *conn)
   ** don't fail.
   */
   if(!data->set.http_fail_on_error)
-    return 0;
+    return FALSE;
 
   /*
   ** Any code < 400 is never terminal.
   */
   if(httpcode < 400)
-    return 0;
+    return FALSE;
 
   /*
   ** Any code >= 400 that's not 401 or 407 is always
   ** a terminal error
   */
   if((httpcode != 401) && (httpcode != 407))
-    return 1;
+    return TRUE;
 
   /*
   ** All we have left to deal with is 401 and 407
@@ -1085,16 +1117,17 @@ static int http_should_fail(struct connectdata *conn)
   ** Either we're not authenticating, or we're supposed to
   ** be authenticating something else.  This is an error.
   */
-  if((httpcode == 401) && !conn->bits.user_passwd)
+  if((httpcode == 401) && !data->conn->bits.user_passwd)
     return TRUE;
 #ifndef CURL_DISABLE_PROXY
-  if((httpcode == 407) && !conn->bits.proxy_user_passwd)
+  if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
     return TRUE;
 #endif
 
   return data->state.authproblem;
 }
 
+#ifndef USE_HYPER
 /*
  * readmoredata() is a "fread() emulation" to provide POST and/or request
  * data. It is used when a huge POST is to be made and the entire chunk wasn't
@@ -1108,8 +1141,8 @@ static size_t readmoredata(char *buffer,
                            size_t nitems,
                            void *userp)
 {
-  struct connectdata *conn = (struct connectdata *)userp;
-  struct HTTP *http = conn->data->req.protop;
+  struct Curl_easy *data = (struct Curl_easy *)userp;
+  struct HTTP *http = data->req.p.http;
   size_t fullsize = size * nitems;
 
   if(!http->postsize)
@@ -1117,7 +1150,7 @@ static size_t readmoredata(char *buffer,
     return 0;
 
   /* make sure that a HTTP request is never sent away chunked! */
-  conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
+  data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
 
   if(http->postsize <= (curl_off_t)fullsize) {
     memcpy(buffer, http->postdata, (size_t)http->postsize);
@@ -1127,8 +1160,8 @@ static size_t readmoredata(char *buffer,
       /* move backup data into focus and continue on that */
       http->postdata = http->backup.postdata;
       http->postsize = http->backup.postsize;
-      conn->data->state.fread_func = http->backup.fread_func;
-      conn->data->state.in = http->backup.fread_in;
+      data->state.fread_func = http->backup.fread_func;
+      data->state.in = http->backup.fread_in;
 
       http->sending++; /* move one step up */
 
@@ -1154,7 +1187,7 @@ static size_t readmoredata(char *buffer,
  * Returns CURLcode
  */
 CURLcode Curl_buffer_send(struct dynbuf *in,
-                          struct connectdata *conn,
+                          struct Curl_easy *data,
                           /* add the number of sent bytes to this
                              counter */
                           curl_off_t *bytes_written,
@@ -1166,8 +1199,8 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
   CURLcode result;
   char *ptr;
   size_t size;
-  struct Curl_easy *data = conn->data;
-  struct HTTP *http = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct HTTP *http = data->req.p.http;
   size_t sendsize;
   curl_socket_t sockfd;
   size_t headersize;
@@ -1226,7 +1259,9 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
   }
   else {
 #ifdef CURLDEBUG
-    /* Allow debug builds override this logic to force short initial sends */
+    /* Allow debug builds to override this logic to force short initial
+       sends
+     */
     char *p = getenv("CURL_SMALLREQSEND");
     if(p) {
       size_t altsize = (size_t)strtoul(p, NULL, 10);
@@ -1240,7 +1275,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
     sendsize = size;
   }
 
-  result = Curl_write(conn, sockfd, ptr, sendsize, &amount);
+  result = Curl_write(data, sockfd, ptr, sendsize, &amount);
 
   if(!result) {
     /*
@@ -1252,16 +1287,12 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
     size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount;
     size_t bodylen = amount - headlen;
 
-    if(data->set.verbose) {
-      /* this data _may_ contain binary stuff */
-      Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen);
-      if(bodylen) {
-        /* there was body data sent beyond the initial header part, pass that
-           on to the debug callback too */
-        Curl_debug(data, CURLINFO_DATA_OUT,
-                   ptr + headlen, bodylen);
-      }
-    }
+    /* this data _may_ contain binary stuff */
+    Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen);
+    if(bodylen)
+      /* there was body data sent beyond the initial header part, pass that on
+         to the debug callback too */
+      Curl_debug(data, CURLINFO_DATA_OUT, ptr + headlen, bodylen);
 
     /* 'amount' can never be a very large value here so typecasting it so a
        signed 31 bit value should not cause problems even if ssize_t is
@@ -1291,10 +1322,13 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
 
         /* set the new pointers for the request-sending */
         data->state.fread_func = (curl_read_callback)readmoredata;
-        data->state.in = (void *)conn;
+        data->state.in = (void *)data;
         http->postdata = ptr;
         http->postsize = (curl_off_t)size;
 
+        /* this much data is remaining header: */
+        data->req.pendingheader = headersize - headlen;
+
         http->send_buffer = *in; /* copy the whole struct */
         http->sending = HTTPSEND_REQUEST;
 
@@ -1317,9 +1351,13 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
   }
   Curl_dyn_free(in);
 
+  /* no remaining header data */
+  data->req.pendingheader = 0;
   return result;
 }
 
+#endif
+
 /* end of the add_buffer functions */
 /* ------------------------------------------------------------------------- */
 
@@ -1353,7 +1391,7 @@ Curl_compareheader(const char *headerline, /* line to check */
   /* pass the header */
   start = &headerline[hlen];
 
-  /* pass all white spaces */
+  /* pass all whitespace */
   while(*start && ISSPACE(*start))
     start++;
 
@@ -1384,9 +1422,10 @@ Curl_compareheader(const char *headerline, /* line to check */
  * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
  * the generic Curl_connect().
  */
-CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
+CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
 
   /* We default to persistent connections. We set this already in this connect
      function to make the re-use checks properly be able to check this bit. */
@@ -1394,7 +1433,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
 
 #ifndef CURL_DISABLE_PROXY
   /* the CONNECT procedure might not have been completed */
-  result = Curl_proxy_connect(conn, FIRSTSOCKET);
+  result = Curl_proxy_connect(data, FIRSTSOCKET);
   if(result)
     return result;
 
@@ -1409,9 +1448,9 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
     /* nothing else to do except wait right now - we're not done here. */
     return CURLE_OK;
 
-  if(conn->data->set.haproxyprotocol) {
+  if(data->set.haproxyprotocol) {
     /* add HAProxy PROXY protocol header */
-    result = add_haproxy_protocol_header(conn);
+    result = add_haproxy_protocol_header(data);
     if(result)
       return result;
   }
@@ -1419,7 +1458,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
 
   if(conn->given->protocol & CURLPROTO_HTTPS) {
     /* perform SSL initialization */
-    result = https_connecting(conn, done);
+    result = https_connecting(data, done);
     if(result)
       return result;
   }
@@ -1432,24 +1471,27 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
 /* this returns the socket to wait for in the DO and DOING state for the multi
    interface and then we're always _sending_ a request and thus we wait for
    the single socket to become writable only */
-static int http_getsock_do(struct connectdata *conn,
+static int http_getsock_do(struct Curl_easy *data,
+                           struct connectdata *conn,
                            curl_socket_t *socks)
 {
   /* write mode */
+  (void)data;
   socks[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_WRITESOCK(0);
 }
 
 #ifndef CURL_DISABLE_PROXY
-static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
+static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
 {
   char proxy_header[128];
   struct dynbuf req;
   CURLcode result;
   char tcp_version[5];
+  DEBUGASSERT(data->conn);
 
   /* Emit the correct prefix for IPv6 */
-  if(conn->bits.ipv6) {
+  if(data->conn->bits.ipv6) {
     strcpy(tcp_version, "TCP6");
   }
   else {
@@ -1460,10 +1502,10 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
             sizeof(proxy_header),
             "PROXY %s %s %s %li %li\r\n",
             tcp_version,
-            conn->data->info.conn_local_ip,
-            conn->data->info.conn_primary_ip,
-            conn->data->info.conn_local_port,
-            conn->data->info.conn_primary_port);
+            data->info.conn_local_ip,
+            data->info.conn_primary_ip,
+            data->info.conn_local_port,
+            data->info.conn_primary_port);
 
   Curl_dyn_init(&req, DYN_HAXPROXY);
 
@@ -1471,7 +1513,7 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
   if(result)
     return result;
 
-  result = Curl_buffer_send(&req, conn, &conn->data->info.request_size,
+  result = Curl_buffer_send(&req, data, &data->info.request_size,
                             0, FIRSTSOCKET);
 
   return result;
@@ -1479,10 +1521,11 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
 #endif
 
 #ifdef USE_SSL
-static CURLcode https_connecting(struct connectdata *conn, bool *done)
+static CURLcode https_connecting(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
-  DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL));
+  struct connectdata *conn = data->conn;
+  DEBUGASSERT((data) && (data->conn->handler->flags & PROTOPT_SSL));
 
 #ifdef ENABLE_QUIC
   if(conn->transport == TRNSPRT_QUIC) {
@@ -1492,16 +1535,18 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
 #endif
 
   /* perform SSL initialization for this socket */
-  result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
+  result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET, done);
   if(result)
     connclose(conn, "Failed HTTPS connection");
 
   return result;
 }
 
-static int https_getsock(struct connectdata *conn,
+static int https_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
                          curl_socket_t *socks)
 {
+  (void)data;
   if(conn->handler->flags & PROTOPT_SSL)
     return Curl_ssl_getsock(conn, socks);
   return GETSOCK_BLANK;
@@ -1513,18 +1558,18 @@ static int https_getsock(struct connectdata *conn,
  * performed.
  */
 
-CURLcode Curl_http_done(struct connectdata *conn,
+CURLcode Curl_http_done(struct Curl_easy *data,
                         CURLcode status, bool premature)
 {
-  struct Curl_easy *data = conn->data;
-  struct HTTP *http = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct HTTP *http = data->req.p.http;
 
   /* Clear multipass flag. If authentication isn't done yet, then it will get
    * a chance to be set back to true when we output the next auth header */
   data->state.authhost.multipass = FALSE;
   data->state.authproxy.multipass = FALSE;
 
-  Curl_unencode_cleanup(conn);
+  Curl_unencode_cleanup(data);
 
   /* set the proper values (possibly modified on POST) */
   conn->seek_func = data->set.seek_func; /* restore */
@@ -1538,6 +1583,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
   Curl_quic_done(data, premature);
   Curl_mime_cleanpart(&http->form);
   Curl_dyn_reset(&data->state.headerb);
+  Curl_hyper_done(data);
 
   if(status)
     return status;
@@ -1553,6 +1599,8 @@ CURLcode Curl_http_done(struct connectdata *conn,
        read from the HTTP server (that counts), this can't be right so we
        return an error here */
     failf(data, "Empty reply from server");
+    /* Mark it as closed to avoid the "left intact" message */
+    streamclose(conn, "Empty reply from server");
     return CURLE_GOT_NOTHING;
   }
 
@@ -1580,6 +1628,7 @@ static bool use_http_1_1plus(const struct Curl_easy *data,
           (data->set.httpversion >= CURL_HTTP_VERSION_1_1));
 }
 
+#ifndef USE_HYPER
 static const char *get_http_string(const struct Curl_easy *data,
                                    const struct connectdata *conn)
 {
@@ -1599,6 +1648,7 @@ static const char *get_http_string(const struct Curl_easy *data,
 
   return "1.0";
 }
+#endif
 
 /* check and possibly add an Expect: header */
 static CURLcode expect100(struct Curl_easy *data,
@@ -1613,7 +1663,7 @@ static CURLcode expect100(struct Curl_easy *data,
     /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
        Expect: 100-continue to the headers which actually speeds up post
        operations (as there is one packet coming back from the web server) */
-    const char *ptr = Curl_checkheaders(conn, "Expect");
+    const char *ptr = Curl_checkheaders(data, "Expect");
     if(ptr) {
       data->state.expect100header =
         Curl_compareheader(ptr, "Expect:", "100-continue");
@@ -1679,15 +1729,20 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
   return result;
 }
 
-CURLcode Curl_add_custom_headers(struct connectdata *conn,
+CURLcode Curl_add_custom_headers(struct Curl_easy *data,
                                  bool is_connect,
-                                 struct dynbuf *req)
+#ifndef USE_HYPER
+                                 struct dynbuf *req
+#else
+                                 void *req
+#endif
+  )
 {
+  struct connectdata *conn = data->conn;
   char *ptr;
   struct curl_slist *h[2];
   struct curl_slist *headers;
   int numlists = 1; /* by default */
-  struct Curl_easy *data = conn->data;
   int i;
 
 #ifndef CURL_DISABLE_PROXY
@@ -1748,7 +1803,9 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
               /* copy the source */
               semicolonp = strdup(headers->data);
               if(!semicolonp) {
+#ifndef USE_HYPER
                 Curl_dyn_free(req);
+#endif
                 return CURLE_OUT_OF_MEMORY;
               }
               /* put a colon where the semicolon is */
@@ -1809,7 +1866,11 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
                    !strcasecompare(data->state.first_host, conn->host.name)))
             ;
           else {
+#ifdef USE_HYPER
+            result = Curl_hyper_header(data, req, compare);
+#else
             result = Curl_dyn_addf(req, "%s\r\n", compare);
+#endif
           }
           if(semicolonp)
             free(semicolonp);
@@ -1825,10 +1886,14 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
 }
 
 #ifndef CURL_DISABLE_PARSEDATE
-CURLcode Curl_add_timecondition(const struct connectdata *conn,
-                                struct dynbuf *req)
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+#ifndef USE_HYPER
+                                struct dynbuf *req
+#else
+                                void *req
+#endif
+  )
 {
-  struct Curl_easy *data = conn->data;
   const struct tm *tm;
   struct tm keeptime;
   CURLcode result;
@@ -1861,7 +1926,7 @@ CURLcode Curl_add_timecondition(const struct connectdata *conn,
     break;
   }
 
-  if(Curl_checkheaders(conn, condp)) {
+  if(Curl_checkheaders(data, condp)) {
     /* A custom header was specified; it will be sent instead. */
     return CURLE_OK;
   }
@@ -1885,7 +1950,11 @@ CURLcode Curl_add_timecondition(const struct connectdata *conn,
             tm->tm_min,
             tm->tm_sec);
 
+#ifndef USE_HYPER
   result = Curl_dyn_add(req, datestr);
+#else
+  result = Curl_hyper_header(data, req, datestr);
+#endif
 
   return result;
 }
@@ -1900,102 +1969,14 @@ CURLcode Curl_add_timecondition(const struct connectdata *conn,
 }
 #endif
 
-/*
- * Curl_http() gets called from the generic multi_do() function when a HTTP
- * request is to be performed. This creates and sends a properly constructed
- * HTTP request.
- */
-CURLcode Curl_http(struct connectdata *conn, bool *done)
+void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
+                      const char **method, Curl_HttpReq *reqp)
 {
-  struct Curl_easy *data = conn->data;
-  CURLcode result = CURLE_OK;
-  struct HTTP *http;
-  const char *path = data->state.up.path;
-  const char *query = data->state.up.query;
-  bool paste_ftp_userpwd = FALSE;
-  char ftp_typecode[sizeof("/;type=?")] = "";
-  const char *host = conn->host.name;
-  const char *te = ""; /* transfer-encoding */
-  const char *ptr;
-  const char *request;
   Curl_HttpReq httpreq = data->state.httpreq;
-#if !defined(CURL_DISABLE_COOKIES)
-  char *addcookies = NULL;
-#endif
-  curl_off_t included_body = 0;
-  const char *httpstring;
-  struct dynbuf req;
-  curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
-  char *altused = NULL;
-
-  /* Always consider the DO phase done after this function call, even if there
-     may be parts of the request that is not yet sent, since we can deal with
-     the rest of the request in the PERFORM phase. */
-  *done = TRUE;
-
-  if(conn->transport != TRNSPRT_QUIC) {
-    if(conn->httpversion < 20) { /* unless the connection is re-used and
-                                    already http2 */
-      switch(conn->negnpn) {
-      case CURL_HTTP_VERSION_2:
-        conn->httpversion = 20; /* we know we're on HTTP/2 now */
-
-        result = Curl_http2_switched(conn, NULL, 0);
-        if(result)
-          return result;
-        break;
-      case CURL_HTTP_VERSION_1_1:
-        /* continue with HTTP/1.1 when explicitly requested */
-        break;
-      default:
-        /* Check if user wants to use HTTP/2 with clear TCP*/
-#ifdef USE_NGHTTP2
-        if(conn->data->set.httpversion ==
-           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
-               whether or not this setting should apply to HTTP/2 proxies. */
-            infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n");
-            break;
-          }
-#endif
-          DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
-          conn->httpversion = 20;
-
-          result = Curl_http2_switched(conn, NULL, 0);
-          if(result)
-            return result;
-        }
-#endif
-        break;
-      }
-    }
-    else {
-      /* prepare for a http2 request */
-      result = Curl_http2_setup(conn);
-      if(result)
-        return result;
-    }
-  }
-  http = data->req.protop;
-  DEBUGASSERT(http);
-
-  if(!data->state.this_is_a_follow) {
-    /* Free to avoid leaking memory on multiple requests*/
-    free(data->state.first_host);
-
-    data->state.first_host = strdup(conn->host.name);
-    if(!data->state.first_host)
-      return CURLE_OUT_OF_MEMORY;
-
-    data->state.first_remote_port = conn->remote_port;
-  }
-
+  const char *request;
   if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) &&
-     data->set.upload) {
+     data->set.upload)
     httpreq = HTTPREQ_PUT;
-  }
 
   /* Now set the 'request' pointer to the proper request string */
   if(data->set.str[STRING_CUSTOMREQUEST])
@@ -2004,7 +1985,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     if(data->set.opt_no_body)
       request = "HEAD";
     else {
-      DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
+      DEBUGASSERT((httpreq >= HTTPREQ_GET) && (httpreq <= HTTPREQ_HEAD));
       switch(httpreq) {
       case HTTPREQ_POST:
       case HTTPREQ_POST_FORM:
@@ -2024,98 +2005,236 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       }
     }
   }
+  *method = request;
+  *reqp = httpreq;
+}
 
+CURLcode Curl_http_useragent(struct Curl_easy *data)
+{
   /* The User-Agent string might have been allocated in url.c already, because
      it might have been used in the proxy connect, but if we have got a header
      with the user-agent string specified, we erase the previously made string
      here. */
-  if(Curl_checkheaders(conn, "User-Agent")) {
+  if(Curl_checkheaders(data, "User-Agent")) {
     free(data->state.aptr.uagent);
     data->state.aptr.uagent = NULL;
   }
+  return CURLE_OK;
+}
 
-  /* setup the authentication headers */
-  {
-    char *pq = NULL;
-    if(query && *query) {
-      pq = aprintf("%s?%s", path, query);
-      if(!pq)
-        return CURLE_OUT_OF_MEMORY;
-    }
-    result = Curl_http_output_auth(conn, request, (pq ? pq : path), FALSE);
-    free(pq);
-    if(result)
-      return result;
-  }
 
-  if(((data->state.authhost.multipass && !data->state.authhost.done)
-      || (data->state.authproxy.multipass && !data->state.authproxy.done)) &&
-     (httpreq != HTTPREQ_GET) &&
-     (httpreq != HTTPREQ_HEAD)) {
-    /* Auth is required and we are not authenticated yet. Make a PUT or POST
-       with content-length zero as a "probe". */
-    conn->bits.authneg = TRUE;
-  }
-  else
-    conn->bits.authneg = FALSE;
+CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
+{
+  const char *ptr;
+  if(!data->state.this_is_a_follow) {
+    /* Free to avoid leaking memory on multiple requests*/
+    free(data->state.first_host);
 
-  Curl_safefree(data->state.aptr.ref);
-  if(data->change.referer && !Curl_checkheaders(conn, "Referer")) {
-    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
-    if(!data->state.aptr.ref)
+    data->state.first_host = strdup(conn->host.name);
+    if(!data->state.first_host)
       return CURLE_OUT_OF_MEMORY;
+
+    data->state.first_remote_port = conn->remote_port;
   }
-  else
-    data->state.aptr.ref = NULL;
+  Curl_safefree(data->state.aptr.host);
 
+  ptr = Curl_checkheaders(data, "Host");
+  if(ptr && (!data->state.this_is_a_follow ||
+             strcasecompare(data->state.first_host, conn->host.name))) {
 #if !defined(CURL_DISABLE_COOKIES)
-  if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie"))
-    addcookies = data->set.str[STRING_COOKIE];
-#endif
-
-  if(!Curl_checkheaders(conn, "Accept-Encoding") &&
-     data->set.str[STRING_ENCODING]) {
-    Curl_safefree(data->state.aptr.accept_encoding);
-    data->state.aptr.accept_encoding =
-      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
-    if(!data->state.aptr.accept_encoding)
+    /* If we have a given custom Host: header, we extract the host name in
+       order to possibly use it for cookie reasons later on. We only allow the
+       custom Host: header if this is NOT a redirect, as setting Host: in the
+       redirected request is being out on thin ice. Except if the host name
+       is the same as the first one! */
+    char *cookiehost = Curl_copy_header_value(ptr);
+    if(!cookiehost)
       return CURLE_OUT_OF_MEMORY;
-  }
-  else {
-    Curl_safefree(data->state.aptr.accept_encoding);
-    data->state.aptr.accept_encoding = NULL;
-  }
-
-#ifdef HAVE_LIBZ
-  /* we only consider transfer-encoding magic if libz support is built-in */
-
-  if(!Curl_checkheaders(conn, "TE") &&
-     data->set.http_transfer_encoding) {
-    /* When we are to insert a TE: header in the request, we must also insert
-       TE in a Connection: header, so we need to merge the custom provided
-       Connection: header and prevent the original to get sent. Note that if
-       the user has inserted his/hers own TE: header we don't do this magic
-       but then assume that the user will handle it all! */
-    char *cptr = Curl_checkheaders(conn, "Connection");
-#define TE_HEADER "TE: gzip\r\n"
-
-    Curl_safefree(data->state.aptr.te);
+    if(!*cookiehost)
+      /* ignore empty data */
+      free(cookiehost);
+    else {
+      /* If the host begins with '[', we start searching for the port after
+         the bracket has been closed */
+      if(*cookiehost == '[') {
+        char *closingbracket;
+        /* since the 'cookiehost' is an allocated memory area that will be
+           freed later we cannot simply increment the pointer */
+        memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
+        closingbracket = strchr(cookiehost, ']');
+        if(closingbracket)
+          *closingbracket = 0;
+      }
+      else {
+        int startsearch = 0;
+        char *colon = strchr(cookiehost + startsearch, ':');
+        if(colon)
+          *colon = 0; /* The host must not include an embedded port number */
+      }
+      Curl_safefree(data->state.aptr.cookiehost);
+      data->state.aptr.cookiehost = cookiehost;
+    }
+#endif
 
-    if(cptr) {
-      cptr = Curl_copy_header_value(cptr);
-      if(!cptr)
+    if(strcmp("Host:", ptr)) {
+      data->state.aptr.host = aprintf("Host:%s\r\n", &ptr[5]);
+      if(!data->state.aptr.host)
         return CURLE_OUT_OF_MEMORY;
     }
+    else
+      /* when clearing the header */
+      data->state.aptr.host = NULL;
+  }
+  else {
+    /* When building Host: headers, we must put the host name within
+       [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
+    const char *host = conn->host.name;
 
-    /* Create the (updated) Connection: header */
-    data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
-                                cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
+    if(((conn->given->protocol&CURLPROTO_HTTPS) &&
+        (conn->remote_port == PORT_HTTPS)) ||
+       ((conn->given->protocol&CURLPROTO_HTTP) &&
+        (conn->remote_port == PORT_HTTP)) )
+      /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
+         the port number in the host string */
+      data->state.aptr.host = aprintf("Host: %s%s%s\r\n",
+                                    conn->bits.ipv6_ip?"[":"",
+                                    host,
+                                    conn->bits.ipv6_ip?"]":"");
+    else
+      data->state.aptr.host = aprintf("Host: %s%s%s:%d\r\n",
+                                    conn->bits.ipv6_ip?"[":"",
+                                    host,
+                                    conn->bits.ipv6_ip?"]":"",
+                                    conn->remote_port);
 
-    free(cptr);
-    if(!data->state.aptr.te)
+    if(!data->state.aptr.host)
+      /* without Host: we can't make a nice request */
       return CURLE_OUT_OF_MEMORY;
   }
+  return CURLE_OK;
+}
+
+/*
+ * Append the request-target to the HTTP request
+ */
+CURLcode Curl_http_target(struct Curl_easy *data,
+                          struct connectdata *conn,
+                          struct dynbuf *r)
+{
+  CURLcode result = CURLE_OK;
+  const char *path = data->state.up.path;
+  const char *query = data->state.up.query;
+
+  if(data->set.str[STRING_TARGET]) {
+    path = data->set.str[STRING_TARGET];
+    query = NULL;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+    /* Using a proxy but does not tunnel through it */
+
+    /* The path sent to the proxy is in fact the entire URL. But if the remote
+       host is a IDN-name, we must make sure that the request we produce only
+       uses the encoded host name! */
+
+    /* and no fragment part */
+    CURLUcode uc;
+    char *url;
+    CURLU *h = curl_url_dup(data->state.uh);
+    if(!h)
+      return CURLE_OUT_OF_MEMORY;
+
+    if(conn->host.dispname != conn->host.name) {
+      uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
+      if(uc) {
+        curl_url_cleanup(h);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
+    if(uc) {
+      curl_url_cleanup(h);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    if(strcasecompare("http", data->state.up.scheme)) {
+      /* when getting HTTP, we don't want the userinfo the URL */
+      uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
+      if(uc) {
+        curl_url_cleanup(h);
+        return CURLE_OUT_OF_MEMORY;
+      }
+      uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
+      if(uc) {
+        curl_url_cleanup(h);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    /* Extract the URL to use in the request. Store in STRING_TEMP_URL for
+       clean-up reasons if the function returns before the free() further
+       down. */
+    uc = curl_url_get(h, CURLUPART_URL, &url, 0);
+    if(uc) {
+      curl_url_cleanup(h);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    curl_url_cleanup(h);
+
+    /* target or url */
+    result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
+      data->set.str[STRING_TARGET]:url);
+    free(url);
+    if(result)
+      return (result);
+
+    if(strcasecompare("ftp", data->state.up.scheme)) {
+      if(data->set.proxy_transfer_mode) {
+        /* when doing ftp, append ;type=<a|i> if not present */
+        char *type = strstr(path, ";type=");
+        if(type && type[6] && type[7] == 0) {
+          switch(Curl_raw_toupper(type[6])) {
+          case 'A':
+          case 'D':
+          case 'I':
+            break;
+          default:
+            type = NULL;
+          }
+        }
+        if(!type) {
+          result = Curl_dyn_addf(r, ";type=%c",
+                                 data->set.prefer_ascii ? 'a' : 'i');
+          if(result)
+            return result;
+        }
+      }
+    }
+  }
+
+  else
+#else
+    (void)conn; /* not used in disabled-proxy builds */
 #endif
+  {
+    result = Curl_dyn_add(r, path);
+    if(result)
+      return result;
+    if(query)
+      result = Curl_dyn_addf(r, "?%s", query);
+  }
+
+  return result;
+}
+
+CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
+                        Curl_HttpReq httpreq, const char **tep)
+{
+  CURLcode result = CURLE_OK;
+  const char *ptr;
+  struct HTTP *http = data->req.p.http;
+  http->postsize = 0;
 
   switch(httpreq) {
   case HTTPREQ_POST_MIME:
@@ -2136,7 +2255,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
 #ifndef CURL_DISABLE_MIME
   if(http->sendit) {
-    const char *cthdr = Curl_checkheaders(conn, "Content-Type");
+    const char *cthdr = Curl_checkheaders(data, "Content-Type");
 
     /* Read and seek body only. */
     http->sendit->flags |= MIME_BODY_ONLY;
@@ -2161,7 +2280,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
 #endif
 
-  ptr = Curl_checkheaders(conn, "Transfer-Encoding");
+  ptr = Curl_checkheaders(data, "Transfer-Encoding");
   if(ptr) {
     /* Some kind of TE is requested, check if 'chunked' is chosen */
     data->req.upload_chunky =
@@ -2192,409 +2311,348 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     }
 
     if(data->req.upload_chunky)
-      te = "Transfer-Encoding: chunked\r\n";
+      *tep = "Transfer-Encoding: chunked\r\n";
   }
+  return result;
+}
 
-  Curl_safefree(data->state.aptr.host);
-
-  ptr = Curl_checkheaders(conn, "Host");
-  if(ptr && (!data->state.this_is_a_follow ||
-             strcasecompare(data->state.first_host, conn->host.name))) {
-#if !defined(CURL_DISABLE_COOKIES)
-    /* If we have a given custom Host: header, we extract the host name in
-       order to possibly use it for cookie reasons later on. We only allow the
-       custom Host: header if this is NOT a redirect, as setting Host: in the
-       redirected request is being out on thin ice. Except if the host name
-       is the same as the first one! */
-    char *cookiehost = Curl_copy_header_value(ptr);
-    if(!cookiehost)
-      return CURLE_OUT_OF_MEMORY;
-    if(!*cookiehost)
-      /* ignore empty data */
-      free(cookiehost);
-    else {
-      /* If the host begins with '[', we start searching for the port after
-         the bracket has been closed */
-      if(*cookiehost == '[') {
-        char *closingbracket;
-        /* since the 'cookiehost' is an allocated memory area that will be
-           freed later we cannot simply increment the pointer */
-        memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
-        closingbracket = strchr(cookiehost, ']');
-        if(closingbracket)
-          *closingbracket = 0;
-      }
-      else {
-        int startsearch = 0;
-        char *colon = strchr(cookiehost + startsearch, ':');
-        if(colon)
-          *colon = 0; /* The host must not include an embedded port number */
-      }
-      Curl_safefree(data->state.aptr.cookiehost);
-      data->state.aptr.cookiehost = cookiehost;
-    }
+CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
+                            struct dynbuf *r, Curl_HttpReq httpreq)
+{
+#ifndef USE_HYPER
+  /* Hyper always handles the body separately */
+  curl_off_t included_body = 0;
 #endif
+  CURLcode result = CURLE_OK;
+  struct HTTP *http = data->req.p.http;
+  const char *ptr;
 
-    if(strcmp("Host:", ptr)) {
-      data->state.aptr.host = aprintf("Host:%s\r\n", &ptr[5]);
-      if(!data->state.aptr.host)
-        return CURLE_OUT_OF_MEMORY;
-    }
-    else
-      /* when clearing the header */
-      data->state.aptr.host = NULL;
-  }
-  else {
-    /* When building Host: headers, we must put the host name within
-       [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
+  /* If 'authdone' is FALSE, we must not set the write socket index to the
+     Curl_transfer() call below, as we're not ready to actually upload any
+     data yet. */
 
-    if(((conn->given->protocol&CURLPROTO_HTTPS) &&
-        (conn->remote_port == PORT_HTTPS)) ||
-       ((conn->given->protocol&CURLPROTO_HTTP) &&
-        (conn->remote_port == PORT_HTTP)) )
-      /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
-         the port number in the host string */
-      data->state.aptr.host = aprintf("Host: %s%s%s\r\n",
-                                    conn->bits.ipv6_ip?"[":"",
-                                    host,
-                                    conn->bits.ipv6_ip?"]":"");
+  switch(httpreq) {
+
+  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+
+    if(conn->bits.authneg)
+      http->postsize = 0;
     else
-      data->state.aptr.host = aprintf("Host: %s%s%s:%d\r\n",
-                                    conn->bits.ipv6_ip?"[":"",
-                                    host,
-                                    conn->bits.ipv6_ip?"]":"",
-                                    conn->remote_port);
+      http->postsize = data->state.infilesize;
 
-    if(!data->state.aptr.host)
-      /* without Host: we can't make a nice request */
-      return CURLE_OUT_OF_MEMORY;
-  }
+    if((http->postsize != -1) && !data->req.upload_chunky &&
+       (conn->bits.authneg || !Curl_checkheaders(data, "Content-Length"))) {
+      /* only add Content-Length if not uploading chunked */
+      result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+                             "\r\n", http->postsize);
+      if(result)
+        return result;
+    }
 
-#ifndef CURL_DISABLE_PROXY
-  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
-    /* Using a proxy but does not tunnel through it */
+    if(http->postsize) {
+      result = expect100(data, conn, r);
+      if(result)
+        return result;
+    }
 
-    /* The path sent to the proxy is in fact the entire URL. But if the remote
-       host is a IDN-name, we must make sure that the request we produce only
-       uses the encoded host name! */
+    /* end of headers */
+    result = Curl_dyn_add(r, "\r\n");
+    if(result)
+      return result;
 
-    /* and no fragment part */
-    CURLUcode uc;
-    CURLU *h = curl_url_dup(data->state.uh);
-    if(!h)
-      return CURLE_OUT_OF_MEMORY;
+    /* set the upload size to the progress meter */
+    Curl_pgrsSetUploadSize(data, http->postsize);
 
-    if(conn->host.dispname != conn->host.name) {
-      uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
-      if(uc) {
-        curl_url_cleanup(h);
-        return CURLE_OUT_OF_MEMORY;
-      }
+    /* this sends the buffer and frees all the buffer resources */
+    result = Curl_buffer_send(r, data, &data->info.request_size, 0,
+                              FIRSTSOCKET);
+    if(result)
+      failf(data, "Failed sending PUT request");
+    else
+      /* prepare for transfer */
+      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+                          http->postsize?FIRSTSOCKET:-1);
+    if(result)
+      return result;
+    break;
+
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+    /* This is form posting using mime data. */
+    if(conn->bits.authneg) {
+      /* nothing to post! */
+      result = Curl_dyn_add(r, "Content-Length: 0\r\n\r\n");
+      if(result)
+        return result;
+
+      result = Curl_buffer_send(r, data, &data->info.request_size, 0,
+                                FIRSTSOCKET);
+      if(result)
+        failf(data, "Failed sending POST request");
+      else
+        /* setup variables for the upcoming transfer */
+        Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+      break;
     }
-    uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
-    if(uc) {
-      curl_url_cleanup(h);
-      return CURLE_OUT_OF_MEMORY;
+
+    data->state.infilesize = http->postsize;
+
+    /* We only set Content-Length and allow a custom Content-Length if
+       we don't upload data chunked, as RFC2616 forbids us to set both
+       kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+    if(http->postsize != -1 && !data->req.upload_chunky &&
+       (conn->bits.authneg || !Curl_checkheaders(data, "Content-Length"))) {
+      /* we allow replacing this header if not during auth negotiation,
+         although it isn't very wise to actually set your own */
+      result = Curl_dyn_addf(r,
+                             "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+                             "\r\n", http->postsize);
+      if(result)
+        return result;
     }
 
-    if(strcasecompare("http", data->state.up.scheme)) {
-      /* when getting HTTP, we don't want the userinfo the URL */
-      uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
-      if(uc) {
-        curl_url_cleanup(h);
-        return CURLE_OUT_OF_MEMORY;
-      }
-      uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
-      if(uc) {
-        curl_url_cleanup(h);
-        return CURLE_OUT_OF_MEMORY;
-      }
-    }
-    /* Extract the URL to use in the request. Store in STRING_TEMP_URL for
-       clean-up reasons if the function returns before the free() further
-       down. */
-    uc = curl_url_get(h, CURLUPART_URL, &data->set.str[STRING_TEMP_URL], 0);
-    if(uc) {
-      curl_url_cleanup(h);
-      return CURLE_OUT_OF_MEMORY;
-    }
-
-    curl_url_cleanup(h);
+#ifndef CURL_DISABLE_MIME
+    /* Output mime-generated headers. */
+    {
+      struct curl_slist *hdr;
 
-    if(strcasecompare("ftp", data->state.up.scheme)) {
-      if(data->set.proxy_transfer_mode) {
-        /* when doing ftp, append ;type=<a|i> if not present */
-        char *type = strstr(path, ";type=");
-        if(type && type[6] && type[7] == 0) {
-          switch(Curl_raw_toupper(type[6])) {
-          case 'A':
-          case 'D':
-          case 'I':
-            break;
-          default:
-            type = NULL;
-          }
-        }
-        if(!type) {
-          char *p = ftp_typecode;
-          /* avoid sending invalid URLs like ftp://example.com;type=i if the
-           * user specified ftp://example.com without the slash */
-          if(!*data->state.up.path && path[strlen(path) - 1] != '/') {
-            *p++ = '/';
-          }
-          msnprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
-                    data->set.prefer_ascii ? 'a' : 'i');
-        }
+      for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
+        result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
+        if(result)
+          return result;
       }
-      if(conn->bits.user_passwd)
-        paste_ftp_userpwd = TRUE;
     }
-  }
-#endif /* CURL_DISABLE_PROXY */
+#endif
 
-  http->p_accept = Curl_checkheaders(conn, "Accept")?NULL:"Accept: */*\r\n";
+    /* For really small posts 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, "Expect");
+    if(ptr) {
+      data->state.expect100header =
+        Curl_compareheader(ptr, "Expect:", "100-continue");
+    }
+    else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
+      result = expect100(data, conn, r);
+      if(result)
+        return result;
+    }
+    else
+      data->state.expect100header = FALSE;
 
-  if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
-     data->state.resume_from) {
-    /**********************************************************************
-     * Resuming upload in HTTP means that we PUT or POST and that we have
-     * got a resume_from value set. The resume value has already created
-     * a Range: header that will be passed along. We need to "fast forward"
-     * the file the given number of bytes and decrease the assume upload
-     * file size before we continue this venture in the dark lands of HTTP.
-     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
-     *********************************************************************/
+    /* make the request end in a true CRLF */
+    result = Curl_dyn_add(r, "\r\n");
+    if(result)
+      return result;
 
-    if(data->state.resume_from < 0) {
-      /*
-       * This is meant to get the size of the present remote-file by itself.
-       * We don't support this now. Bail out!
-       */
-      data->state.resume_from = 0;
-    }
+    /* set the upload size to the progress meter */
+    Curl_pgrsSetUploadSize(data, http->postsize);
 
-    if(data->state.resume_from && !data->state.this_is_a_follow) {
-      /* do we still game? */
+    /* Read from mime structure. */
+    data->state.fread_func = (curl_read_callback) Curl_mime_read;
+    data->state.in = (void *) http->sendit;
+    http->sending = HTTPSEND_BODY;
 
-      /* Now, let's read off the proper amount of bytes from the
-         input. */
-      int seekerr = CURL_SEEKFUNC_CANTSEEK;
-      if(conn->seek_func) {
-        Curl_set_in_callback(data, true);
-        seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
-                                  SEEK_SET);
-        Curl_set_in_callback(data, false);
-      }
+    /* this sends the buffer and frees all the buffer resources */
+    result = Curl_buffer_send(r, data, &data->info.request_size, 0,
+                              FIRSTSOCKET);
+    if(result)
+      failf(data, "Failed sending POST request");
+    else
+      /* prepare for transfer */
+      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+                          http->postsize?FIRSTSOCKET:-1);
+    if(result)
+      return result;
 
-      if(seekerr != CURL_SEEKFUNC_OK) {
-        curl_off_t passed = 0;
+    break;
 
-        if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
-          failf(data, "Could not seek stream");
-          return CURLE_READ_ERROR;
-        }
-        /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
-        do {
-          size_t readthisamountnow =
-            (data->state.resume_from - passed > data->set.buffer_size) ?
-            (size_t)data->set.buffer_size :
-            curlx_sotouz(data->state.resume_from - passed);
+  case HTTPREQ_POST:
+    /* this is the simple POST, using x-www-form-urlencoded style */
 
-          size_t actuallyread =
-            data->state.fread_func(data->state.buffer, 1, readthisamountnow,
-                                   data->state.in);
+    if(conn->bits.authneg)
+      http->postsize = 0;
+    else
+      /* the size of the post body */
+      http->postsize = data->state.infilesize;
 
-          passed += actuallyread;
-          if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
-            /* this checks for greater-than only to make sure that the
-               CURL_READFUNC_ABORT return code still aborts */
-            failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
-                  " bytes from the input", passed);
-            return CURLE_READ_ERROR;
-          }
-        } while(passed < data->state.resume_from);
-      }
+    /* We only set Content-Length and allow a custom Content-Length if
+       we don't upload data chunked, as RFC2616 forbids us to set both
+       kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+    if((http->postsize != -1) && !data->req.upload_chunky &&
+       (conn->bits.authneg || !Curl_checkheaders(data, "Content-Length"))) {
+      /* we allow replacing this header if not during auth negotiation,
+         although it isn't very wise to actually set your own */
+      result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+                             "\r\n", http->postsize);
+      if(result)
+        return result;
+    }
 
-      /* now, decrease the size of the read */
-      if(data->state.infilesize>0) {
-        data->state.infilesize -= data->state.resume_from;
+    if(!Curl_checkheaders(data, "Content-Type")) {
+      result = Curl_dyn_add(r, "Content-Type: application/"
+                            "x-www-form-urlencoded\r\n");
+      if(result)
+        return result;
+    }
 
-        if(data->state.infilesize <= 0) {
-          failf(data, "File already completely uploaded");
-          return CURLE_PARTIAL_FILE;
-        }
-      }
-      /* we've passed, proceed as normal */
+    /* For really small posts 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, "Expect");
+    if(ptr) {
+      data->state.expect100header =
+        Curl_compareheader(ptr, "Expect:", "100-continue");
     }
-  }
-  if(data->state.use_range) {
-    /*
-     * A range is selected. We use different headers whether we're downloading
-     * or uploading and we always let customized headers override our internal
-     * ones if any such are specified.
-     */
-    if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
-       !Curl_checkheaders(conn, "Range")) {
-      /* if a line like this was already allocated, free the previous one */
-      free(data->state.aptr.rangeline);
-      data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
-                                         data->state.range);
+    else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
+      result = expect100(data, conn, r);
+      if(result)
+        return result;
     }
-    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
-            !Curl_checkheaders(conn, "Content-Range")) {
+    else
+      data->state.expect100header = FALSE;
 
-      /* if a line like this was already allocated, free the previous one */
-      free(data->state.aptr.rangeline);
+#ifndef USE_HYPER
+    /* With Hyper the body is always passed on separately */
+    if(data->set.postfields) {
 
-      if(data->set.set_resume_from < 0) {
-        /* Upload resume was asked for, but we don't know the size of the
-           remote part so we tell the server (and act accordingly) that we
-           upload the whole file (again) */
-        data->state.aptr.rangeline =
-          aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
-                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
-                  data->state.infilesize - 1, data->state.infilesize);
+      /* In HTTP2, we send request body in DATA frame regardless of
+         its size. */
+      if(conn->httpversion != 20 &&
+         !data->state.expect100header &&
+         (http->postsize < MAX_INITIAL_POST_SIZE)) {
+        /* if we don't use expect: 100  AND
+           postsize is less than MAX_INITIAL_POST_SIZE
 
-      }
-      else if(data->state.resume_from) {
-        /* This is because "resume" was selected */
-        curl_off_t total_expected_size =
-          data->state.resume_from + data->state.infilesize;
-        data->state.aptr.rangeline =
-          aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
-                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
-                  data->state.range, total_expected_size-1,
-                  total_expected_size);
-      }
-      else {
-        /* Range was selected and then we just pass the incoming range and
-           append total size */
-        data->state.aptr.rangeline =
-          aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
-                  data->state.range, data->state.infilesize);
-      }
-      if(!data->state.aptr.rangeline)
-        return CURLE_OUT_OF_MEMORY;
-    }
-  }
+           then append the post data to the HTTP request header. This limit
+           is no magic limit but only set to prevent really huge POSTs to
+           get the data duplicated with malloc() and family. */
 
-  httpstring = get_http_string(data, conn);
+        /* end of headers! */
+        result = Curl_dyn_add(r, "\r\n");
+        if(result)
+          return result;
 
-  /* initialize a dynamic send-buffer */
-  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+        if(!data->req.upload_chunky) {
+          /* We're not sending it 'chunked', append it to the request
+             already now to reduce the number if send() calls */
+          result = Curl_dyn_addn(r, data->set.postfields,
+                                 (size_t)http->postsize);
+          included_body = http->postsize;
+        }
+        else {
+          if(http->postsize) {
+            char chunk[16];
+            /* Append the POST data chunky-style */
+            msnprintf(chunk, sizeof(chunk), "%x\r\n", (int)http->postsize);
+            result = Curl_dyn_add(r, chunk);
+            if(!result) {
+              included_body = http->postsize + strlen(chunk);
+              result = Curl_dyn_addn(r, data->set.postfields,
+                                     (size_t)http->postsize);
+              if(!result)
+                result = Curl_dyn_add(r, "\r\n");
+              included_body += 2;
+            }
+          }
+          if(!result) {
+            result = Curl_dyn_add(r, "\x30\x0d\x0a\x0d\x0a");
+            /* 0  CR  LF  CR  LF */
+            included_body += 5;
+          }
+        }
+        if(result)
+          return result;
+        /* Make sure the progress information is accurate */
+        Curl_pgrsSetUploadSize(data, http->postsize);
+      }
+      else {
+        /* A huge POST coming up, do data separate from the request */
+        http->postdata = data->set.postfields;
 
-  /* add the main request stuff */
-  /* GET/HEAD/POST/PUT */
-  result = Curl_dyn_addf(&req, "%s ", request);
-  if(result)
-    return result;
+        http->sending = HTTPSEND_BODY;
 
-  if(data->set.str[STRING_TARGET]) {
-    path = data->set.str[STRING_TARGET];
-    query = NULL;
-  }
+        data->state.fread_func = (curl_read_callback)readmoredata;
+        data->state.in = (void *)data;
 
-#ifndef CURL_DISABLE_PROXY
-  /* url */
-  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
-    char *url = data->set.str[STRING_TEMP_URL];
-    result = Curl_dyn_add(&req, url);
-    Curl_safefree(data->set.str[STRING_TEMP_URL]);
-  }
-  else
-#endif
-  if(paste_ftp_userpwd)
-    result = Curl_dyn_addf(&req, "ftp://%s:%s@%s", conn->user, conn->passwd,
-                           path + sizeof("ftp://") - 1);
-  else {
-    result = Curl_dyn_add(&req, path);
-    if(result)
-      return result;
-    if(query)
-      result = Curl_dyn_addf(&req, "?%s", query);
-  }
-  if(result)
-    return result;
+        /* set the upload size to the progress meter */
+        Curl_pgrsSetUploadSize(data, http->postsize);
 
-#ifdef USE_ALTSVC
-  if(conn->bits.altused && !Curl_checkheaders(conn, "Alt-Used")) {
-    altused = aprintf("Alt-Used: %s:%d\r\n",
-                      conn->conn_to_host.name, conn->conn_to_port);
-    if(!altused) {
-      Curl_dyn_free(&req);
-      return CURLE_OUT_OF_MEMORY;
+        /* end of headers! */
+        result = Curl_dyn_add(r, "\r\n");
+        if(result)
+          return result;
+      }
     }
-  }
+    else
 #endif
-  result =
-    Curl_dyn_addf(&req,
-                  "%s" /* ftp typecode (;type=x) */
-                  " HTTP/%s\r\n" /* HTTP version */
-                  "%s" /* host */
-                  "%s" /* proxyuserpwd */
-                  "%s" /* userpwd */
-                  "%s" /* range */
-                  "%s" /* user agent */
-                  "%s" /* accept */
-                  "%s" /* TE: */
-                  "%s" /* accept-encoding */
-                  "%s" /* referer */
-                  "%s" /* Proxy-Connection */
-                  "%s" /* transfer-encoding */
-                  "%s",/* Alt-Used */
+    {
+       /* end of headers! */
+      result = Curl_dyn_add(r, "\r\n");
+      if(result)
+        return result;
 
-                  ftp_typecode,
-                  httpstring,
-                  (data->state.aptr.host?data->state.aptr.host:""),
-                  data->state.aptr.proxyuserpwd?
-                  data->state.aptr.proxyuserpwd:"",
-                  data->state.aptr.userpwd?data->state.aptr.userpwd:"",
-                  (data->state.use_range && data->state.aptr.rangeline)?
-                  data->state.aptr.rangeline:"",
-                  (data->set.str[STRING_USERAGENT] &&
-                   *data->set.str[STRING_USERAGENT] &&
-                   data->state.aptr.uagent)?
-                  data->state.aptr.uagent:"",
-                  http->p_accept?http->p_accept:"",
-                  data->state.aptr.te?data->state.aptr.te:"",
-                  (data->set.str[STRING_ENCODING] &&
-                   *data->set.str[STRING_ENCODING] &&
-                   data->state.aptr.accept_encoding)?
-                  data->state.aptr.accept_encoding:"",
-                  (data->change.referer && data->state.aptr.ref)?
-                  data->state.aptr.ref:"" /* Referer: <data> */,
-#ifndef CURL_DISABLE_PROXY
-                  (conn->bits.httpproxy &&
-                   !conn->bits.tunnel_proxy &&
-                   !Curl_checkProxyheaders(conn, "Proxy-Connection"))?
-                  "Proxy-Connection: Keep-Alive\r\n":"",
-#else
-                  "",
-#endif
-                  te,
-                  altused ? altused : ""
-      );
+      if(data->req.upload_chunky && conn->bits.authneg) {
+        /* Chunky upload is selected and we're negotiating auth still, send
+           end-of-data only */
+        result = Curl_dyn_add(r, (char *)"\x30\x0d\x0a\x0d\x0a");
+        /* 0  CR  LF  CR  LF */
+        if(result)
+          return result;
+      }
 
-  /* clear userpwd and proxyuserpwd to avoid re-using old credentials
-   * from re-used connections */
-  Curl_safefree(data->state.aptr.userpwd);
-  Curl_safefree(data->state.aptr.proxyuserpwd);
-  free(altused);
+      else if(data->state.infilesize) {
+        /* set the upload size to the progress meter */
+        Curl_pgrsSetUploadSize(data, http->postsize?http->postsize:-1);
+
+        /* set the pointer to mark that we will send the post body using the
+           read callback, but only if we're not in authenticate negotiation */
+        if(!conn->bits.authneg)
+          http->postdata = (char *)&http->postdata;
+      }
+    }
+    /* issue the request */
+    result = Curl_buffer_send(r, data, &data->info.request_size,
+                              (size_t)included_body, FIRSTSOCKET);
 
-  if(result)
-    return result;
+    if(result)
+      failf(data, "Failed sending HTTP POST request");
+    else
+      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+                          http->postdata?FIRSTSOCKET:-1);
+    break;
 
-  if(!(conn->handler->flags&PROTOPT_SSL) &&
-     conn->httpversion != 20 &&
-     (data->set.httpversion == CURL_HTTP_VERSION_2)) {
-    /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
-       over SSL */
-    result = Curl_http2_request_upgrade(&req, conn);
+  default:
+    result = Curl_dyn_add(r, "\r\n");
     if(result)
       return result;
+
+    /* issue the request */
+    result = Curl_buffer_send(r, data, &data->info.request_size, 0,
+                              FIRSTSOCKET);
+
+    if(result)
+      failf(data, "Failed sending HTTP request");
+    else
+      /* HTTP GET/HEAD download: */
+      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
   }
 
+  return result;
+}
+
 #if !defined(CURL_DISABLE_COOKIES)
+CURLcode Curl_http_cookies(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct dynbuf *r)
+{
+  CURLcode result = CURLE_OK;
+  char *addcookies = NULL;
+  if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie"))
+    addcookies = data->set.str[STRING_COOKIE];
+
   if(data->cookies || addcookies) {
     struct Cookie *co = NULL; /* no cookies from start */
     int count = 0;
@@ -2603,7 +2661,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
       co = Curl_cookie_getlist(data->cookies,
                                data->state.aptr.cookiehost?
-                               data->state.aptr.cookiehost:host,
+                               data->state.aptr.cookiehost:
+                               conn->host.name,
                                data->state.up.path,
                                (conn->handler->protocol&CURLPROTO_HTTPS)?
                                TRUE:FALSE);
@@ -2615,11 +2674,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       while(co) {
         if(co->value) {
           if(0 == count) {
-            result = Curl_dyn_add(&req, "Cookie: ");
+            result = Curl_dyn_add(r, "Cookie: ");
             if(result)
               break;
           }
-          result = Curl_dyn_addf(&req, "%s%s=%s", count?"; ":"",
+          result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"",
                                  co->name, co->value);
           if(result)
             break;
@@ -2631,357 +2690,516 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     }
     if(addcookies && !result) {
       if(!count)
-        result = Curl_dyn_add(&req, "Cookie: ");
+        result = Curl_dyn_add(r, "Cookie: ");
       if(!result) {
-        result = Curl_dyn_addf(&req, "%s%s", count?"; ":"", addcookies);
+        result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies);
         count++;
       }
     }
     if(count && !result)
-      result = Curl_dyn_add(&req, "\r\n");
+      result = Curl_dyn_add(r, "\r\n");
 
     if(result)
       return result;
   }
+  return result;
+}
 #endif
 
-  result = Curl_add_timecondition(conn, &req);
-  if(result)
-    return result;
+CURLcode Curl_http_range(struct Curl_easy *data,
+                         Curl_HttpReq httpreq)
+{
+  if(data->state.use_range) {
+    /*
+     * A range is selected. We use different headers whether we're downloading
+     * or uploading and we always let customized headers override our internal
+     * ones if any such are specified.
+     */
+    if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
+       !Curl_checkheaders(data, "Range")) {
+      /* if a line like this was already allocated, free the previous one */
+      free(data->state.aptr.rangeline);
+      data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
+                                           data->state.range);
+    }
+    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
+            !Curl_checkheaders(data, "Content-Range")) {
 
-  result = Curl_add_custom_headers(conn, FALSE, &req);
-  if(result)
-    return result;
+      /* if a line like this was already allocated, free the previous one */
+      free(data->state.aptr.rangeline);
 
-  http->postdata = NULL;  /* nothing to post at this point */
-  Curl_pgrsSetUploadSize(data, -1); /* upload size is unknown atm */
+      if(data->set.set_resume_from < 0) {
+        /* Upload resume was asked for, but we don't know the size of the
+           remote part so we tell the server (and act accordingly) that we
+           upload the whole file (again) */
+        data->state.aptr.rangeline =
+          aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
+                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+                  data->state.infilesize - 1, data->state.infilesize);
 
-  /* If 'authdone' is FALSE, we must not set the write socket index to the
-     Curl_transfer() call below, as we're not ready to actually upload any
-     data yet. */
+      }
+      else if(data->state.resume_from) {
+        /* This is because "resume" was selected */
+        curl_off_t total_expected_size =
+          data->state.resume_from + data->state.infilesize;
+        data->state.aptr.rangeline =
+          aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
+                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+                  data->state.range, total_expected_size-1,
+                  total_expected_size);
+      }
+      else {
+        /* Range was selected and then we just pass the incoming range and
+           append total size */
+        data->state.aptr.rangeline =
+          aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+                  data->state.range, data->state.infilesize);
+      }
+      if(!data->state.aptr.rangeline)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  return CURLE_OK;
+}
 
-  switch(httpreq) {
+CURLcode Curl_http_resume(struct Curl_easy *data,
+                          struct connectdata *conn,
+                          Curl_HttpReq httpreq)
+{
+  if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
+     data->state.resume_from) {
+    /**********************************************************************
+     * Resuming upload in HTTP means that we PUT or POST and that we have
+     * got a resume_from value set. The resume value has already created
+     * a Range: header that will be passed along. We need to "fast forward"
+     * the file the given number of bytes and decrease the assume upload
+     * file size before we continue this venture in the dark lands of HTTP.
+     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
+     *********************************************************************/
 
-  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+    if(data->state.resume_from < 0) {
+      /*
+       * This is meant to get the size of the present remote-file by itself.
+       * We don't support this now. Bail out!
+       */
+      data->state.resume_from = 0;
+    }
 
-    if(conn->bits.authneg)
-      postsize = 0;
-    else
-      postsize = data->state.infilesize;
+    if(data->state.resume_from && !data->state.this_is_a_follow) {
+      /* do we still game? */
 
-    if((postsize != -1) && !data->req.upload_chunky &&
-       (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
-      /* only add Content-Length if not uploading chunked */
-      result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
-                             "\r\n", postsize);
-      if(result)
-        return result;
-    }
+      /* Now, let's read off the proper amount of bytes from the
+         input. */
+      int seekerr = CURL_SEEKFUNC_CANTSEEK;
+      if(conn->seek_func) {
+        Curl_set_in_callback(data, true);
+        seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+                                  SEEK_SET);
+        Curl_set_in_callback(data, false);
+      }
 
-    if(postsize != 0) {
-      result = expect100(data, conn, &req);
-      if(result)
-        return result;
-    }
+      if(seekerr != CURL_SEEKFUNC_OK) {
+        curl_off_t passed = 0;
 
-    /* end of headers */
-    result = Curl_dyn_add(&req, "\r\n");
-    if(result)
-      return result;
+        if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+          failf(data, "Could not seek stream");
+          return CURLE_READ_ERROR;
+        }
+        /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+        do {
+          size_t readthisamountnow =
+            (data->state.resume_from - passed > data->set.buffer_size) ?
+            (size_t)data->set.buffer_size :
+            curlx_sotouz(data->state.resume_from - passed);
 
-    /* set the upload size to the progress meter */
-    Curl_pgrsSetUploadSize(data, postsize);
+          size_t actuallyread =
+            data->state.fread_func(data->state.buffer, 1, readthisamountnow,
+                                   data->state.in);
 
-    /* this sends the buffer and frees all the buffer resources */
-    result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
-                              FIRSTSOCKET);
-    if(result)
-      failf(data, "Failed sending PUT request");
-    else
-      /* prepare for transfer */
-      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
-                          postsize?FIRSTSOCKET:-1);
-    if(result)
-      return result;
-    break;
+          passed += actuallyread;
+          if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+            /* this checks for greater-than only to make sure that the
+               CURL_READFUNC_ABORT return code still aborts */
+            failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
+                  " bytes from the input", passed);
+            return CURLE_READ_ERROR;
+          }
+        } while(passed < data->state.resume_from);
+      }
 
-  case HTTPREQ_POST_FORM:
-  case HTTPREQ_POST_MIME:
-    /* This is form posting using mime data. */
-    if(conn->bits.authneg) {
-      /* nothing to post! */
-      result = Curl_dyn_add(&req, "Content-Length: 0\r\n\r\n");
-      if(result)
-        return result;
+      /* now, decrease the size of the read */
+      if(data->state.infilesize>0) {
+        data->state.infilesize -= data->state.resume_from;
 
-      result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
-                                FIRSTSOCKET);
-      if(result)
-        failf(data, "Failed sending POST request");
-      else
-        /* setup variables for the upcoming transfer */
-        Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
-      break;
+        if(data->state.infilesize <= 0) {
+          failf(data, "File already completely uploaded");
+          return CURLE_PARTIAL_FILE;
+        }
+      }
+      /* we've passed, proceed as normal */
     }
+  }
+  return CURLE_OK;
+}
 
-    data->state.infilesize = postsize = http->postsize;
+CURLcode Curl_http_firstwrite(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              bool *done)
+{
+  struct SingleRequest *k = &data->req;
+  DEBUGASSERT(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP));
+  if(data->req.newurl) {
+    if(conn->bits.close) {
+      /* Abort after the headers if "follow Location" is set
+         and we're set to close anyway. */
+      k->keepon &= ~KEEP_RECV;
+      *done = TRUE;
+      return CURLE_OK;
+    }
+    /* We have a new url to load, but since we want to be able to re-use this
+       connection properly, we read the full response in "ignore more" */
+    k->ignorebody = TRUE;
+    infof(data, "Ignoring the response-body\n");
+  }
+  if(data->state.resume_from && !k->content_range &&
+     (data->state.httpreq == HTTPREQ_GET) &&
+     !k->ignorebody) {
+
+    if(k->size == data->state.resume_from) {
+      /* The resume point is at the end of file, consider this fine even if it
+         doesn't allow resume from here. */
+      infof(data, "The entire document is already downloaded");
+      connclose(conn, "already downloaded");
+      /* Abort download */
+      k->keepon &= ~KEEP_RECV;
+      *done = TRUE;
+      return CURLE_OK;
+    }
 
-    /* We only set Content-Length and allow a custom Content-Length if
-       we don't upload data chunked, as RFC2616 forbids us to set both
-       kinds of headers (Transfer-Encoding: chunked and Content-Length) */
-    if(postsize != -1 && !data->req.upload_chunky &&
-       (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
-      /* we allow replacing this header if not during auth negotiation,
-         although it isn't very wise to actually set your own */
-      result = Curl_dyn_addf(&req,
-                             "Content-Length: %" CURL_FORMAT_CURL_OFF_T
-                             "\r\n", postsize);
-      if(result)
-        return result;
+    /* we wanted to resume a download, although the server doesn't seem to
+     * support this and we did this with a GET (if it wasn't a GET we did a
+     * POST or PUT resume) */
+    failf(data, "HTTP server doesn't seem to support "
+          "byte ranges. Cannot resume.");
+    return CURLE_RANGE_ERROR;
+  }
+
+  if(data->set.timecondition && !data->state.range) {
+    /* A time condition has been set AND no ranges have been requested. This
+       seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
+       action for a HTTP/1.1 client */
+
+    if(!Curl_meets_timecondition(data, k->timeofdoc)) {
+      *done = TRUE;
+      /* We're simulating a http 304 from server so we return
+         what should have been returned from the server */
+      data->info.httpcode = 304;
+      infof(data, "Simulate a HTTP 304 response!\n");
+      /* we abort the transfer before it is completed == we ruin the
+         re-use ability. Close the connection */
+      connclose(conn, "Simulated 304 handling");
+      return CURLE_OK;
     }
+  } /* we have a time condition */
 
-#ifndef CURL_DISABLE_MIME
-    /* Output mime-generated headers. */
-    {
-      struct curl_slist *hdr;
+  return CURLE_OK;
+}
 
-      for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
-        result = Curl_dyn_addf(&req, "%s\r\n", hdr->data);
+#ifndef USE_HYPER
+/*
+ * Curl_http() gets called from the generic multi_do() function when a HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = CURLE_OK;
+  struct HTTP *http;
+  Curl_HttpReq httpreq;
+  const char *te = ""; /* transfer-encoding */
+  const char *request;
+  const char *httpstring;
+  struct dynbuf req;
+  char *altused = NULL;
+  const char *p_accept;      /* Accept: string */
+
+  /* Always consider the DO phase done after this function call, even if there
+     may be parts of the request that are not yet sent, since we can deal with
+     the rest of the request in the PERFORM phase. */
+  *done = TRUE;
+
+  if(conn->transport != TRNSPRT_QUIC) {
+    if(conn->httpversion < 20) { /* unless the connection is re-used and
+                                    already http2 */
+      switch(conn->negnpn) {
+      case CURL_HTTP_VERSION_2:
+        conn->httpversion = 20; /* we know we're on HTTP/2 now */
+
+        result = Curl_http2_switched(data, NULL, 0);
         if(result)
           return result;
-      }
-    }
+        break;
+      case CURL_HTTP_VERSION_1_1:
+        /* continue with HTTP/1.1 when explicitly requested */
+        break;
+      default:
+        /* Check if user wants to use HTTP/2 with clear TCP*/
+#ifdef USE_NGHTTP2
+        if(data->set.httpversion == 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
+               whether or not this setting should apply to HTTP/2 proxies. */
+            infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n");
+            break;
+          }
 #endif
+          DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
+          conn->httpversion = 20;
 
-    /* For really small posts 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(conn, "Expect");
-    if(ptr) {
-      data->state.expect100header =
-        Curl_compareheader(ptr, "Expect:", "100-continue");
+          result = Curl_http2_switched(data, NULL, 0);
+          if(result)
+            return result;
+        }
+#endif
+        break;
+      }
     }
-    else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) {
-      result = expect100(data, conn, &req);
+    else {
+      /* prepare for a http2 request */
+      result = Curl_http2_setup(data, conn);
       if(result)
         return result;
     }
-    else
-      data->state.expect100header = FALSE;
+  }
+  http = data->req.p.http;
+  DEBUGASSERT(http);
 
-    /* make the request end in a true CRLF */
-    result = Curl_dyn_add(&req, "\r\n");
-    if(result)
-      return result;
+  result = Curl_http_host(data, conn);
+  if(result)
+    return result;
 
-    /* set the upload size to the progress meter */
-    Curl_pgrsSetUploadSize(data, postsize);
+  result = Curl_http_useragent(data);
+  if(result)
+    return result;
 
-    /* Read from mime structure. */
-    data->state.fread_func = (curl_read_callback) Curl_mime_read;
-    data->state.in = (void *) http->sendit;
-    http->sending = HTTPSEND_BODY;
+  Curl_http_method(data, conn, &request, &httpreq);
 
-    /* this sends the buffer and frees all the buffer resources */
-    result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
-                              FIRSTSOCKET);
-    if(result)
-      failf(data, "Failed sending POST request");
-    else
-      /* prepare for transfer */
-      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
-                          postsize?FIRSTSOCKET:-1);
+  /* setup the authentication headers */
+  {
+    char *pq = NULL;
+    if(data->state.up.query) {
+      pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
+      if(!pq)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    result = Curl_http_output_auth(data, conn, request, httpreq,
+                                   (pq ? pq : data->state.up.path), FALSE);
+    free(pq);
     if(result)
       return result;
+  }
 
-    break;
+  Curl_safefree(data->state.aptr.ref);
+  if(data->change.referer && !Curl_checkheaders(data, "Referer")) {
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+    if(!data->state.aptr.ref)
+      return CURLE_OUT_OF_MEMORY;
+  }
 
-  case HTTPREQ_POST:
-    /* this is the simple POST, using x-www-form-urlencoded style */
+  if(!Curl_checkheaders(data, "Accept-Encoding") &&
+     data->set.str[STRING_ENCODING]) {
+    Curl_safefree(data->state.aptr.accept_encoding);
+    data->state.aptr.accept_encoding =
+      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+    if(!data->state.aptr.accept_encoding)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    Curl_safefree(data->state.aptr.accept_encoding);
+    data->state.aptr.accept_encoding = NULL;
+  }
 
-    if(conn->bits.authneg)
-      postsize = 0;
-    else
-      /* the size of the post body */
-      postsize = data->state.infilesize;
+#ifdef HAVE_LIBZ
+  /* we only consider transfer-encoding magic if libz support is built-in */
 
-    /* We only set Content-Length and allow a custom Content-Length if
-       we don't upload data chunked, as RFC2616 forbids us to set both
-       kinds of headers (Transfer-Encoding: chunked and Content-Length) */
-    if((postsize != -1) && !data->req.upload_chunky &&
-       (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
-      /* we allow replacing this header if not during auth negotiation,
-         although it isn't very wise to actually set your own */
-      result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
-                             "\r\n", postsize);
-      if(result)
-        return result;
-    }
+  if(!Curl_checkheaders(data, "TE") &&
+     data->set.http_transfer_encoding) {
+    /* When we are to insert a TE: header in the request, we must also insert
+       TE in a Connection: header, so we need to merge the custom provided
+       Connection: header and prevent the original to get sent. Note that if
+       the user has inserted his/her own TE: header we don't do this magic
+       but then assume that the user will handle it all! */
+    char *cptr = Curl_checkheaders(data, "Connection");
+#define TE_HEADER "TE: gzip\r\n"
 
-    if(!Curl_checkheaders(conn, "Content-Type")) {
-      result = Curl_dyn_add(&req, "Content-Type: application/"
-                            "x-www-form-urlencoded\r\n");
-      if(result)
-        return result;
-    }
+    Curl_safefree(data->state.aptr.te);
 
-    /* For really small posts 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(conn, "Expect");
-    if(ptr) {
-      data->state.expect100header =
-        Curl_compareheader(ptr, "Expect:", "100-continue");
-    }
-    else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) {
-      result = expect100(data, conn, &req);
-      if(result)
-        return result;
+    if(cptr) {
+      cptr = Curl_copy_header_value(cptr);
+      if(!cptr)
+        return CURLE_OUT_OF_MEMORY;
     }
-    else
-      data->state.expect100header = FALSE;
-
-    if(data->set.postfields) {
-
-      /* In HTTP2, we send request body in DATA frame regardless of
-         its size. */
-      if(conn->httpversion != 20 &&
-         !data->state.expect100header &&
-         (postsize < MAX_INITIAL_POST_SIZE)) {
-        /* if we don't use expect: 100  AND
-           postsize is less than MAX_INITIAL_POST_SIZE
 
-           then append the post data to the HTTP request header. This limit
-           is no magic limit but only set to prevent really huge POSTs to
-           get the data duplicated with malloc() and family. */
+    /* Create the (updated) Connection: header */
+    data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
+                                cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
 
-        /* end of headers! */
-        result = Curl_dyn_add(&req, "\r\n");
-        if(result)
-          return result;
+    free(cptr);
+    if(!data->state.aptr.te)
+      return CURLE_OUT_OF_MEMORY;
+  }
+#endif
 
-        if(!data->req.upload_chunky) {
-          /* We're not sending it 'chunked', append it to the request
-             already now to reduce the number if send() calls */
-          result = Curl_dyn_addn(&req, data->set.postfields,
-                                 (size_t)postsize);
-          included_body = postsize;
-        }
-        else {
-          if(postsize) {
-            /* Append the POST data chunky-style */
-            result = Curl_dyn_addf(&req, "%x\r\n", (int)postsize);
-            if(!result) {
-              result = Curl_dyn_addn(&req, data->set.postfields,
-                                     (size_t)postsize);
-              if(!result)
-                result = Curl_dyn_add(&req, "\r\n");
-              included_body = postsize + 2;
-            }
-          }
-          if(!result)
-            result = Curl_dyn_add(&req, "\x30\x0d\x0a\x0d\x0a");
-          /* 0  CR  LF  CR  LF */
-          included_body += 5;
-        }
-        if(result)
-          return result;
-        /* Make sure the progress information is accurate */
-        Curl_pgrsSetUploadSize(data, postsize);
-      }
-      else {
-        /* A huge POST coming up, do data separate from the request */
-        http->postsize = postsize;
-        http->postdata = data->set.postfields;
+  result = Curl_http_body(data, conn, httpreq, &te);
+  if(result)
+    return result;
 
-        http->sending = HTTPSEND_BODY;
+  p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
 
-        data->state.fread_func = (curl_read_callback)readmoredata;
-        data->state.in = (void *)conn;
+  result = Curl_http_resume(data, conn, httpreq);
+  if(result)
+    return result;
 
-        /* set the upload size to the progress meter */
-        Curl_pgrsSetUploadSize(data, http->postsize);
+  result = Curl_http_range(data, httpreq);
+  if(result)
+    return result;
 
-        /* end of headers! */
-        result = Curl_dyn_add(&req, "\r\n");
-        if(result)
-          return result;
-      }
-    }
-    else {
-       /* end of headers! */
-      result = Curl_dyn_add(&req, "\r\n");
-      if(result)
-        return result;
+  httpstring = get_http_string(data, conn);
 
-      if(data->req.upload_chunky && conn->bits.authneg) {
-        /* Chunky upload is selected and we're negotiating auth still, send
-           end-of-data only */
-        result = Curl_dyn_add(&req, (char *)"\x30\x0d\x0a\x0d\x0a");
-        /* 0  CR  LF  CR  LF */
-        if(result)
-          return result;
-      }
+  /* initialize a dynamic send-buffer */
+  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
 
-      else if(data->state.infilesize) {
-        /* set the upload size to the progress meter */
-        Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
+  /* add the main request stuff */
+  /* GET/HEAD/POST/PUT */
+  result = Curl_dyn_addf(&req, "%s ", request);
+  if(!result)
+    result = Curl_http_target(data, conn, &req);
+  if(result) {
+    Curl_dyn_free(&req);
+    return result;
+  }
 
-        /* set the pointer to mark that we will send the post body using the
-           read callback, but only if we're not in authenticate
-           negotiation  */
-        if(!conn->bits.authneg) {
-          http->postdata = (char *)&http->postdata;
-          http->postsize = postsize;
-        }
-      }
+#ifndef CURL_DISABLE_ALTSVC
+  if(conn->bits.altused && !Curl_checkheaders(data, "Alt-Used")) {
+    altused = aprintf("Alt-Used: %s:%d\r\n",
+                      conn->conn_to_host.name, conn->conn_to_port);
+    if(!altused) {
+      Curl_dyn_free(&req);
+      return CURLE_OUT_OF_MEMORY;
     }
-    /* issue the request */
-    result = Curl_buffer_send(&req, conn, &data->info.request_size,
-                              (size_t)included_body, FIRSTSOCKET);
+  }
+#endif
+  result =
+    Curl_dyn_addf(&req,
+                  " HTTP/%s\r\n" /* HTTP version */
+                  "%s" /* host */
+                  "%s" /* proxyuserpwd */
+                  "%s" /* userpwd */
+                  "%s" /* range */
+                  "%s" /* user agent */
+                  "%s" /* accept */
+                  "%s" /* TE: */
+                  "%s" /* accept-encoding */
+                  "%s" /* referer */
+                  "%s" /* Proxy-Connection */
+                  "%s" /* transfer-encoding */
+                  "%s",/* Alt-Used */
 
-    if(result)
-      failf(data, "Failed sending HTTP POST request");
-    else
-      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
-                          http->postdata?FIRSTSOCKET:-1);
-    break;
+                  httpstring,
+                  (data->state.aptr.host?data->state.aptr.host:""),
+                  data->state.aptr.proxyuserpwd?
+                  data->state.aptr.proxyuserpwd:"",
+                  data->state.aptr.userpwd?data->state.aptr.userpwd:"",
+                  (data->state.use_range && data->state.aptr.rangeline)?
+                  data->state.aptr.rangeline:"",
+                  (data->set.str[STRING_USERAGENT] &&
+                   *data->set.str[STRING_USERAGENT] &&
+                   data->state.aptr.uagent)?
+                  data->state.aptr.uagent:"",
+                  p_accept?p_accept:"",
+                  data->state.aptr.te?data->state.aptr.te:"",
+                  (data->set.str[STRING_ENCODING] &&
+                   *data->set.str[STRING_ENCODING] &&
+                   data->state.aptr.accept_encoding)?
+                  data->state.aptr.accept_encoding:"",
+                  (data->change.referer && data->state.aptr.ref)?
+                  data->state.aptr.ref:"" /* Referer: <data> */,
+#ifndef CURL_DISABLE_PROXY
+                  (conn->bits.httpproxy &&
+                   !conn->bits.tunnel_proxy &&
+                   !Curl_checkheaders(data, "Proxy-Connection") &&
+                   !Curl_checkProxyheaders(data, conn, "Proxy-Connection"))?
+                  "Proxy-Connection: Keep-Alive\r\n":"",
+#else
+                  "",
+#endif
+                  te,
+                  altused ? altused : ""
+      );
+
+  /* clear userpwd and proxyuserpwd to avoid re-using old credentials
+   * from re-used connections */
+  Curl_safefree(data->state.aptr.userpwd);
+  Curl_safefree(data->state.aptr.proxyuserpwd);
+  free(altused);
 
-  default:
-    result = Curl_dyn_add(&req, "\r\n");
-    if(result)
+  if(result) {
+    Curl_dyn_free(&req);
+    return result;
+  }
+
+  if(!(conn->handler->flags&PROTOPT_SSL) &&
+     conn->httpversion != 20 &&
+     (data->set.httpversion == CURL_HTTP_VERSION_2)) {
+    /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
+       over SSL */
+    result = Curl_http2_request_upgrade(&req, conn);
+    if(result) {
+      Curl_dyn_free(&req);
       return result;
+    }
+  }
 
-    /* issue the request */
-    result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
-                              FIRSTSOCKET);
+  result = Curl_http_cookies(data, conn, &req);
+  if(!result)
+    result = Curl_add_timecondition(data, &req);
+  if(!result)
+    result = Curl_add_custom_headers(data, FALSE, &req);
 
-    if(result)
-      failf(data, "Failed sending HTTP request");
-    else
-      /* HTTP GET/HEAD download: */
-      Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+  if(!result) {
+    http->postdata = NULL;  /* nothing to post at this point */
+    if((httpreq == HTTPREQ_GET) ||
+       (httpreq == HTTPREQ_HEAD))
+      Curl_pgrsSetUploadSize(data, 0); /* nothing */
+
+    /* bodysend takes ownership of the 'req' memory on success */
+    result = Curl_http_bodysend(data, conn, &req, httpreq);
   }
-  if(result)
+  if(result) {
+    Curl_dyn_free(&req);
     return result;
-  if(!postsize && (http->sending != HTTPSEND_REQUEST))
+  }
+
+  if((http->postsize > -1) &&
+     (http->postsize <= data->req.writebytecount) &&
+     (http->sending != HTTPSEND_REQUEST))
     data->req.upload_done = TRUE;
 
   if(data->req.writebytecount) {
     /* if a request-body has been sent off, we make sure this progress is noted
        properly */
     Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
 
-    if(data->req.writebytecount >= postsize) {
+    if(!http->postsize) {
       /* already sent the entire request body, mark the "upload" as
          complete */
       infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
             " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n",
-            data->req.writebytecount, postsize);
+            data->req.writebytecount, http->postsize);
       data->req.upload_done = TRUE;
       data->req.keepon &= ~KEEP_SEND; /* we're done writing */
       data->req.exp100 = EXP100_SEND_DATA; /* already sent */
@@ -2997,6 +3215,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   return result;
 }
 
+#endif /* USE_HYPER */
+
 typedef enum {
   STATUS_UNKNOWN, /* not enough data to tell yet */
   STATUS_DONE, /* a status line was read */
@@ -3101,41 +3321,383 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
   return checkhttpprefix(data, s, len);
 }
 
-static void print_http_error(struct Curl_easy *data)
+/*
+ * Curl_http_header() parses a single response header.
+ */
+CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
+                          char *headp)
 {
+  CURLcode result;
   struct SingleRequest *k = &data->req;
-  char *beg = Curl_dyn_ptr(&data->state.headerb);
-
-  /* make sure that data->req.p points to the HTTP status line */
-  if(!strncmp(beg, "HTTP", 4)) {
-
-    /* skip to HTTP status code */
-    beg = strchr(beg, ' ');
-    if(beg && *++beg) {
-
-      /* find trailing CR */
-      char end_char = '\r';
-      char *end = strchr(beg, end_char);
-      if(!end) {
-        /* try to find LF (workaround for non-compliant HTTP servers) */
-        end_char = '\n';
-        end = strchr(beg, end_char);
+  /* Check for Content-Length: header lines to get size */
+  if(!k->http_bodyless &&
+     !data->set.ignorecl && checkprefix("Content-Length:", headp)) {
+    curl_off_t contentlength;
+    CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength);
+
+    if(offt == CURL_OFFT_OK) {
+      if(data->set.max_filesize &&
+         contentlength > data->set.max_filesize) {
+        failf(data, "Maximum file size exceeded");
+        return CURLE_FILESIZE_EXCEEDED;
+      }
+      k->size = contentlength;
+      k->maxdownload = k->size;
+      /* we set the progress download size already at this point
+         just to make it easier for apps/callbacks to extract this
+         info as soon as possible */
+      Curl_pgrsSetDownloadSize(data, k->size);
+    }
+    else if(offt == CURL_OFFT_FLOW) {
+      /* out of range */
+      if(data->set.max_filesize) {
+        failf(data, "Maximum file size exceeded");
+        return CURLE_FILESIZE_EXCEEDED;
+      }
+      streamclose(conn, "overflow content-length");
+      infof(data, "Overflow Content-Length: value!\n");
+    }
+    else {
+      /* negative or just rubbish - bad HTTP */
+      failf(data, "Invalid Content-Length: value");
+      return CURLE_WEIRD_SERVER_REPLY;
+    }
+  }
+  /* check for Content-Type: header lines to get the MIME-type */
+  else if(checkprefix("Content-Type:", headp)) {
+    char *contenttype = Curl_copy_header_value(headp);
+    if(!contenttype)
+      return CURLE_OUT_OF_MEMORY;
+    if(!*contenttype)
+      /* ignore empty data */
+      free(contenttype);
+    else {
+      Curl_safefree(data->info.contenttype);
+      data->info.contenttype = contenttype;
+    }
+  }
+#ifndef CURL_DISABLE_PROXY
+  else if((conn->httpversion == 10) &&
+          conn->bits.httpproxy &&
+          Curl_compareheader(headp, "Proxy-Connection:", "keep-alive")) {
+    /*
+     * When a HTTP/1.0 reply comes when using a proxy, the
+     * 'Proxy-Connection: keep-alive' line tells us the
+     * connection will be kept alive for our pleasure.
+     * Default action for 1.0 is to close.
+     */
+    connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
+    infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
+  }
+  else if((conn->httpversion == 11) &&
+          conn->bits.httpproxy &&
+          Curl_compareheader(headp, "Proxy-Connection:", "close")) {
+    /*
+     * We get a HTTP/1.1 response from a proxy and it says it'll
+     * close down after this transfer.
+     */
+    connclose(conn, "Proxy-Connection: asked to close after done");
+    infof(data, "HTTP/1.1 proxy connection set close!\n");
+  }
+#endif
+  else if((conn->httpversion == 10) &&
+          Curl_compareheader(headp, "Connection:", "keep-alive")) {
+    /*
+     * A HTTP/1.0 reply with the 'Connection: keep-alive' line
+     * tells us the connection will be kept alive for our
+     * pleasure.  Default action for 1.0 is to close.
+     *
+     * [RFC2068, section 19.7.1] */
+    connkeep(conn, "Connection keep-alive");
+    infof(data, "HTTP/1.0 connection set to keep alive!\n");
+  }
+  else if(Curl_compareheader(headp, "Connection:", "close")) {
+    /*
+     * [RFC 2616, section 8.1.2.1]
+     * "Connection: close" is HTTP/1.1 language and means that
+     * the connection will close when this request has been
+     * served.
+     */
+    streamclose(conn, "Connection: close used");
+  }
+  else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) {
+    /* One or more encodings. We check for chunked and/or a compression
+       algorithm. */
+    /*
+     * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
+     * means that the server will send a series of "chunks". Each
+     * chunk starts with line with info (including size of the
+     * coming block) (terminated with CRLF), then a block of data
+     * with the previously mentioned size. There can be any amount
+     * of chunks, and a chunk-data set to zero signals the
+     * end-of-chunks. */
+
+    result = Curl_build_unencoding_stack(data, headp + 18, TRUE);
+    if(result)
+      return result;
+  }
+  else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) &&
+          data->set.str[STRING_ENCODING]) {
+    /*
+     * Process Content-Encoding. Look for the values: identity,
+     * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
+     * x-compress are the same as gzip and compress. (Sec 3.5 RFC
+     * 2616). zlib cannot handle compress.  However, errors are
+     * handled further down when the response body is processed
+     */
+    result = Curl_build_unencoding_stack(data, headp + 17, FALSE);
+    if(result)
+      return result;
+  }
+  else if(checkprefix("Retry-After:", headp)) {
+    /* Retry-After = HTTP-date / delay-seconds */
+    curl_off_t retry_after = 0; /* zero for unknown or "now" */
+    time_t date = Curl_getdate_capped(&headp[12]);
+    if(-1 == date) {
+      /* not a date, try it as a decimal number */
+      (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after);
+    }
+    else
+      /* convert date to number of seconds into the future */
+      retry_after = date - time(NULL);
+    data->info.retry_after = retry_after; /* store it */
+  }
+  else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) {
+    /* Content-Range: bytes [num]-
+       Content-Range: bytes: [num]-
+       Content-Range: [num]-
+       Content-Range: [asterisk]/[total]
+
+       The second format was added since Sun's webserver
+       JavaWebServer/1.1.1 obviously sends the header this way!
+       The third added since some servers use that!
+       The forth means the requested range was unsatisfied.
+    */
+
+    char *ptr = headp + 14;
+
+    /* Move forward until first digit or asterisk */
+    while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
+      ptr++;
+
+    /* if it truly stopped on a digit */
+    if(ISDIGIT(*ptr)) {
+      if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
+        if(data->state.resume_from == k->offset)
+          /* we asked for a resume and we got it */
+          k->content_range = TRUE;
       }
+    }
+    else
+      data->state.resume_from = 0; /* get everything */
+  }
+#if !defined(CURL_DISABLE_COOKIES)
+  else if(data->cookies && data->state.cookie_engine &&
+          checkprefix("Set-Cookie:", headp)) {
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+                    CURL_LOCK_ACCESS_SINGLE);
+    Curl_cookie_add(data,
+                    data->cookies, TRUE, FALSE, headp + 11,
+                    /* If there is a custom-set Host: name, use it
+                       here, or else use real peer host name. */
+                    data->state.aptr.cookiehost?
+                    data->state.aptr.cookiehost:conn->host.name,
+                    data->state.up.path,
+                    (conn->handler->protocol&CURLPROTO_HTTPS)?
+                    TRUE:FALSE);
+    Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+  }
+#endif
+  else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) &&
+          (data->set.timecondition || data->set.get_filetime) ) {
+    k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:"));
+    if(data->set.get_filetime)
+      data->info.filetime = k->timeofdoc;
+  }
+  else if((checkprefix("WWW-Authenticate:", headp) &&
+           (401 == k->httpcode)) ||
+          (checkprefix("Proxy-authenticate:", headp) &&
+           (407 == k->httpcode))) {
+
+    bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
+    char *auth = Curl_copy_header_value(headp);
+    if(!auth)
+      return CURLE_OUT_OF_MEMORY;
+
+    result = Curl_http_input_auth(data, proxy, auth);
+
+    free(auth);
+
+    if(result)
+      return result;
+  }
+#ifdef USE_SPNEGO
+  else if(checkprefix("Persistent-Auth", headp)) {
+    struct negotiatedata *negdata = &conn->negotiate;
+    struct auth *authp = &data->state.authhost;
+    if(authp->picked == CURLAUTH_NEGOTIATE) {
+      char *persistentauth = Curl_copy_header_value(headp);
+      if(!persistentauth)
+        return CURLE_OUT_OF_MEMORY;
+      negdata->noauthpersist = checkprefix("false", persistentauth)?
+        TRUE:FALSE;
+      negdata->havenoauthpersist = TRUE;
+      infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
+            negdata->noauthpersist, persistentauth);
+      free(persistentauth);
+    }
+  }
+#endif
+  else if((k->httpcode >= 300 && k->httpcode < 400) &&
+          checkprefix("Location:", headp) &&
+          !data->req.location) {
+    /* this is the URL that the server advises us to use instead */
+    char *location = Curl_copy_header_value(headp);
+    if(!location)
+      return CURLE_OUT_OF_MEMORY;
+    if(!*location)
+      /* ignore empty data */
+      free(location);
+    else {
+      data->req.location = location;
 
-      if(end) {
-        /* temporarily replace CR or LF by NUL and print the error message */
-        *end = '\0';
-        failf(data, "The requested URL returned error: %s", beg);
+      if(data->set.http_follow_location) {
+        DEBUGASSERT(!data->req.newurl);
+        data->req.newurl = strdup(data->req.location); /* clone */
+        if(!data->req.newurl)
+          return CURLE_OUT_OF_MEMORY;
 
-        /* restore the previously replaced CR or LF */
-        *end = end_char;
-        return;
+        /* some cases of POST and PUT etc needs to rewind the data
+           stream at this point */
+        result = http_perhapsrewind(data, conn);
+        if(result)
+          return result;
       }
     }
   }
 
-  /* fall-back to printing the HTTP status code only */
-  failf(data, "The requested URL returned error: %d", k->httpcode);
+#ifdef USE_HSTS
+  /* If enabled, the header is incoming and this is over HTTPS */
+  else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) &&
+          (conn->handler->flags & PROTOPT_SSL)) {
+    CURLcode check =
+      Curl_hsts_parse(data->hsts, data->state.up.hostname,
+                      &headp[ sizeof("Strict-Transport-Security:") -1 ]);
+    if(check)
+      infof(data, "Illegal STS header skipped\n");
+#ifdef DEBUGBUILD
+    else
+      infof(data, "Parsed STS header fine (%zu entries)\n",
+            data->hsts->list.size);
+#endif
+  }
+#endif
+#ifndef CURL_DISABLE_ALTSVC
+  /* If enabled, the header is incoming and this is over HTTPS */
+  else if(data->asi && checkprefix("Alt-Svc:", headp) &&
+          ((conn->handler->flags & PROTOPT_SSL) ||
+#ifdef CURLDEBUG
+           /* allow debug builds to circumvent the HTTPS restriction */
+           getenv("CURL_ALTSVC_HTTP")
+#else
+           0
+#endif
+            )) {
+    /* the ALPN of the current request */
+    enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
+    result = Curl_altsvc_parse(data, data->asi,
+                               &headp[ strlen("Alt-Svc:") ],
+                               id, conn->host.name,
+                               curlx_uitous(conn->remote_port));
+    if(result)
+      return result;
+  }
+#endif
+  else if(conn->handler->protocol & CURLPROTO_RTSP) {
+    result = Curl_rtsp_parseheader(data, headp);
+    if(result)
+      return result;
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Called after the first HTTP response line (the status line) has been
+ * received and parsed.
+ */
+
+CURLcode Curl_http_statusline(struct Curl_easy *data,
+                              struct connectdata *conn)
+{
+  struct SingleRequest *k = &data->req;
+  data->info.httpcode = k->httpcode;
+
+  data->info.httpversion = conn->httpversion;
+  if(!data->state.httpversion ||
+     data->state.httpversion > conn->httpversion)
+    /* store the lowest server version we encounter */
+    data->state.httpversion = conn->httpversion;
+
+  /*
+   * This code executes as part of processing the header.  As a
+   * result, it's not totally clear how to interpret the
+   * response code yet as that depends on what other headers may
+   * be present.  401 and 407 may be errors, but may be OK
+   * depending on how authentication is working.  Other codes
+   * are definitely errors, so give up here.
+   */
+  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
+     k->httpcode == 416) {
+    /* "Requested Range Not Satisfiable", just proceed and
+       pretend this is no error */
+    k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
+  }
+
+  if(conn->httpversion == 10) {
+    /* Default action for HTTP/1.0 must be to close, unless
+       we get one of those fancy headers that tell us the
+       server keeps it open for us! */
+    infof(data, "HTTP 1.0, assume close after body\n");
+    connclose(conn, "HTTP/1.0 close after body");
+  }
+  else if(conn->httpversion == 20 ||
+          (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
+    DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
+    /* HTTP/2 cannot avoid multiplexing since it is a core functionality
+       of the protocol */
+    conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+  }
+  else if(conn->httpversion >= 11 &&
+          !conn->bits.close) {
+    /* If HTTP version is >= 1.1 and connection is persistent */
+    DEBUGF(infof(data,
+                 "HTTP 1.1 or later with persistent connection\n"));
+  }
+
+  k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
+  switch(k->httpcode) {
+  case 304:
+    /* (quote from RFC2616, section 10.3.5): The 304 response
+     * MUST NOT contain a message-body, and thus is always
+     * terminated by the first empty line after the header
+     * fields.  */
+    if(data->set.timecondition)
+      data->info.timecond = TRUE;
+    /* FALLTHROUGH */
+  case 204:
+    /* (quote from RFC2616, section 10.2.5): The server has
+     * fulfilled the request but does not need to return an
+     * entity-body ... The 204 response MUST NOT include a
+     * message-body, and thus is always terminated by the first
+     * empty line after the header fields. */
+    k->size = 0;
+    k->maxdownload = 0;
+    k->http_bodyless = TRUE;
+    break;
+  default:
+    break;
+  }
+  return CURLE_OK;
 }
 
 /*
@@ -3186,7 +3748,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           k->badheader = HEADER_ALLBAD;
           streamclose(conn, "bad HTTP: No end-of-message indicator");
           if(!data->set.http09_allowed) {
-            failf(data, "Received HTTP/0.9 when not allowed\n");
+            failf(data, "Received HTTP/0.9 when not allowed");
             return CURLE_UNSUPPORTED_PROTOCOL;
           }
           break;
@@ -3221,7 +3783,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         streamclose(conn, "bad HTTP: No end-of-message indicator");
         /* this is not the beginning of a protocol first header line */
         if(!data->set.http09_allowed) {
-          failf(data, "Received HTTP/0.9 when not allowed\n");
+          failf(data, "Received HTTP/0.9 when not allowed");
           return CURLE_UNSUPPORTED_PROTOCOL;
         }
         k->header = FALSE;
@@ -3296,7 +3858,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 
             /* switch to http2 now. The bytes after response headers
                are also processed here, otherwise they are lost. */
-            result = Curl_http2_switched(conn, k->str, *nread);
+            result = Curl_http2_switched(data, k->str, *nread);
             if(result)
               return result;
             *nread = 0;
@@ -3362,15 +3924,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         conn->proxy_negotiate_state = GSS_AUTHSUCC;
       }
 #endif
-      /*
-       * When all the headers have been parsed, see if we should give
-       * up and return an error.
-       */
-      if(http_should_fail(conn)) {
-        failf(data, "The requested URL returned error: %d",
-              k->httpcode);
-        return CURLE_HTTP_RETURNED_ERROR;
-      }
 
       /* now, only output this if the header AND body are requested:
        */
@@ -3379,7 +3932,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         writetype |= CLIENTWRITE_BODY;
 
       headerlen = Curl_dyn_len(&data->state.headerb);
-      result = Curl_client_write(conn, writetype,
+      result = Curl_client_write(data, writetype,
                                  Curl_dyn_ptr(&data->state.headerb),
                                  headerlen);
       if(result)
@@ -3388,13 +3941,23 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
       data->info.header_size += (long)headerlen;
       data->req.headerbytecount += (long)headerlen;
 
+      /*
+       * When all the headers have been parsed, see if we should give
+       * up and return an error.
+       */
+      if(http_should_fail(data)) {
+        failf(data, "The requested URL returned error: %d",
+              k->httpcode);
+        return CURLE_HTTP_RETURNED_ERROR;
+      }
+
       data->req.deductheadercount =
         (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
 
       /* Curl_http_auth_act() checks what authentication methods
        * that are available and decides which one (if any) to
        * use. It will set 'newurl' if an auth method was picked. */
-      result = Curl_http_auth_act(conn);
+      result = Curl_http_auth_act(data);
 
       if(result)
         return result;
@@ -3432,8 +3995,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                 infof(data, "Got 417 while waiting for a 100\n");
                 data->state.disableexpect = TRUE;
                 DEBUGASSERT(!data->req.newurl);
-                data->req.newurl = strdup(conn->data->change.url);
-                Curl_done_sending(conn, k);
+                data->req.newurl = strdup(data->change.url);
+                Curl_done_sending(data, k);
               }
               else if(data->set.http_keep_sending_on_error) {
                 infof(data, "HTTP error before end of send, keep sending\n");
@@ -3445,7 +4008,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
               else {
                 infof(data, "HTTP error before end of send, stop sending\n");
                 streamclose(conn, "Stop sending data before everything sent");
-                result = Curl_done_sending(conn, k);
+                result = Curl_done_sending(data, k);
                 if(result)
                   return result;
                 k->upload_done = TRUE;
@@ -3531,10 +4094,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           k->keepon &= ~KEEP_RECV;
         }
 
-        if(data->set.verbose)
-          Curl_debug(data, CURLINFO_HEADER_IN,
-                     str_start, headerlen);
-        break;          /* exit header line loop */
+        Curl_debug(data, CURLINFO_HEADER_IN, str_start, headerlen);
+        break; /* exit header line loop */
       }
 
       /* We continue reading headers, reset the line-based header */
@@ -3655,83 +4216,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
       }
 
       if(nc) {
-        data->info.httpcode = k->httpcode;
-
-        data->info.httpversion = conn->httpversion;
-        if(!data->state.httpversion ||
-           data->state.httpversion > conn->httpversion)
-          /* store the lowest server version we encounter */
-          data->state.httpversion = conn->httpversion;
-
-        /*
-         * This code executes as part of processing the header.  As a
-         * result, it's not totally clear how to interpret the
-         * response code yet as that depends on what other headers may
-         * be present.  401 and 407 may be errors, but may be OK
-         * depending on how authentication is working.  Other codes
-         * are definitely errors, so give up here.
-         */
-        if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
-             k->httpcode == 416) {
-          /* "Requested Range Not Satisfiable", just proceed and
-             pretend this is no error */
-          k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
-        }
-        else if(data->set.http_fail_on_error && (k->httpcode >= 400) &&
-                ((k->httpcode != 401) || !conn->bits.user_passwd)
-#ifndef CURL_DISABLE_PROXY
-                && ((k->httpcode != 407) || !conn->bits.proxy_user_passwd)
-#endif
-          ) {
-          /* serious error, go home! */
-          print_http_error(data);
-          return CURLE_HTTP_RETURNED_ERROR;
-        }
-
-        if(conn->httpversion == 10) {
-          /* Default action for HTTP/1.0 must be to close, unless
-             we get one of those fancy headers that tell us the
-             server keeps it open for us! */
-          infof(data, "HTTP 1.0, assume close after body\n");
-          connclose(conn, "HTTP/1.0 close after body");
-        }
-        else if(conn->httpversion == 20 ||
-                (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
-          DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
-          /* HTTP/2 cannot avoid multiplexing since it is a core functionality
-             of the protocol */
-          conn->bundle->multiuse = BUNDLE_MULTIPLEX;
-        }
-        else if(conn->httpversion >= 11 &&
-                !conn->bits.close) {
-          /* If HTTP version is >= 1.1 and connection is persistent */
-          DEBUGF(infof(data,
-                       "HTTP 1.1 or later with persistent connection\n"));
-        }
-
-        k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
-        switch(k->httpcode) {
-        case 304:
-          /* (quote from RFC2616, section 10.3.5): The 304 response
-           * MUST NOT contain a message-body, and thus is always
-           * terminated by the first empty line after the header
-           * fields.  */
-          if(data->set.timecondition)
-            data->info.timecond = TRUE;
-          /* FALLTHROUGH */
-        case 204:
-          /* (quote from RFC2616, section 10.2.5): The server has
-           * fulfilled the request but does not need to return an
-           * entity-body ... The 204 response MUST NOT include a
-           * message-body, and thus is always terminated by the first
-           * empty line after the header fields. */
-          k->size = 0;
-          k->maxdownload = 0;
-          k->http_bodyless = TRUE;
-          break;
-        default:
-          break;
-        }
+        result = Curl_http_statusline(data, conn);
+        if(result)
+          return result;
       }
       else {
         k->header = FALSE;   /* this is not a header line */
@@ -3744,278 +4231,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     if(result)
       return result;
 
-    /* Check for Content-Length: header lines to get size */
-    if(!k->http_bodyless &&
-       !data->set.ignorecl && checkprefix("Content-Length:", headp)) {
-      curl_off_t contentlength;
-      CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength);
-
-      if(offt == CURL_OFFT_OK) {
-        if(data->set.max_filesize &&
-           contentlength > data->set.max_filesize) {
-          failf(data, "Maximum file size exceeded");
-          return CURLE_FILESIZE_EXCEEDED;
-        }
-        k->size = contentlength;
-        k->maxdownload = k->size;
-        /* we set the progress download size already at this point
-           just to make it easier for apps/callbacks to extract this
-           info as soon as possible */
-        Curl_pgrsSetDownloadSize(data, k->size);
-      }
-      else if(offt == CURL_OFFT_FLOW) {
-        /* out of range */
-        if(data->set.max_filesize) {
-          failf(data, "Maximum file size exceeded");
-          return CURLE_FILESIZE_EXCEEDED;
-        }
-        streamclose(conn, "overflow content-length");
-        infof(data, "Overflow Content-Length: value!\n");
-      }
-      else {
-        /* negative or just rubbish - bad HTTP */
-        failf(data, "Invalid Content-Length: value");
-        return CURLE_WEIRD_SERVER_REPLY;
-      }
-    }
-    /* check for Content-Type: header lines to get the MIME-type */
-    else if(checkprefix("Content-Type:", headp)) {
-      char *contenttype = Curl_copy_header_value(headp);
-      if(!contenttype)
-        return CURLE_OUT_OF_MEMORY;
-      if(!*contenttype)
-        /* ignore empty data */
-        free(contenttype);
-      else {
-        Curl_safefree(data->info.contenttype);
-        data->info.contenttype = contenttype;
-      }
-    }
-#ifndef CURL_DISABLE_PROXY
-    else if((conn->httpversion == 10) &&
-            conn->bits.httpproxy &&
-            Curl_compareheader(headp, "Proxy-Connection:", "keep-alive")) {
-      /*
-       * When a HTTP/1.0 reply comes when using a proxy, the
-       * 'Proxy-Connection: keep-alive' line tells us the
-       * connection will be kept alive for our pleasure.
-       * Default action for 1.0 is to close.
-       */
-      connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
-      infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
-    }
-    else if((conn->httpversion == 11) &&
-            conn->bits.httpproxy &&
-            Curl_compareheader(headp, "Proxy-Connection:", "close")) {
-      /*
-       * We get a HTTP/1.1 response from a proxy and it says it'll
-       * close down after this transfer.
-       */
-      connclose(conn, "Proxy-Connection: asked to close after done");
-      infof(data, "HTTP/1.1 proxy connection set close!\n");
-    }
-#endif
-    else if((conn->httpversion == 10) &&
-            Curl_compareheader(headp, "Connection:", "keep-alive")) {
-      /*
-       * A HTTP/1.0 reply with the 'Connection: keep-alive' line
-       * tells us the connection will be kept alive for our
-       * pleasure.  Default action for 1.0 is to close.
-       *
-       * [RFC2068, section 19.7.1] */
-      connkeep(conn, "Connection keep-alive");
-      infof(data, "HTTP/1.0 connection set to keep alive!\n");
-    }
-    else if(Curl_compareheader(headp, "Connection:", "close")) {
-      /*
-       * [RFC 2616, section 8.1.2.1]
-       * "Connection: close" is HTTP/1.1 language and means that
-       * the connection will close when this request has been
-       * served.
-       */
-      streamclose(conn, "Connection: close used");
-    }
-    else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) {
-      /* One or more encodings. We check for chunked and/or a compression
-         algorithm. */
-      /*
-       * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
-       * means that the server will send a series of "chunks". Each
-       * chunk starts with line with info (including size of the
-       * coming block) (terminated with CRLF), then a block of data
-       * with the previously mentioned size. There can be any amount
-       * of chunks, and a chunk-data set to zero signals the
-       * end-of-chunks. */
-
-      result = Curl_build_unencoding_stack(conn, headp + 18, TRUE);
-      if(result)
-        return result;
-    }
-    else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) &&
-            data->set.str[STRING_ENCODING]) {
-      /*
-       * Process Content-Encoding. Look for the values: identity,
-       * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
-       * x-compress are the same as gzip and compress. (Sec 3.5 RFC
-       * 2616). zlib cannot handle compress.  However, errors are
-       * handled further down when the response body is processed
-       */
-      result = Curl_build_unencoding_stack(conn, headp + 17, FALSE);
-      if(result)
-        return result;
-    }
-    else if(checkprefix("Retry-After:", headp)) {
-      /* Retry-After = HTTP-date / delay-seconds */
-      curl_off_t retry_after = 0; /* zero for unknown or "now" */
-      time_t date = Curl_getdate_capped(&headp[12]);
-      if(-1 == date) {
-        /* not a date, try it as a decimal number */
-        (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after);
-      }
-      else
-        /* convert date to number of seconds into the future */
-        retry_after = date - time(NULL);
-      data->info.retry_after = retry_after; /* store it */
-    }
-    else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) {
-      /* Content-Range: bytes [num]-
-         Content-Range: bytes: [num]-
-         Content-Range: [num]-
-         Content-Range: [asterisk]/[total]
-
-         The second format was added since Sun's webserver
-         JavaWebServer/1.1.1 obviously sends the header this way!
-         The third added since some servers use that!
-         The forth means the requested range was unsatisfied.
-      */
-
-      char *ptr = headp + 14;
-
-      /* Move forward until first digit or asterisk */
-      while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
-        ptr++;
-
-      /* if it truly stopped on a digit */
-      if(ISDIGIT(*ptr)) {
-        if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
-          if(data->state.resume_from == k->offset)
-            /* we asked for a resume and we got it */
-            k->content_range = TRUE;
-        }
-      }
-      else
-        data->state.resume_from = 0; /* get everything */
-    }
-#if !defined(CURL_DISABLE_COOKIES)
-    else if(data->cookies && data->state.cookie_engine &&
-            checkprefix("Set-Cookie:", headp)) {
-      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
-                      CURL_LOCK_ACCESS_SINGLE);
-      Curl_cookie_add(data,
-                      data->cookies, TRUE, FALSE, headp + 11,
-                      /* If there is a custom-set Host: name, use it
-                         here, or else use real peer host name. */
-                      data->state.aptr.cookiehost?
-                      data->state.aptr.cookiehost:conn->host.name,
-                      data->state.up.path,
-                      (conn->handler->protocol&CURLPROTO_HTTPS)?
-                      TRUE:FALSE);
-      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
-    }
-#endif
-    else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) &&
-            (data->set.timecondition || data->set.get_filetime) ) {
-      k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:"));
-      if(data->set.get_filetime)
-        data->info.filetime = k->timeofdoc;
-    }
-    else if((checkprefix("WWW-Authenticate:", headp) &&
-             (401 == k->httpcode)) ||
-            (checkprefix("Proxy-authenticate:", headp) &&
-             (407 == k->httpcode))) {
-
-      bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
-      char *auth = Curl_copy_header_value(headp);
-      if(!auth)
-        return CURLE_OUT_OF_MEMORY;
-
-      result = Curl_http_input_auth(conn, proxy, auth);
-
-      free(auth);
-
-      if(result)
-        return result;
-    }
-#ifdef USE_SPNEGO
-    else if(checkprefix("Persistent-Auth", headp)) {
-      struct negotiatedata *negdata = &conn->negotiate;
-      struct auth *authp = &data->state.authhost;
-      if(authp->picked == CURLAUTH_NEGOTIATE) {
-        char *persistentauth = Curl_copy_header_value(headp);
-        if(!persistentauth)
-          return CURLE_OUT_OF_MEMORY;
-        negdata->noauthpersist = checkprefix("false", persistentauth)?
-          TRUE:FALSE;
-        negdata->havenoauthpersist = TRUE;
-        infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
-          negdata->noauthpersist, persistentauth);
-        free(persistentauth);
-      }
-    }
-#endif
-    else if((k->httpcode >= 300 && k->httpcode < 400) &&
-            checkprefix("Location:", headp) &&
-            !data->req.location) {
-      /* this is the URL that the server advises us to use instead */
-      char *location = Curl_copy_header_value(headp);
-      if(!location)
-        return CURLE_OUT_OF_MEMORY;
-      if(!*location)
-        /* ignore empty data */
-        free(location);
-      else {
-        data->req.location = location;
-
-        if(data->set.http_follow_location) {
-          DEBUGASSERT(!data->req.newurl);
-          data->req.newurl = strdup(data->req.location); /* clone */
-          if(!data->req.newurl)
-            return CURLE_OUT_OF_MEMORY;
-
-          /* some cases of POST and PUT etc needs to rewind the data
-             stream at this point */
-          result = http_perhapsrewind(conn);
-          if(result)
-            return result;
-        }
-      }
-    }
-#ifdef USE_ALTSVC
-    /* If enabled, the header is incoming and this is over HTTPS */
-    else if(data->asi && checkprefix("Alt-Svc:", headp) &&
-            ((conn->handler->flags & PROTOPT_SSL) ||
-#ifdef CURLDEBUG
-             /* allow debug builds to circumvent the HTTPS restriction */
-             getenv("CURL_ALTSVC_HTTP")
-#else
-             0
-#endif
-              )) {
-      /* the ALPN of the current request */
-      enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
-      result = Curl_altsvc_parse(data, data->asi,
-                                 &headp[ strlen("Alt-Svc:") ],
-                                 id, conn->host.name,
-                                 curlx_uitous(conn->remote_port));
-      if(result)
-        return result;
-    }
-#endif
-    else if(conn->handler->protocol & CURLPROTO_RTSP) {
-      result = Curl_rtsp_parseheader(conn, headp);
-      if(result)
-        return result;
-    }
+    result = Curl_http_header(data, conn, headp);
+    if(result)
+      return result;
 
     /*
      * End of header-checks. Write them to the client.
@@ -4025,11 +4243,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     if(data->set.include_header)
       writetype |= CLIENTWRITE_BODY;
 
-    if(data->set.verbose)
-      Curl_debug(data, CURLINFO_HEADER_IN, headp,
-                 Curl_dyn_len(&data->state.headerb));
+    Curl_debug(data, CURLINFO_HEADER_IN, headp,
+               Curl_dyn_len(&data->state.headerb));
 
-    result = Curl_client_write(conn, writetype, headp,
+    result = Curl_client_write(data, writetype, headp,
                                Curl_dyn_len(&data->state.headerb));
     if(result)
       return result;
index 9ea3eb2..28f9341 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
  ***************************************************************************/
 #include "curl_setup.h"
 
+typedef enum {
+  HTTPREQ_GET,
+  HTTPREQ_POST,
+  HTTPREQ_POST_FORM, /* we make a difference internally */
+  HTTPREQ_POST_MIME, /* we make a difference internally */
+  HTTPREQ_PUT,
+  HTTPREQ_HEAD
+} Curl_HttpReq;
+
 #ifndef CURL_DISABLE_HTTP
 
 #ifdef USE_NGHTTP2
@@ -42,32 +51,78 @@ bool Curl_compareheader(const char *headerline,  /* line to check */
 
 char *Curl_copy_header_value(const char *header);
 
-char *Curl_checkProxyheaders(const struct connectdata *conn,
+char *Curl_checkProxyheaders(struct Curl_easy *data,
+                             const struct connectdata *conn,
                              const char *thisheader);
+#ifndef USE_HYPER
 CURLcode Curl_buffer_send(struct dynbuf *in,
-                          struct connectdata *conn,
+                          struct Curl_easy *data,
                           curl_off_t *bytes_written,
                           size_t included_body_bytes,
                           int socketindex);
+#else
+#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
+#endif
 
-CURLcode Curl_add_timecondition(const struct connectdata *conn,
-                                struct dynbuf *buf);
-CURLcode Curl_add_custom_headers(struct connectdata *conn,
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+#ifndef USE_HYPER
+                                struct dynbuf *req
+#else
+                                void *headers
+#endif
+  );
+CURLcode Curl_add_custom_headers(struct Curl_easy *data,
                                  bool is_connect,
-                                 struct dynbuf *req_buffer);
+#ifndef USE_HYPER
+                                 struct dynbuf *req
+#else
+                                 void *headers
+#endif
+  );
 CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
                                     struct dynbuf *buf,
                                     struct Curl_easy *handle);
 
+void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
+                      const char **method, Curl_HttpReq *);
+CURLcode Curl_http_useragent(struct Curl_easy *data);
+CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn,
+                          struct dynbuf *req);
+CURLcode Curl_http_statusline(struct Curl_easy *data,
+                              struct connectdata *conn);
+CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
+                          char *headp);
+CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
+                        Curl_HttpReq httpreq,
+                        const char **teep);
+CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
+                            struct dynbuf *r, Curl_HttpReq httpreq);
+#ifndef CURL_DISABLE_COOKIES
+CURLcode Curl_http_cookies(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct dynbuf *r);
+#else
+#define Curl_http_cookies(a,b,c) CURLE_OK
+#endif
+CURLcode Curl_http_resume(struct Curl_easy *data,
+                          struct connectdata *conn,
+                          Curl_HttpReq httpreq);
+CURLcode Curl_http_range(struct Curl_easy *data,
+                         Curl_HttpReq httpreq);
+CURLcode Curl_http_firstwrite(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              bool *done);
+
 /* protocol-specific functions set up to be called by the main engine */
-CURLcode Curl_http(struct connectdata *conn, bool *done);
-CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
-CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
+CURLcode Curl_http(struct Curl_easy *data, bool *done);
+CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature);
+CURLcode Curl_http_connect(struct Curl_easy *data, bool *done);
 
 /* These functions are in http.c */
-CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
+CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
                               const char *auth);
-CURLcode Curl_http_auth_act(struct connectdata *conn);
+CURLcode Curl_http_auth_act(struct Curl_easy *data);
 
 /* If only the PICKNONE bit is set, there has been a round-trip and we
    selected to use no auth at all. Ie, we actively select no auth, as opposed
@@ -115,7 +170,6 @@ struct HTTP {
   const char *postdata;
 
   const char *p_pragma;      /* Pragma: string */
-  const char *p_accept;      /* Accept: string */
 
   /* For FORM posting */
   curl_mimepart form;
@@ -234,11 +288,13 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 /**
  * Curl_http_output_auth() setups the authentication headers for the
  * host/proxy and the correct authentication
- * method. conn->data->state.authdone is set to TRUE when authentication is
+ * method. data->state.authdone is set to TRUE when authentication is
  * done.
  *
+ * @param data all information about the current transfer
  * @param conn all information about the current connection
  * @param request pointer to the request keyword
+ * @param httpreq is the request type
  * @param path pointer to the requested path
  * @param proxytunnel boolean if this is the request setting up a "proxy
  * tunnel"
@@ -246,8 +302,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
  * @returns CURLcode
  */
 CURLcode
-Curl_http_output_auth(struct connectdata *conn,
+Curl_http_output_auth(struct Curl_easy *data,
+                      struct connectdata *conn,
                       const char *request,
+                      Curl_HttpReq httpreq,
                       const char *path,
                       bool proxytunnel); /* TRUE if this is the request setting
                                             up the proxy tunnel */
index d316da8..be4c712 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #endif
 
 
-static ssize_t http2_recv(struct connectdata *conn, int sockindex,
+static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
                           char *mem, size_t len, CURLcode *err);
-static bool http2_connisdead(struct connectdata *conn);
+static bool http2_connisdead(struct Curl_easy *data,
+                             struct connectdata *conn);
 static int h2_session_send(struct Curl_easy *data,
                            nghttp2_session *h2);
-static int h2_process_pending_input(struct connectdata *conn,
+static int h2_process_pending_input(struct Curl_easy *data,
                                     struct http_conn *httpc,
                                     CURLcode *err);
 
@@ -92,18 +93,20 @@ void Curl_http2_init_userset(struct UserDefined *set)
   set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
 }
 
-static int http2_perform_getsock(const struct connectdata *conn,
-                                 curl_socket_t *sock)
+static int http2_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         curl_socket_t *sock)
 {
   const struct http_conn *c = &conn->proto.httpc;
-  struct SingleRequest *k = &conn->data->req;
+  struct SingleRequest *k = &data->req;
   int bitmap = GETSOCK_BLANK;
 
   sock[0] = conn->sock[FIRSTSOCKET];
 
-  /* in a HTTP/2 connection we can basically always get a frame so we should
-     always be ready for one */
-  bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+  if(!(k->keepon & KEEP_RECV_PAUSE))
+    /* Unless paused - in a HTTP/2 connection we can basically always get a
+       frame so we should always be ready for one */
+    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
 
   /* we're still uploading or the HTTP/2 layer wants to send data */
   if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
@@ -113,12 +116,6 @@ static int http2_perform_getsock(const struct connectdata *conn,
   return bitmap;
 }
 
-static int http2_getsock(struct connectdata *conn,
-                         curl_socket_t *socks)
-{
-  return http2_perform_getsock(conn, socks);
-}
-
 /*
  * http2_stream_free() free HTTP2 stream related data
  */
@@ -139,18 +136,22 @@ static void http2_stream_free(struct HTTP *http)
  * connection cache and not the "main" one. Don't touch the easy handle!
  */
 
-static CURLcode http2_disconnect(struct connectdata *conn,
+static CURLcode http2_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
                                  bool dead_connection)
 {
   struct http_conn *c = &conn->proto.httpc;
   (void)dead_connection;
+#ifndef DEBUG_HTTP2
+  (void)data;
+#endif
 
-  H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
+  H2BUGF(infof(data, "HTTP/2 DISCONNECT starts now\n"));
 
   nghttp2_session_del(c->h2);
   Curl_safefree(c->inbuf);
 
-  H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
+  H2BUGF(infof(data, "HTTP/2 DISCONNECT done\n"));
 
   return CURLE_OK;
 }
@@ -162,7 +163,7 @@ static CURLcode http2_disconnect(struct connectdata *conn,
  * Instead, if it is readable, run Curl_connalive() to peek at the socket
  * and distinguish between closed and data.
  */
-static bool http2_connisdead(struct connectdata *conn)
+static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
 {
   int sval;
   bool dead = TRUE;
@@ -192,14 +193,14 @@ static bool http2_connisdead(struct connectdata *conn)
       if(httpc->recv_underlying)
         /* if called "too early", this pointer isn't setup yet! */
         nread = ((Curl_recv *)httpc->recv_underlying)(
-          conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
+          data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
       if(nread != -1) {
-        infof(conn->data,
+        infof(data,
               "%d bytes stray data read before trying h2 connection\n",
               (int)nread);
         httpc->nread_inbuf = 0;
         httpc->inbuflen = nread;
-        (void)h2_process_pending_input(conn, httpc, &result);
+        (void)h2_process_pending_input(data, httpc, &result);
       }
       else
         /* the read failed so let's say this is dead anyway */
@@ -210,24 +211,25 @@ static bool http2_connisdead(struct connectdata *conn)
   return dead;
 }
 
-static unsigned int http2_conncheck(struct connectdata *check,
+static unsigned int http2_conncheck(struct Curl_easy *data,
+                                    struct connectdata *conn,
                                     unsigned int checks_to_perform)
 {
   unsigned int ret_val = CONNRESULT_NONE;
-  struct http_conn *c = &check->proto.httpc;
+  struct http_conn *c = &conn->proto.httpc;
   int rc;
   bool send_frames = false;
 
   if(checks_to_perform & CONNCHECK_ISDEAD) {
-    if(http2_connisdead(check))
+    if(http2_connisdead(data, conn))
       ret_val |= CONNRESULT_DEAD;
   }
 
   if(checks_to_perform & CONNCHECK_KEEPALIVE) {
     struct curltime now = Curl_now();
-    timediff_t elapsed = Curl_timediff(now, check->keepalive);
+    timediff_t elapsed = Curl_timediff(now, conn->keepalive);
 
-    if(elapsed > check->upkeep_interval_ms) {
+    if(elapsed > data->set.upkeep_interval_ms) {
       /* Perform an HTTP/2 PING */
       rc = nghttp2_submit_ping(c->h2, 0, ZERO_NULL);
       if(!rc) {
@@ -236,18 +238,18 @@ static unsigned int http2_conncheck(struct connectdata *check,
         send_frames = true;
       }
       else {
-       failf(check->data, "nghttp2_submit_ping() failed: %s(%d)",
+       failf(data, "nghttp2_submit_ping() failed: %s(%d)",
              nghttp2_strerror(rc), rc);
       }
 
-      check->keepalive = now;
+      conn->keepalive = now;
     }
   }
 
   if(send_frames) {
     rc = nghttp2_session_send(c->h2);
     if(rc)
-      failf(check->data, "nghttp2_session_send() failed: %s(%d)",
+      failf(data, "nghttp2_session_send() failed: %s(%d)",
             nghttp2_strerror(rc), rc);
   }
 
@@ -257,7 +259,7 @@ static unsigned int http2_conncheck(struct connectdata *check,
 /* called from http_setup_conn */
 void Curl_http2_setup_req(struct Curl_easy *data)
 {
-  struct HTTP *http = data->req.protop;
+  struct HTTP *http = data->req.p.http;
   http->bodystarted = FALSE;
   http->status_code = -1;
   http->pausedata = NULL;
@@ -294,12 +296,13 @@ static const struct Curl_handler Curl_handler_http2 = {
   http2_getsock,                        /* proto_getsock */
   http2_getsock,                        /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  http2_perform_getsock,                /* perform_getsock */
+  http2_getsock,                        /* perform_getsock */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   http2_conncheck,                      /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
+  CURLPROTO_HTTP,                       /* family */
   PROTOPT_STREAM                        /* flags */
 };
 
@@ -315,12 +318,13 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
   http2_getsock,                        /* proto_getsock */
   http2_getsock,                        /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  http2_perform_getsock,                /* perform_getsock */
+  http2_getsock,                        /* perform_getsock */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   http2_conncheck,                      /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
+  CURLPROTO_HTTP,                       /* family */
   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
 };
 
@@ -340,7 +344,7 @@ int Curl_http2_ver(char *p, size_t len)
  * written. See the documentation of nghttp2_send_callback for the details.
  */
 static ssize_t send_callback(nghttp2_session *h2,
-                             const uint8_t *data, size_t length, int flags,
+                             const uint8_t *mem, size_t length, int flags,
                              void *userp)
 {
   struct connectdata *conn = (struct connectdata *)userp;
@@ -355,8 +359,8 @@ static ssize_t send_callback(nghttp2_session *h2,
     /* called before setup properly! */
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET,
-                                             data, length, &result);
+  written = ((Curl_send*)c->send_underlying)(conn->data, FIRSTSOCKET,
+                                             mem, length, &result);
 
   if(result == CURLE_AGAIN) {
     return NGHTTP2_ERR_WOULDBLOCK;
@@ -391,7 +395,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
   if(!h || !GOOD_EASY_HANDLE(h->data))
     return NULL;
   else {
-    struct HTTP *stream = h->data->req.protop;
+    struct HTTP *stream = h->data->req.p.http;
     if(num < stream->push_headers_used)
       return stream->push_headers[num];
   }
@@ -413,7 +417,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
      !strcmp(header, ":") || strchr(header + 1, ':'))
     return NULL;
   else {
-    struct HTTP *stream = h->data->req.protop;
+    struct HTTP *stream = h->data->req.p.http;
     size_t len = strlen(header);
     size_t i;
     for(i = 0; i<stream->push_headers_used; i++) {
@@ -460,7 +464,7 @@ static struct Curl_easy *duphandle(struct Curl_easy *data)
       (void)Curl_close(&second);
     }
     else {
-      second->req.protop = http;
+      second->req.p.http = http;
       Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS);
       Curl_http2_setup_req(second);
       second->state.stream_weight = data->state.stream_weight;
@@ -537,9 +541,9 @@ static int push_promise(struct Curl_easy *data,
     /* ask the application */
     H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
 
-    stream = data->req.protop;
+    stream = data->req.p.http;
     if(!stream) {
-      failf(data, "Internal NULL stream!\n");
+      failf(data, "Internal NULL stream!");
       (void)Curl_close(&newhandle);
       rv = CURL_PUSH_DENY;
       goto fail;
@@ -567,13 +571,13 @@ static int push_promise(struct Curl_easy *data,
     if(rv) {
       DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
       /* denied, kill off the new handle again */
-      http2_stream_free(newhandle->req.protop);
-      newhandle->req.protop = NULL;
+      http2_stream_free(newhandle->req.p.http);
+      newhandle->req.p.http = NULL;
       (void)Curl_close(&newhandle);
       goto fail;
     }
 
-    newstream = newhandle->req.protop;
+    newstream = newhandle->req.p.http;
     newstream->stream_id = frame->promised_stream_id;
     newhandle->req.maxdownload = -1;
     newhandle->req.size = -1;
@@ -583,8 +587,8 @@ static int push_promise(struct Curl_easy *data,
     rc = Curl_multi_add_perform(data->multi, newhandle, conn);
     if(rc) {
       infof(data, "failed to add handle to multi\n");
-      http2_stream_free(newhandle->req.protop);
-      newhandle->req.protop = NULL;
+      http2_stream_free(newhandle->req.p.http);
+      newhandle->req.p.http = NULL;
       Curl_close(&newhandle);
       rv = CURL_PUSH_DENY;
       goto fail;
@@ -667,7 +671,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     return 0;
   }
 
-  stream = data_s->req.protop;
+  stream = data_s->req.p.http;
   if(!stream) {
     H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
                  stream_id));
@@ -783,7 +787,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
        internal error more than anything else! */
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  stream = data_s->req.protop;
+  stream = data_s->req.p.http;
   if(!stream)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
@@ -849,7 +853,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
     }
     H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
                  nghttp2_http2_strerror(error_code), error_code, stream_id));
-    stream = data_s->req.protop;
+    stream = data_s->req.p.http;
     if(!stream)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
 
@@ -894,7 +898,7 @@ static int on_begin_headers(nghttp2_session *session,
     return 0;
   }
 
-  stream = data_s->req.protop;
+  stream = data_s->req.p.http;
   if(!stream || !stream->bodystarted) {
     return 0;
   }
@@ -952,9 +956,9 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
        internal error more than anything else! */
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  stream = data_s->req.protop;
+  stream = data_s->req.p.http;
   if(!stream) {
-    failf(data_s, "Internal NULL stream! 5\n");
+    failf(data_s, "Internal NULL stream!");
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -1100,7 +1104,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
          internal error more than anything else! */
       return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-    stream = data_s->req.protop;
+    stream = data_s->req.p.http;
     if(!stream)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
@@ -1161,7 +1165,7 @@ static void populate_settings(struct connectdata *conn,
 
 void Curl_http2_done(struct Curl_easy *data, bool premature)
 {
-  struct HTTP *http = data->req.protop;
+  struct HTTP *http = data->req.p.http;
   struct http_conn *httpc = &data->conn->proto.httpc;
 
   /* there might be allocated resources done before this got the 'h2' pointer
@@ -1207,19 +1211,12 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
     }
     http->stream_id = 0;
   }
-
-  if(0 == nghttp2_session_check_request_allowed(httpc->h2)) {
-    /* No more requests are allowed in the current session, so the connection
-       may not be reused. This is set when a GOAWAY frame has been received or
-       when the limit of stream identifiers has been reached. */
-    connclose(data->conn, "http/2: No new requests allowed");
-  }
 }
 
 /*
  * Initialize nghttp2 for a Curl connection
  */
-static CURLcode http2_init(struct connectdata *conn)
+static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
 {
   if(!conn->proto.httpc.h2) {
     int rc;
@@ -1232,7 +1229,7 @@ static CURLcode http2_init(struct connectdata *conn)
     rc = nghttp2_session_callbacks_new(&callbacks);
 
     if(rc) {
-      failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
+      failf(data, "Couldn't initialize nghttp2 callbacks!");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
 
@@ -1261,7 +1258,7 @@ static CURLcode http2_init(struct connectdata *conn)
     nghttp2_session_callbacks_del(callbacks);
 
     if(rc) {
-      failf(conn->data, "Couldn't initialize nghttp2!");
+      failf(data, "Couldn't initialize nghttp2!");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
   }
@@ -1278,7 +1275,8 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
   ssize_t binlen;
   char *base64;
   size_t blen;
-  struct SingleRequest *k = &conn->data->req;
+  struct Curl_easy *data = conn->data;
+  struct SingleRequest *k = &data->req;
   uint8_t *binsettings = conn->proto.httpc.binsettings;
   struct http_conn *httpc = &conn->proto.httpc;
 
@@ -1288,14 +1286,14 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
   binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
                                          httpc->local_settings,
                                          httpc->local_settings_num);
-  if(!binlen) {
-    failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
+  if(binlen <= 0) {
+    failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
     Curl_dyn_free(req);
     return CURLE_FAILED_INIT;
   }
   conn->proto.httpc.binlen = binlen;
 
-  result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
+  result = Curl_base64url_encode(data, (const char *)binsettings, binlen,
                                  &base64, &blen);
   if(result) {
     Curl_dyn_free(req);
@@ -1329,14 +1327,13 @@ static int should_close_session(struct http_conn *httpc)
  * This function returns 0 if it succeeds, or -1 and error code will
  * be assigned to *err.
  */
-static int h2_process_pending_input(struct connectdata *conn,
+static int h2_process_pending_input(struct Curl_easy *data,
                                     struct http_conn *httpc,
                                     CURLcode *err)
 {
   ssize_t nread;
   char *inbuf;
   ssize_t rv;
-  struct Curl_easy *data = conn->data;
 
   nread = httpc->inbuflen - httpc->nread_inbuf;
   inbuf = httpc->inbuf + httpc->nread_inbuf;
@@ -1345,7 +1342,7 @@ static int h2_process_pending_input(struct connectdata *conn,
   if(rv < 0) {
     failf(data,
           "h2_process_pending_input: nghttp2_session_mem_recv() returned "
-          "%zd:%s\n", rv, nghttp2_strerror((int)rv));
+          "%zd:%s", rv, nghttp2_strerror((int)rv));
     *err = CURLE_RECV_ERROR;
     return -1;
   }
@@ -1371,6 +1368,14 @@ static int h2_process_pending_input(struct connectdata *conn,
     return -1;
   }
 
+  if(nghttp2_session_check_request_allowed(httpc->h2) == 0) {
+    /* No more requests are allowed in the current session, so
+       the connection may not be reused. This is set when a
+       GOAWAY frame has been received or when the limit of stream
+       identifiers has been reached. */
+    connclose(data->conn, "http/2: No new requests allowed");
+  }
+
   if(should_close_session(httpc)) {
     H2BUGF(infof(data,
                  "h2_process_pending_input: nothing to do in this session\n"));
@@ -1378,19 +1383,19 @@ static int h2_process_pending_input(struct connectdata *conn,
       *err = CURLE_HTTP2;
     else {
       /* not an error per se, but should still close the connection */
-      connclose(conn, "GOAWAY received");
+      connclose(data->conn, "GOAWAY received");
       *err = CURLE_OK;
     }
     return -1;
   }
-
   return 0;
 }
 
 /*
  * Called from transfer.c:done_sending when we stop uploading.
  */
-CURLcode Curl_http2_done_sending(struct connectdata *conn)
+CURLcode Curl_http2_done_sending(struct Curl_easy *data,
+                                 struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
 
@@ -1398,7 +1403,7 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
      (conn->handler == &Curl_handler_http2)) {
     /* make sure this is only attempted for HTTP/2 transfers */
 
-    struct HTTP *stream = conn->data->req.protop;
+    struct HTTP *stream = data->req.p.http;
 
     struct http_conn *httpc = &conn->proto.httpc;
     nghttp2_session *h2 = httpc->h2;
@@ -1411,13 +1416,11 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
       /* resume sending here to trigger the callback to get called again so
          that it can signal EOF to nghttp2 */
       (void)nghttp2_session_resume_data(h2, stream->stream_id);
-
-      (void)h2_process_pending_input(conn, httpc, &result);
+      (void)h2_process_pending_input(data, httpc, &result);
     }
 
     /* If nghttp2 still has pending frames unsent */
     if(nghttp2_session_want_write(h2)) {
-      struct Curl_easy *data = conn->data;
       struct SingleRequest *k = &data->req;
       int rv;
 
@@ -1448,7 +1451,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
   drained_transfer(data, httpc);
 
   if(httpc->pause_stream_id == 0) {
-    if(h2_process_pending_input(conn, httpc, err) != 0) {
+    if(h2_process_pending_input(data, httpc, err) != 0) {
       return -1;
     }
   }
@@ -1494,10 +1497,9 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
         break;
       len = lf + 1 - trailp;
 
-      if(data->set.verbose)
-        Curl_debug(data, CURLINFO_HEADER_IN, trailp, len);
+      Curl_debug(data, CURLINFO_HEADER_IN, trailp, len);
       /* pass the trailers one by one to the callback */
-      result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailp, len);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, trailp, len);
       if(result) {
         *err = result;
         return -1;
@@ -1522,7 +1524,7 @@ static void h2_pri_spec(struct Curl_easy *data,
                         nghttp2_priority_spec *pri_spec)
 {
   struct HTTP *depstream = (data->set.stream_depends_on?
-                            data->set.stream_depends_on->req.protop:NULL);
+                            data->set.stream_depends_on->req.p.http:NULL);
   int32_t depstream_id = depstream? depstream->stream_id:0;
   nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
                              data->set.stream_depends_e);
@@ -1539,7 +1541,7 @@ static void h2_pri_spec(struct Curl_easy *data,
 static int h2_session_send(struct Curl_easy *data,
                            nghttp2_session *h2)
 {
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   if((data->set.stream_weight != data->state.stream_weight) ||
      (data->set.stream_depends_e != data->state.stream_depends_e) ||
      (data->set.stream_depends_on != data->state.stream_depends_on) ) {
@@ -1561,15 +1563,13 @@ static int h2_session_send(struct Curl_easy *data,
   return nghttp2_session_send(h2);
 }
 
-static ssize_t http2_recv(struct connectdata *conn, int sockindex,
+static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
                           char *mem, size_t len, CURLcode *err)
 {
-  CURLcode result = CURLE_OK;
-  ssize_t rv;
   ssize_t nread;
+  struct connectdata *conn = data->conn;
   struct http_conn *httpc = &conn->proto.httpc;
-  struct Curl_easy *data = conn->data;
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
 
   (void)sockindex; /* we always do HTTP2 on sockindex 0 */
 
@@ -1632,8 +1632,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       /* We have paused nghttp2, but we have no pause data (see
          on_data_chunk_recv). */
       httpc->pause_stream_id = 0;
-      if(h2_process_pending_input(conn, httpc, &result) != 0) {
-        *err = result;
+      if(h2_process_pending_input(data, httpc, err) != 0) {
         return -1;
       }
     }
@@ -1661,8 +1660,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
          frames, then we have to call it again with 0-length data.
          Without this, on_stream_close callback will not be called,
          and stream could be hanged. */
-      if(h2_process_pending_input(conn, httpc, &result) != 0) {
-        *err = result;
+      if(h2_process_pending_input(data, httpc, err) != 0) {
         return -1;
       }
     }
@@ -1688,7 +1686,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
     return -1;
   }
   else {
-    char *inbuf;
     /* remember where to store incoming data for this stream and how big the
        buffer is */
     stream->mem = mem;
@@ -1697,16 +1694,15 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
 
     if(httpc->inbuflen == 0) {
       nread = ((Curl_recv *)httpc->recv_underlying)(
-          conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
+        data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, err);
 
       if(nread == -1) {
-        if(result != CURLE_AGAIN)
+        if(*err != CURLE_AGAIN)
           failf(data, "Failed receiving HTTP2 data");
         else if(stream->closed)
           /* received when the stream was already closed! */
           return http2_handle_stream_close(conn, data, stream, err);
 
-        *err = result;
         return -1;
       }
 
@@ -1719,47 +1715,18 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       H2BUGF(infof(data, "nread=%zd\n", nread));
 
       httpc->inbuflen = nread;
-      inbuf = httpc->inbuf;
+
+      DEBUGASSERT(httpc->nread_inbuf == 0);
     }
     else {
       nread = httpc->inbuflen - httpc->nread_inbuf;
-      inbuf = httpc->inbuf + httpc->nread_inbuf;
-
+      (void)nread;  /* silence warning, used in debug */
       H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
                    nread));
     }
-    rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
 
-    if(nghttp2_is_fatal((int)rv)) {
-      failf(data, "nghttp2_session_mem_recv() returned %zd:%s\n",
-            rv, nghttp2_strerror((int)rv));
-      *err = CURLE_RECV_ERROR;
-      return -1;
-    }
-    H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
-    if(nread == rv) {
-      H2BUGF(infof(data, "All data in connection buffer processed\n"));
-      httpc->inbuflen = 0;
-      httpc->nread_inbuf = 0;
-    }
-    else {
-      httpc->nread_inbuf += rv;
-      H2BUGF(infof(data, "%zu bytes left in connection buffer\n",
-                   httpc->inbuflen - httpc->nread_inbuf));
-    }
-    /* Always send pending frames in nghttp2 session, because
-       nghttp2_session_mem_recv() may queue new frame */
-    rv = h2_session_send(data, httpc->h2);
-    if(rv != 0) {
-      *err = CURLE_SEND_ERROR;
+    if(h2_process_pending_input(data, httpc, err) != 0)
       return -1;
-    }
-
-    if(should_close_session(httpc)) {
-      H2BUGF(infof(data, "http2_recv: nothing to do in this session\n"));
-      *err = CURLE_HTTP2;
-      return -1;
-    }
   }
   if(stream->memlen) {
     ssize_t retlen = stream->memlen;
@@ -1864,7 +1831,7 @@ static header_instruction inspect_header(const char *name, size_t namelen,
   }
 }
 
-static ssize_t http2_send(struct connectdata *conn, int sockindex,
+static ssize_t http2_send(struct Curl_easy *data, int sockindex,
                           const void *mem, size_t len, CURLcode *err)
 {
   /*
@@ -1873,8 +1840,9 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
    * request.
    */
   int rv;
+  struct connectdata *conn = data->conn;
   struct http_conn *httpc = &conn->proto.httpc;
-  struct HTTP *stream = conn->data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   nghttp2_nv *nva = NULL;
   size_t nheader;
   size_t i;
@@ -1888,16 +1856,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
   (void)sockindex;
 
-  H2BUGF(infof(conn->data, "http2_send len=%zu\n", len));
+  H2BUGF(infof(data, "http2_send len=%zu\n", len));
 
   if(stream->stream_id != -1) {
     if(stream->close_handled) {
-      infof(conn->data, "stream %d closed\n", stream->stream_id);
+      infof(data, "stream %d closed\n", stream->stream_id);
       *err = CURLE_HTTP2_STREAM;
       return -1;
     }
     else if(stream->closed) {
-      return http2_handle_stream_close(conn, conn->data, stream, err);
+      return http2_handle_stream_close(conn, data, stream, err);
     }
     /* If stream_id != -1, we have dispatched request HEADERS, and now
        are going to send or sending request body in DATA frame */
@@ -1908,7 +1876,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
       *err = CURLE_SEND_ERROR;
       return -1;
     }
-    rv = h2_session_send(conn->data, h2);
+    rv = h2_session_send(data, h2);
     if(nghttp2_is_fatal(rv)) {
       *err = CURLE_SEND_ERROR;
       return -1;
@@ -1921,7 +1889,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     stream->upload_len = 0;
 
     if(should_close_session(httpc)) {
-      H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+      H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
       *err = CURLE_HTTP2;
       return -1;
     }
@@ -1934,7 +1902,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
       nghttp2_session_resume_data(h2, stream->stream_id);
     }
 
-    H2BUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
+    H2BUGF(infof(data, "http2_send returns %zu for stream %u\n", len,
                  stream->stream_id));
     return len;
   }
@@ -1978,7 +1946,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   nva[0].valuelen = (size_t)(end - hdbuf);
   nva[0].flags = NGHTTP2_NV_FLAG_NONE;
   if(HEADER_OVERFLOW(nva[0])) {
-    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    failf(data, "Failed sending HTTP request: Header overflow");
     goto fail;
   }
 
@@ -2000,7 +1968,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   nva[1].valuelen = (size_t)(end - hdbuf);
   nva[1].flags = NGHTTP2_NV_FLAG_NONE;
   if(HEADER_OVERFLOW(nva[1])) {
-    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    failf(data, "Failed sending HTTP request: Header overflow");
     goto fail;
   }
 
@@ -2013,7 +1981,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   nva[2].valuelen = strlen((char *)nva[2].value);
   nva[2].flags = NGHTTP2_NV_FLAG_NONE;
   if(HEADER_OVERFLOW(nva[2])) {
-    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    failf(data, "Failed sending HTTP request: Header overflow");
     goto fail;
   }
 
@@ -2073,7 +2041,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
     nva[i].flags = NGHTTP2_NV_FLAG_NONE;
     if(HEADER_OVERFLOW(nva[i])) {
-      failf(conn->data, "Failed sending HTTP request: Header overflow");
+      failf(data, "Failed sending HTTP request: Header overflow");
       goto fail;
     }
     ++i;
@@ -2097,30 +2065,30 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     for(i = 0; i < nheader; ++i) {
       acc += nva[i].namelen + nva[i].valuelen;
 
-      H2BUGF(infof(conn->data, "h2 header: %.*s:%.*s\n",
+      H2BUGF(infof(data, "h2 header: %.*s:%.*s\n",
                    nva[i].namelen, nva[i].name,
                    nva[i].valuelen, nva[i].value));
     }
 
     if(acc > MAX_ACC) {
-      infof(conn->data, "http2_send: Warning: The cumulative length of all "
-            "headers exceeds %zu bytes and that could cause the "
+      infof(data, "http2_send: Warning: The cumulative length of all "
+            "headers exceeds %d bytes and that could cause the "
             "stream to be rejected.\n", MAX_ACC);
     }
   }
 
-  h2_pri_spec(conn->data, &pri_spec);
+  h2_pri_spec(data, &pri_spec);
 
-  H2BUGF(infof(conn->data, "http2_send request allowed %d (easy handle %p)\n",
-               nghttp2_session_check_request_allowed(h2), (void *)conn->data));
+  H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)\n",
+               nghttp2_session_check_request_allowed(h2), (void *)data));
 
-  switch(conn->data->state.httpreq) {
+  switch(data->state.httpreq) {
   case HTTPREQ_POST:
   case HTTPREQ_POST_FORM:
   case HTTPREQ_POST_MIME:
   case HTTPREQ_PUT:
-    if(conn->data->state.infilesize != -1)
-      stream->upload_left = conn->data->state.infilesize;
+    if(data->state.infilesize != -1)
+      stream->upload_left = data->state.infilesize;
     else
       /* data sending without specifying the data amount up front */
       stream->upload_left = -1; /* unknown, but not zero */
@@ -2128,36 +2096,41 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     data_prd.read_callback = data_source_read_callback;
     data_prd.source.ptr = NULL;
     stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
-                                       &data_prd, conn->data);
+                                       &data_prd, data);
     break;
   default:
     stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
-                                       NULL, conn->data);
+                                       NULL, data);
   }
 
   Curl_safefree(nva);
 
   if(stream_id < 0) {
-    H2BUGF(infof(conn->data, "http2_send() send error\n"));
+    H2BUGF(infof(data,
+                 "http2_send() nghttp2_submit_request error (%s)%d\n",
+                 nghttp2_strerror(stream_id), stream_id));
     *err = CURLE_SEND_ERROR;
     return -1;
   }
 
-  infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
-        stream_id, (void *)conn->data);
+  infof(data, "Using Stream ID: %x (easy handle %p)\n",
+        stream_id, (void *)data);
   stream->stream_id = stream_id;
 
   /* this does not call h2_session_send() since there can not have been any
-   * priority upodate since the nghttp2_submit_request() call above */
+   * priority update since the nghttp2_submit_request() call above */
   rv = nghttp2_session_send(h2);
-
   if(rv != 0) {
+    H2BUGF(infof(data,
+                 "http2_send() nghttp2_session_send error (%s)%d\n",
+                 nghttp2_strerror(rv), rv));
+
     *err = CURLE_SEND_ERROR;
     return -1;
   }
 
   if(should_close_session(httpc)) {
-    H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+    H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
     *err = CURLE_HTTP2;
     return -1;
   }
@@ -2179,13 +2152,14 @@ fail:
   return -1;
 }
 
-CURLcode Curl_http2_setup(struct connectdata *conn)
+CURLcode Curl_http2_setup(struct Curl_easy *data,
+                          struct connectdata *conn)
 {
   CURLcode result;
   struct http_conn *httpc = &conn->proto.httpc;
-  struct HTTP *stream = conn->data->req.protop;
+  struct HTTP *stream = data->req.p.http;
 
-  DEBUGASSERT(conn->data->state.buffer);
+  DEBUGASSERT(data->state.buffer);
 
   stream->stream_id = -1;
 
@@ -2201,18 +2175,18 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   else
     conn->handler = &Curl_handler_http2;
 
-  result = http2_init(conn);
+  result = http2_init(data, conn);
   if(result) {
     Curl_dyn_free(&stream->header_recvbuf);
     return result;
   }
 
-  infof(conn->data, "Using HTTP2, server supports multi-use\n");
+  infof(data, "Using HTTP2, server supports multi-use\n");
   stream->upload_left = 0;
   stream->upload_mem = NULL;
   stream->upload_len = 0;
-  stream->mem = conn->data->state.buffer;
-  stream->len = conn->data->set.buffer_size;
+  stream->mem = data->state.buffer;
+  stream->len = data->set.buffer_size;
 
   httpc->inbuflen = 0;
   httpc->nread_inbuf = 0;
@@ -2224,23 +2198,22 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   conn->httpversion = 20;
   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
 
-  infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
-  multi_connchanged(conn->data->multi);
+  infof(data, "Connection state changed (HTTP/2 confirmed)\n");
+  multi_connchanged(data->multi);
 
   return CURLE_OK;
 }
 
-CURLcode Curl_http2_switched(struct connectdata *conn,
+CURLcode Curl_http2_switched(struct Curl_easy *data,
                              const char *mem, size_t nread)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   struct http_conn *httpc = &conn->proto.httpc;
   int rv;
-  ssize_t nproc;
-  struct Curl_easy *data = conn->data;
-  struct HTTP *stream = conn->data->req.protop;
+  struct HTTP *stream = data->req.p.http;
 
-  result = Curl_http2_setup(conn);
+  result = Curl_http2_setup(data, conn);
   if(result)
     return result;
 
@@ -2249,7 +2222,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
   conn->recv[FIRSTSOCKET] = http2_recv;
   conn->send[FIRSTSOCKET] = http2_send;
 
-  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
+  if(data->req.upgr101 == UPGR101_RECEIVED) {
     /* stream 1 is opened implicitly on upgrade */
     stream->stream_id = 1;
     /* queue SETTINGS frame (again) */
@@ -2299,52 +2272,24 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
      data into stream->mem, overwriting data already there. */
   if(H2_BUFSIZE < nread) {
     failf(data, "connection buffer size is too small to store data following "
-                "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
+          "HTTP Upgrade response header: buflen=%d, datalen=%zu",
           H2_BUFSIZE, nread);
     return CURLE_HTTP2;
   }
 
-  infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
-                    " after upgrade: len=%zu\n",
+  infof(data, "Copying HTTP/2 data in stream buffer to connection buffer"
+        " after upgrade: len=%zu\n",
         nread);
 
   if(nread)
     memcpy(httpc->inbuf, mem, nread);
-  httpc->inbuflen = nread;
-
-  nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
-                                   httpc->inbuflen);
-
-  if(nghttp2_is_fatal((int)nproc)) {
-    failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
-          nghttp2_strerror((int)nproc), (int)nproc);
-    return CURLE_HTTP2;
-  }
 
-  H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
-
-  if((ssize_t)nread == nproc) {
-    httpc->inbuflen = 0;
-    httpc->nread_inbuf = 0;
-  }
-  else {
-    httpc->nread_inbuf += nproc;
-  }
-
-  /* Try to send some frames since we may read SETTINGS already. */
-  rv = h2_session_send(data, httpc->h2);
+  httpc->inbuflen = nread;
 
-  if(rv != 0) {
-    failf(data, "nghttp2_session_send() failed: %s(%d)",
-          nghttp2_strerror(rv), rv);
-    return CURLE_HTTP2;
-  }
+  DEBUGASSERT(httpc->nread_inbuf == 0);
 
-  if(should_close_session(httpc)) {
-    H2BUGF(infof(data,
-                 "nghttp2_session_send(): nothing to do in this session\n"));
+  if(-1 == h2_process_pending_input(data, httpc, &result))
     return CURLE_HTTP2;
-  }
 
   return CURLE_OK;
 }
@@ -2358,7 +2303,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
     return CURLE_OK;
 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
   else {
-    struct HTTP *stream = data->req.protop;
+    struct HTTP *stream = data->req.p.http;
     struct http_conn *httpc = &data->conn->proto.httpc;
     uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
     int rv = nghttp2_session_set_local_window_size(httpc->h2,
index e82b212..119e584 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -44,14 +44,15 @@ void Curl_http2_init_state(struct UrlState *state);
 void Curl_http2_init_userset(struct UserDefined *set);
 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
                                     struct connectdata *conn);
-CURLcode Curl_http2_setup(struct connectdata *conn);
-CURLcode Curl_http2_switched(struct connectdata *conn,
-                             const char *data, size_t nread);
+CURLcode Curl_http2_setup(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_http2_switched(struct Curl_easy *data,
+                             const char *ptr, size_t nread);
 /* called from http_setup_conn */
 void Curl_http2_setup_conn(struct connectdata *conn);
 void Curl_http2_setup_req(struct Curl_easy *data);
 void Curl_http2_done(struct Curl_easy *data, bool premature);
-CURLcode Curl_http2_done_sending(struct connectdata *conn);
+CURLcode Curl_http2_done_sending(struct Curl_easy *data,
+                                 struct connectdata *conn);
 CURLcode Curl_http2_add_child(struct Curl_easy *parent,
                               struct Curl_easy *child,
                               bool exclusive);
@@ -64,14 +65,14 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause);
 bool Curl_h2_http_1_1_error(struct connectdata *conn);
 #else /* USE_NGHTTP2 */
 #define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
-#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_setup(x,y) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_setup_conn(x) Curl_nop_stmt
 #define Curl_http2_setup_req(x)
 #define Curl_http2_init_state(x)
 #define Curl_http2_init_userset(x)
 #define Curl_http2_done(x,y)
-#define Curl_http2_done_sending(x)
+#define Curl_http2_done_sending(x,y)
 #define Curl_http2_add_child(x, y, z)
 #define Curl_http2_remove_child(x, y)
 #define Curl_http2_cleanup_dependencies(x)
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
new file mode 100644 (file)
index 0000000..8fd1c77
--- /dev/null
@@ -0,0 +1,394 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2021, 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.haxx.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.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include "urldata.h"
+#include "strcase.h"
+#include "strdup.h"
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "http_aws_sigv4.h"
+#include "curl_sha256.h"
+#include "transfer.h"
+
+#include "strcase.h"
+#include "parsedate.h"
+#include "sendf.h"
+
+#include <time.h>
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define HMAC_SHA256(k, kl, d, dl, o)        \
+  do {                                      \
+    ret = Curl_hmacit(Curl_HMAC_SHA256,     \
+                      (unsigned char *)k,   \
+                      (unsigned int)kl,     \
+                      (unsigned char *)d,   \
+                      (unsigned int)dl, o); \
+    if(ret != CURLE_OK) {                   \
+      goto fail;                            \
+    }                                       \
+  } while(0)
+
+static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l)
+{
+  int i;
+
+  DEBUGASSERT(dst_l >= 65);
+  for(i = 0; i < 32; ++i) {
+    curl_msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]);
+  }
+}
+
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
+{
+  CURLcode ret = CURLE_OUT_OF_MEMORY;
+  struct connectdata *conn = data->conn;
+  size_t len;
+  const char *tmp0;
+  const char *tmp1;
+  char *provider0_low = NULL;
+  char *provider0_up = NULL;
+  char *provider1_low = NULL;
+  char *provider1_mid = NULL;
+  char *region = NULL;
+  char *service = NULL;
+  const char *hostname = conn->host.name;
+#ifdef DEBUGBUILD
+  char *force_timestamp;
+#endif
+  time_t clock;
+  struct tm tm;
+  char timestamp[17];
+  char date[9];
+  const char *content_type = Curl_checkheaders(data, "Content-Type");
+  char *canonical_headers = NULL;
+  char *signed_headers = NULL;
+  Curl_HttpReq httpreq;
+  const char *method;
+  const char *post_data = data->set.postfields ? data->set.postfields : "";
+  unsigned char sha_hash[32];
+  char sha_hex[65];
+  char *canonical_request = NULL;
+  char *request_type = NULL;
+  char *credential_scope = NULL;
+  char *str_to_sign = NULL;
+  const char *user = conn->user ? conn->user : "";
+  const char *passwd = conn->passwd ? conn->passwd : "";
+  char *secret = NULL;
+  unsigned char tmp_sign0[32] = {0};
+  unsigned char tmp_sign1[32] = {0};
+  char *auth_headers = NULL;
+
+  DEBUGASSERT(!proxy);
+  (void)proxy;
+
+  if(Curl_checkheaders(data, "Authorization")) {
+    /* Authorization already present, Bailing out */
+    return CURLE_OK;
+  }
+
+  /*
+   * Parameters parsing
+   * Google and Outscale use the same OSC or GOOG,
+   * but Amazon uses AWS and AMZ for header arguments.
+   * AWS is the default because most of non-amazon providers
+   * are still using aws:amz as a prefix.
+   */
+  tmp0 = data->set.str[STRING_AWS_SIGV4] ?
+    data->set.str[STRING_AWS_SIGV4] : "aws:amz";
+  tmp1 = strchr(tmp0, ':');
+  len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
+  if(len < 1) {
+    infof(data, "first provider can't be empty\n");
+    ret = CURLE_BAD_FUNCTION_ARGUMENT;
+    goto fail;
+  }
+  provider0_low = malloc(len + 1);
+  provider0_up = malloc(len + 1);
+  if(!provider0_low || !provider0_up) {
+    goto fail;
+  }
+  Curl_strntolower(provider0_low, tmp0, len);
+  provider0_low[len] = '\0';
+  Curl_strntoupper(provider0_up, tmp0, len);
+  provider0_up[len] = '\0';
+
+  if(tmp1) {
+    tmp0 = tmp1 + 1;
+    tmp1 = strchr(tmp0, ':');
+    len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
+    if(len < 1) {
+      infof(data, "second provider can't be empty\n");
+      ret = CURLE_BAD_FUNCTION_ARGUMENT;
+      goto fail;
+    }
+    provider1_low = malloc(len + 1);
+    provider1_mid = malloc(len + 1);
+    if(!provider1_low || !provider1_mid) {
+      goto fail;
+    }
+    Curl_strntolower(provider1_low, tmp0, len);
+    provider1_low[len] = '\0';
+    Curl_strntolower(provider1_mid, tmp0, len);
+    provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]);
+    provider1_mid[len] = '\0';
+
+    if(tmp1) {
+      tmp0 = tmp1 + 1;
+      tmp1 = strchr(tmp0, ':');
+      len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
+      if(len < 1) {
+        infof(data, "region can't be empty\n");
+        ret = CURLE_BAD_FUNCTION_ARGUMENT;
+        goto fail;
+      }
+      region = Curl_memdup(tmp0, len + 1);
+      if(!region) {
+        goto fail;
+      }
+      region[len] = '\0';
+
+      if(tmp1) {
+        tmp0 = tmp1 + 1;
+        service = strdup(tmp0);
+        if(!service) {
+          goto fail;
+        }
+        if(strlen(service) < 1) {
+          infof(data, "service can't be empty\n");
+          ret = CURLE_BAD_FUNCTION_ARGUMENT;
+          goto fail;
+        }
+      }
+    }
+  }
+  else {
+    provider1_low = Curl_memdup(provider0_low, len + 1);
+    provider1_mid = Curl_memdup(provider0_low, len + 1);
+    if(!provider1_low || !provider1_mid) {
+      goto fail;
+    }
+    provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]);
+  }
+
+  if(!service) {
+    tmp0 = hostname;
+    tmp1 = strchr(tmp0, '.');
+    len = tmp1 - tmp0;
+    if(!tmp1 || len < 1) {
+      infof(data, "service missing in parameters or hostname\n");
+      ret = CURLE_URL_MALFORMAT;
+      goto fail;
+    }
+    service = Curl_memdup(tmp0, len + 1);
+    if(!service) {
+      goto fail;
+    }
+    service[len] = '\0';
+
+    if(!region) {
+      tmp0 = tmp1 + 1;
+      tmp1 = strchr(tmp0, '.');
+      len = tmp1 - tmp0;
+      if(!tmp1 || len < 1) {
+        infof(data, "region missing in parameters or hostname\n");
+        ret = CURLE_URL_MALFORMAT;
+        goto fail;
+      }
+      region = Curl_memdup(tmp0, len + 1);
+      if(!region) {
+        goto fail;
+      }
+      region[len] = '\0';
+    }
+  }
+
+#ifdef DEBUGBUILD
+  force_timestamp = getenv("CURL_FORCETIME");
+  if(force_timestamp)
+    clock = 0;
+  else
+    time(&clock);
+#else
+  time(&clock);
+#endif
+  ret = Curl_gmtime(clock, &tm);
+  if(ret != CURLE_OK) {
+    goto fail;
+  }
+  if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
+    goto fail;
+  }
+  memcpy(date, timestamp, sizeof(date));
+  date[sizeof(date) - 1] = 0;
+
+  if(content_type) {
+    content_type = strchr(content_type, ':');
+    if(!content_type) {
+      ret = CURLE_FAILED_INIT;
+      goto fail;
+    }
+    content_type++;
+    /* Skip whitespace now */
+    while(*content_type == ' ' || *content_type == '\t')
+      ++content_type;
+
+    canonical_headers = curl_maprintf("content-type:%s\n"
+                                      "host:%s\n"
+                                      "x-%s-date:%s\n",
+                                      content_type,
+                                      hostname,
+                                      provider1_low, timestamp);
+    signed_headers = curl_maprintf("content-type;host;x-%s-date",
+                                   provider1_low);
+  }
+  else {
+    canonical_headers = curl_maprintf("host:%s\n"
+                                      "x-%s-date:%s\n",
+                                      hostname,
+                                      provider1_low, timestamp);
+    signed_headers = curl_maprintf("host;x-%s-date", provider1_low);
+  }
+
+  if(!canonical_headers || !signed_headers) {
+    goto fail;
+  }
+
+  Curl_sha256it(sha_hash,
+                (const unsigned char *) post_data, strlen(post_data));
+  sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+
+  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 : "",
+                  canonical_headers,
+                  signed_headers,
+                  sha_hex);
+  if(!canonical_request) {
+    goto fail;
+  }
+
+  request_type = curl_maprintf("%s4_request", provider0_low);
+  if(!request_type) {
+    goto fail;
+  }
+
+  credential_scope = curl_maprintf("%s/%s/%s/%s",
+                                   date, region, service, request_type);
+  if(!credential_scope) {
+    goto fail;
+  }
+
+  Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
+                strlen(canonical_request));
+  sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+
+  /*
+   * Google allow to use rsa key instead of HMAC, so this code might change
+   * In the furure, but for now we support only HMAC version
+   */
+  str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
+                              "%s\n" /* RequestDateTime */
+                              "%s\n" /* CredentialScope */
+                              "%s",  /* HashedCanonicalRequest in hex */
+                              provider0_up,
+                              timestamp,
+                              credential_scope,
+                              sha_hex);
+  if(!str_to_sign) {
+    goto fail;
+  }
+
+  secret = curl_maprintf("%s4%s", provider0_up, passwd);
+  if(!secret) {
+    goto fail;
+  }
+
+  HMAC_SHA256(secret, strlen(secret),
+              date, strlen(date), tmp_sign0);
+  HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0),
+              region, strlen(region), tmp_sign1);
+  HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1),
+              service, strlen(service), tmp_sign0);
+  HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0),
+              request_type, strlen(request_type), tmp_sign1);
+  HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1),
+              str_to_sign, strlen(str_to_sign), tmp_sign0);
+
+  sha256_to_hex(sha_hex, tmp_sign0, sizeof(sha_hex));
+
+  auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
+                               "Credential=%s/%s, "
+                               "SignedHeaders=%s, "
+                               "Signature=%s\r\n"
+                               "X-%s-Date: %s\r\n",
+                               provider0_up,
+                               user,
+                               credential_scope,
+                               signed_headers,
+                               sha_hex,
+                               provider1_mid,
+                               timestamp);
+  if(!auth_headers) {
+    goto fail;
+  }
+
+  Curl_safefree(data->state.aptr.userpwd);
+  data->state.aptr.userpwd = auth_headers;
+  data->state.authhost.done = TRUE;
+  ret = CURLE_OK;
+
+fail:
+  free(provider0_low);
+  free(provider0_up);
+  free(provider1_low);
+  free(provider1_mid);
+  free(region);
+  free(service);
+  free(canonical_headers);
+  free(signed_headers);
+  free(canonical_request);
+  free(request_type);
+  free(credential_scope);
+  free(str_to_sign);
+  free(secret);
+  return ret;
+}
+
+#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) */
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.h b/Utilities/cmcurl/lib/http_aws_sigv4.h
new file mode 100644 (file)
index 0000000..886b314
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_HTTP_AWS_SIGV4_H
+#define HEADER_CURL_HTTP_AWS_SIGV4_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2021, 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.haxx.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.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/* this is for creating aws_sigv4 header output */
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy);
+
+#endif /* HEADER_CURL_HTTP_AWS_SIGV4_H */
index 767f806..beb9695 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #ifdef CURL_DOES_CONVERSIONS
 /* Check for an ASCII hex digit.
    We avoid the use of ISXDIGIT to accommodate non-ASCII hosts. */
-static bool Curl_isxdigit_ascii(char digit)
+static bool isxdigit_ascii(char digit)
 {
   return (digit >= 0x30 && digit <= 0x39) /* 0-9 */
-        || (digit >= 0x41 && digit <= 0x46) /* A-F */
-        || (digit >= 0x61 && digit <= 0x66); /* a-f */
+    || (digit >= 0x41 && digit <= 0x46) /* A-F */
+    || (digit >= 0x61 && digit <= 0x66); /* a-f */
 }
 #else
-#define Curl_isxdigit_ascii(x) Curl_isxdigit(x)
+#define isxdigit_ascii(x) Curl_isxdigit(x)
 #endif
 
-void Curl_httpchunk_init(struct connectdata *conn)
+void Curl_httpchunk_init(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct Curl_chunker *chunk = &conn->chunk;
   chunk->hexindex = 0;      /* start at 0 */
-  chunk->dataleft = 0;      /* no data left yet! */
   chunk->state = CHUNK_HEX; /* we get hex first! */
   Curl_dyn_init(&conn->trailer, DYN_H1_TRAILER);
 }
@@ -107,14 +107,14 @@ void Curl_httpchunk_init(struct connectdata *conn)
  * This function always uses ASCII hex values to accommodate non-ASCII hosts.
  * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
  */
-CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
+CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
                               char *datap,
                               ssize_t datalen,
                               ssize_t *wrotep,
                               CURLcode *extrap)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct Curl_chunker *ch = &conn->chunk;
   struct SingleRequest *k = &data->req;
   size_t piece;
@@ -126,7 +126,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
   /* the original data is written to the client, but we go on with the
      chunk read process, to properly calculate the content length*/
   if(data->set.http_te_skip && !k->ignorebody) {
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, datap, datalen);
     if(result) {
       *extrap = result;
       return CHUNKE_PASSTHRU_ERROR;
@@ -136,8 +136,8 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
   while(length) {
     switch(ch->state) {
     case CHUNK_HEX:
-      if(Curl_isxdigit_ascii(*datap)) {
-        if(ch->hexindex < MAXNUM_SIZE) {
+      if(isxdigit_ascii(*datap)) {
+        if(ch->hexindex < CHUNK_MAXNUM_LEN) {
           ch->hexbuffer[ch->hexindex] = *datap;
           datap++;
           length--;
@@ -158,8 +158,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
         ch->hexbuffer[ch->hexindex] = 0;
 
         /* convert to host encoding before calling strtoul */
-        result = Curl_convert_from_network(conn->data, ch->hexbuffer,
-                                           ch->hexindex);
+        result = Curl_convert_from_network(data, ch->hexbuffer, ch->hexindex);
         if(result) {
           /* Curl_convert_from_network calls failf if unsuccessful */
           /* Treat it as a bad hex character */
@@ -194,11 +193,11 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
       piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
 
       /* Write the data portion available */
-      if(!conn->data->set.http_te_skip && !k->ignorebody) {
-        if(!conn->data->set.http_ce_skip && k->writer_stack)
-          result = Curl_unencode_write(conn, k->writer_stack, datap, piece);
+      if(!data->set.http_te_skip && !k->ignorebody) {
+        if(!data->set.http_ce_skip && k->writer_stack)
+          result = Curl_unencode_write(data, k->writer_stack, datap, piece);
         else
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
 
         if(result) {
           *extrap = result;
@@ -219,7 +218,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
     case CHUNK_POSTLF:
       if(*datap == 0x0a) {
         /* The last one before we go back to hex state and start all over. */
-        Curl_httpchunk_init(conn); /* sets state back to CHUNK_HEX */
+        Curl_httpchunk_init(data); /* sets state back to CHUNK_HEX */
       }
       else if(*datap != 0x0d)
         return CHUNKE_BAD_CHUNK;
@@ -242,14 +241,14 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
           tr = Curl_dyn_ptr(&conn->trailer);
           trlen = Curl_dyn_len(&conn->trailer);
           /* Convert to host encoding before calling Curl_client_write */
-          result = Curl_convert_from_network(conn->data, tr, trlen);
+          result = Curl_convert_from_network(data, tr, trlen);
           if(result)
             /* Curl_convert_from_network calls failf if unsuccessful */
             /* Treat it as a bad chunk */
             return CHUNKE_BAD_CHUNK;
 
           if(!data->set.http_te_skip) {
-            result = Curl_client_write(conn, CLIENTWRITE_HEADER, tr, trlen);
+            result = Curl_client_write(data, CLIENTWRITE_HEADER, tr, trlen);
             if(result) {
               *extrap = result;
               return CHUNKE_PASSTHRU_ERROR;
@@ -309,7 +308,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
 
         /* Record the length of any data left in the end of the buffer
            even if there's no more chunks to read */
-        ch->dataleft = curlx_sotouz(length);
+        ch->datasize = curlx_sotouz(length);
 
         return CHUNKE_STOP; /* return stop */
       }
index 8f4a33c..741a9a3 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -26,10 +26,10 @@ struct connectdata;
 
 /*
  * The longest possible hexadecimal number we support in a chunked transfer.
- * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
- * to convert it, we "only" support 2^32 bytes chunk data.
+ * Neither RFC2616 nor the later HTTP specs define a maximum chunk size.
+ * For 64 bit curl_off_t we support 16 digits. For 32 bit, 8 digits.
  */
-#define MAXNUM_SIZE 16
+#define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2)
 
 typedef enum {
   /* await and buffer all hexadecimal digits until we get one that isn't a
@@ -48,7 +48,7 @@ typedef enum {
      big deal. */
   CHUNK_POSTLF,
 
-  /* Used to mark that we're out of the game.  NOTE: that there's a 'dataleft'
+  /* Used to mark that we're out of the game.  NOTE: that there's a 'datasize'
      field in the struct that will tell how many bytes that were not passed to
      the client in the end of the last buffer! */
   CHUNK_STOP,
@@ -83,16 +83,15 @@ typedef enum {
 const char *Curl_chunked_strerror(CHUNKcode code);
 
 struct Curl_chunker {
-  char hexbuffer[ MAXNUM_SIZE + 1];
-  int hexindex;
-  ChunkyState state;
   curl_off_t datasize;
-  size_t dataleft; /* untouched data amount at the end of the last buffer */
+  ChunkyState state;
+  unsigned char hexindex;
+  char hexbuffer[ CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */
 };
 
 /* The following functions are defined in http_chunks.c */
-void Curl_httpchunk_init(struct connectdata *conn);
-CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
+void Curl_httpchunk_init(struct Curl_easy *data);
+CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *datap,
                               ssize_t length, ssize_t *wrote,
                               CURLcode *passthru);
 
index b06dc0d..596b215 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -41,13 +41,11 @@ Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
 
 */
 
-CURLcode Curl_input_digest(struct connectdata *conn,
+CURLcode Curl_input_digest(struct Curl_easy *data,
                            bool proxy,
                            const char *header) /* rest of the *-authenticate:
                                                   header */
 {
-  struct Curl_easy *data = conn->data;
-
   /* Point to the correct struct with this */
   struct digestdata *digest;
 
@@ -68,13 +66,13 @@ CURLcode Curl_input_digest(struct connectdata *conn,
   return Curl_auth_decode_digest_http_message(header, digest);
 }
 
-CURLcode Curl_output_digest(struct connectdata *conn,
+CURLcode Curl_output_digest(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool proxy,
                             const unsigned char *request,
                             const unsigned char *uripath)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   unsigned char *path = NULL;
   char *tmp = NULL;
   char *response;
index 96e39a7..106caa7 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
 
 /* this is for digest header input */
-CURLcode Curl_input_digest(struct connectdata *conn,
+CURLcode Curl_input_digest(struct Curl_easy *data,
                            bool proxy, const char *header);
 
 /* this is for creating digest header output */
-CURLcode Curl_output_digest(struct connectdata *conn,
+CURLcode Curl_output_digest(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool proxy,
                             const unsigned char *request,
                             const unsigned char *uripath);
index 0a19ec2..d759748 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "curl_memory.h"
 #include "memdebug.h"
 
-CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
-                              const char *header)
+CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
+                              bool proxy, const char *header)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   size_t len;
 
   /* Point to the username, password, service and host */
@@ -90,7 +89,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
   neg_ctx->havenegdata = len != 0;
   if(!len) {
     if(state == GSS_AUTHSUCC) {
-      infof(conn->data, "Negotiate auth restarted\n");
+      infof(data, "Negotiate auth restarted\n");
       Curl_http_auth_cleanup_negotiate(conn);
     }
     else if(state != GSS_AUTHNONE) {
@@ -116,15 +115,14 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
   return result;
 }
 
-CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
+CURLcode Curl_output_negotiate(struct Curl_easy *data,
+                               struct connectdata *conn, bool proxy)
 {
   struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
     &conn->negotiate;
-  struct auth *authp = proxy ? &conn->data->state.authproxy :
-    &conn->data->state.authhost;
+  struct auth *authp = proxy ? &data->state.authproxy : &data->state.authhost;
   curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
     &conn->http_negotiate_state;
-  struct Curl_easy *data = conn->data;
   char *base64 = NULL;
   size_t len = 0;
   char *userp;
@@ -147,12 +145,12 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
     (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
 
     if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
-      infof(conn->data, "Curl_output_negotiate, "
+      infof(data, "Curl_output_negotiate, "
        "no persistent authentication: cleanup existing context");
       Curl_http_auth_cleanup_negotiate(conn);
     }
     if(!neg_ctx->context) {
-      result = Curl_input_negotiate(conn, proxy, "Negotiate");
+      result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
       if(result == CURLE_AUTH_ERROR) {
         /* negotiate auth failed, let's continue unauthenticated to stay
          * compatible with the behavior before curl-7_64_0-158-g6c6035532 */
@@ -163,8 +161,7 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
         return result;
     }
 
-    result = Curl_auth_create_spnego_message(conn->data,
-      neg_ctx, &base64, &len);
+    result = Curl_auth_create_spnego_message(data, neg_ctx, &base64, &len);
     if(result)
       return result;
 
index a737f6f..2640a3e 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
 
 /* this is for Negotiate header input */
-CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
-                              const char *header);
+CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
+                              bool proxy, const char *header);
 
 /* this is for creating Negotiate header output */
-CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
+CURLcode Curl_output_negotiate(struct Curl_easy *data,
+                               struct connectdata *conn, bool proxy);
 
 void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
 
index cab543c..6cb829e 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -59,7 +59,7 @@
 # define DEBUG_OUT(x) Curl_nop_stmt
 #endif
 
-CURLcode Curl_input_ntlm(struct connectdata *conn,
+CURLcode Curl_input_ntlm(struct Curl_easy *data,
                          bool proxy,         /* if proxy or not */
                          const char *header) /* rest of the www-authenticate:
                                                 header */
@@ -68,6 +68,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
   struct ntlmdata *ntlm;
   curlntlm *state;
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
   state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
@@ -79,7 +80,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
       header++;
 
     if(*header) {
-      result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm);
+      result = Curl_auth_decode_ntlm_type2_message(data, header, ntlm);
       if(result)
         return result;
 
@@ -87,17 +88,17 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
     }
     else {
       if(*state == NTLMSTATE_LAST) {
-        infof(conn->data, "NTLM auth restarted\n");
+        infof(data, "NTLM auth restarted\n");
         Curl_http_auth_cleanup_ntlm(conn);
       }
       else if(*state == NTLMSTATE_TYPE3) {
-        infof(conn->data, "NTLM handshake rejected\n");
+        infof(data, "NTLM handshake rejected\n");
         Curl_http_auth_cleanup_ntlm(conn);
         *state = NTLMSTATE_NONE;
         return CURLE_REMOTE_ACCESS_DENIED;
       }
       else if(*state >= NTLMSTATE_TYPE1) {
-        infof(conn->data, "NTLM handshake failure (internal error)\n");
+        infof(data, "NTLM handshake failure (internal error)\n");
         return CURLE_REMOTE_ACCESS_DENIED;
       }
 
@@ -111,7 +112,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
 /*
  * This is for creating ntlm header output
  */
-CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
+CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
 {
   char *base64 = NULL;
   size_t len = 0;
@@ -131,8 +132,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   struct ntlmdata *ntlm;
   curlntlm *state;
   struct auth *authp;
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
 
   DEBUGASSERT(conn);
   DEBUGASSERT(data);
@@ -142,12 +142,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
     allocuserpwd = &data->state.aptr.proxyuserpwd;
     userp = conn->http_proxy.user;
     passwdp = conn->http_proxy.passwd;
-    service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ?
-              conn->data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+    service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+              data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     hostname = conn->http_proxy.host.name;
     ntlm = &conn->proxyntlm;
     state = &conn->proxy_ntlm_state;
-    authp = &conn->data->state.authproxy;
+    authp = &data->state.authproxy;
 #else
     return CURLE_NOT_BUILT_IN;
 #endif
@@ -156,12 +156,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
     allocuserpwd = &data->state.aptr.userpwd;
     userp = conn->user;
     passwdp = conn->passwd;
-    service = conn->data->set.str[STRING_SERVICE_NAME] ?
-              conn->data->set.str[STRING_SERVICE_NAME] : "HTTP";
+    service = data->set.str[STRING_SERVICE_NAME] ?
+              data->set.str[STRING_SERVICE_NAME] : "HTTP";
     hostname = conn->host.name;
     ntlm = &conn->ntlm;
     state = &conn->http_ntlm_state;
-    authp = &conn->data->state.authhost;
+    authp = &data->state.authhost;
   }
   authp->done = FALSE;
 
@@ -188,7 +188,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
     /* Create a type-1 message */
-    result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp,
+    result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
                                                  service, hostname,
                                                  ntlm, &base64,
                                                  &len);
@@ -210,7 +210,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
 
   case NTLMSTATE_TYPE2:
     /* We already received the type-2 message, create a type-3 message */
-    result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp,
+    result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
                                                  ntlm, &base64, &len);
     if(result)
       return result;
index 3ebdf97..5b4fa00 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
 
 /* this is for ntlm header input */
-CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
+CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy,
                          const char *header);
 
 /* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy);
 
 void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
 
index f188cbf..a03a27f 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -27,6 +27,9 @@
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 
 #include <curl/curl.h>
+#ifdef USE_HYPER
+#include <hyper.h>
+#endif
 #include "sendf.h"
 #include "http.h"
 #include "url.h"
  * proxy_ssl_connected connection bit when complete.  Can be
  * called multiple times.
  */
-static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex)
+static CURLcode https_proxy_connect(struct Curl_easy *data, int sockindex)
 {
 #ifdef USE_SSL
+  struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
   DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS);
   if(!conn->bits.proxy_ssl_connected[sockindex]) {
     /* perform SSL initialization for this socket */
     result =
-      Curl_ssl_connect_nonblocking(conn, sockindex,
+      Curl_ssl_connect_nonblocking(data, conn, sockindex,
                                    &conn->bits.proxy_ssl_connected[sockindex]);
     if(result)
       /* a failed connection is marked for closure to prevent (bad) re-use or
@@ -64,17 +68,17 @@ static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex)
   }
   return result;
 #else
-  (void) conn;
+  (void) data;
   (void) sockindex;
   return CURLE_NOT_BUILT_IN;
 #endif
 }
 
-CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
+CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
-    const CURLcode result = https_proxy_connect(conn, sockindex);
+    const CURLcode result = https_proxy_connect(data, sockindex);
     if(result)
       return result;
     if(!conn->bits.proxy_ssl_connected[sockindex])
@@ -102,9 +106,9 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
      * This function might be called several times in the multi interface case
      * if the proxy's CONNECT response is not instant.
      */
-    prot_save = conn->data->req.protop;
+    prot_save = data->req.p.http;
     memset(&http_proxy, 0, sizeof(http_proxy));
-    conn->data->req.protop = &http_proxy;
+    data->req.p.http = &http_proxy;
     connkeep(conn, "HTTP proxy CONNECT");
 
     /* for the secondary socket (FTP), use the "connect to host"
@@ -124,8 +128,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
       remote_port = conn->conn_to_port;
     else
       remote_port = conn->remote_port;
-    result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port);
-    conn->data->req.protop = prot_save;
+    result = Curl_proxyCONNECT(data, sockindex, hostname, remote_port);
+    data->req.p.http = prot_save;
     if(CURLE_OK != result)
       return result;
     Curl_safefree(data->state.aptr.proxyuserpwd);
@@ -149,15 +153,16 @@ bool Curl_connect_ongoing(struct connectdata *conn)
     (conn->connect_state->tunnel_state != TUNNEL_COMPLETE);
 }
 
-static CURLcode connect_init(struct connectdata *conn, bool reinit)
+static CURLcode connect_init(struct Curl_easy *data, bool reinit)
 {
   struct http_connect_state *s;
+  struct connectdata *conn = data->conn;
   if(!reinit) {
     DEBUGASSERT(!conn->connect_state);
     s = calloc(1, sizeof(struct http_connect_state));
     if(!s)
       return CURLE_OUT_OF_MEMORY;
-    infof(conn->data, "allocate connect buffer!\n");
+    infof(data, "allocate connect buffer!\n");
     conn->connect_state = s;
     Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
   }
@@ -167,29 +172,63 @@ static CURLcode connect_init(struct connectdata *conn, bool reinit)
     Curl_dyn_reset(&s->rcvbuf);
   }
   s->tunnel_state = TUNNEL_INIT;
-  s->keepon = TRUE;
+  s->keepon = KEEPON_CONNECT;
   s->cl = 0;
   s->close_connection = FALSE;
   return CURLE_OK;
 }
 
-static void connect_done(struct connectdata *conn)
+static void connect_done(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct http_connect_state *s = conn->connect_state;
   s->tunnel_state = TUNNEL_COMPLETE;
   Curl_dyn_free(&s->rcvbuf);
-  infof(conn->data, "CONNECT phase completed!\n");
+  infof(data, "CONNECT phase completed!\n");
+}
+
+static CURLcode CONNECT_host(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const char *hostname,
+                             int remote_port,
+                             char **connecthostp,
+                             char **hostp)
+{
+  char *hostheader; /* for CONNECT */
+  char *host = NULL; /* Host: */
+  bool ipv6_ip = conn->bits.ipv6_ip;
+
+  /* the hostname may be different */
+  if(hostname != conn->host.name)
+    ipv6_ip = (strchr(hostname, ':') != NULL);
+  hostheader = /* host:port with IPv6 support */
+    aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
+            remote_port);
+  if(!hostheader)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!Curl_checkProxyheaders(data, conn, "Host")) {
+    host = aprintf("Host: %s\r\n", hostheader);
+    if(!host) {
+      free(hostheader);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  *connecthostp = hostheader;
+  *hostp = host;
+  return CURLE_OK;
 }
 
-static CURLcode CONNECT(struct connectdata *conn,
+static CURLcode CONNECT(struct Curl_easy *data,
                         int sockindex,
                         const char *hostname,
                         int remote_port)
+#ifndef USE_HYPER
 {
   int subversion = 0;
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
   CURLcode result;
+  struct connectdata *conn = data->conn;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
   struct http_connect_state *s = conn->connect_state;
   char *linep;
@@ -207,8 +246,9 @@ static CURLcode CONNECT(struct connectdata *conn,
     timediff_t check;
     if(TUNNEL_INIT == s->tunnel_state) {
       /* BEGIN CONNECT PHASE */
-      char *host_port;
       struct dynbuf req;
+      char *hostheader = NULL;
+      char *host = NULL;
 
       infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
             hostname, remote_port);
@@ -219,50 +259,28 @@ static CURLcode CONNECT(struct connectdata *conn,
       free(data->req.newurl);
       data->req.newurl = NULL;
 
-      host_port = aprintf("%s:%d", hostname, remote_port);
-      if(!host_port)
-        return CURLE_OUT_OF_MEMORY;
-
       /* initialize a dynamic send-buffer */
       Curl_dyn_init(&req, DYN_HTTP_REQUEST);
 
-      /* Setup the proxy-authorization header, if any */
-      result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE);
+      result = CONNECT_host(data, conn,
+                            hostname, remote_port, &hostheader, &host);
+      if(result)
+        return result;
 
-      free(host_port);
+      /* Setup the proxy-authorization header, if any */
+      result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+                                     hostheader, TRUE);
 
       if(!result) {
-        char *host = NULL;
         const char *proxyconn = "";
         const char *useragent = "";
         const char *httpv =
           (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1";
-        bool ipv6_ip = conn->bits.ipv6_ip;
-        char *hostheader;
-
-        /* the hostname may be different */
-        if(hostname != conn->host.name)
-          ipv6_ip = (strchr(hostname, ':') != NULL);
-        hostheader = /* host:port with IPv6 support */
-          aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
-                  remote_port);
-        if(!hostheader) {
-          Curl_dyn_free(&req);
-          return CURLE_OUT_OF_MEMORY;
-        }
 
-        if(!Curl_checkProxyheaders(conn, "Host")) {
-          host = aprintf("Host: %s\r\n", hostheader);
-          if(!host) {
-            free(hostheader);
-            Curl_dyn_free(&req);
-            return CURLE_OUT_OF_MEMORY;
-          }
-        }
-        if(!Curl_checkProxyheaders(conn, "Proxy-Connection"))
+        if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection"))
           proxyconn = "Proxy-Connection: Keep-Alive\r\n";
 
-        if(!Curl_checkProxyheaders(conn, "User-Agent") &&
+        if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
            data->set.str[STRING_USERAGENT])
           useragent = data->state.aptr.uagent;
 
@@ -281,12 +299,8 @@ static CURLcode CONNECT(struct connectdata *conn,
                         useragent,
                         proxyconn);
 
-        if(host)
-          free(host);
-        free(hostheader);
-
         if(!result)
-          result = Curl_add_custom_headers(conn, TRUE, &req);
+          result = Curl_add_custom_headers(data, TRUE, &req);
 
         if(!result)
           /* CRLF terminate the request */
@@ -295,13 +309,14 @@ static CURLcode CONNECT(struct connectdata *conn,
         if(!result) {
           /* Send the connect request to the proxy */
           /* BLOCKING */
-          result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
+          result = Curl_buffer_send(&req, data, &data->info.request_size, 0,
                                     sockindex);
         }
         if(result)
           failf(data, "Failed sending CONNECT to proxy");
       }
-
+      free(host);
+      free(hostheader);
       Curl_dyn_free(&req);
       if(result)
         return result;
@@ -330,16 +345,16 @@ static CURLcode CONNECT(struct connectdata *conn,
 
         /* Read one byte at a time to avoid a race condition. Wait at most one
            second before looping to ensure continuous pgrsUpdates. */
-        result = Curl_read(conn, tunnelsocket, &byte, 1, &gotbytes);
+        result = Curl_read(data, tunnelsocket, &byte, 1, &gotbytes);
         if(result == CURLE_AGAIN)
           /* socket buffer drained, return */
           return CURLE_OK;
 
-        if(Curl_pgrsUpdate(conn))
+        if(Curl_pgrsUpdate(data))
           return CURLE_ABORTED_BY_CALLBACK;
 
         if(result) {
-          s->keepon = FALSE;
+          s->keepon = KEEPON_DONE;
           break;
         }
         else if(gotbytes <= 0) {
@@ -353,11 +368,11 @@ static CURLcode CONNECT(struct connectdata *conn,
             error = SELECT_ERROR;
             failf(data, "Proxy CONNECT aborted");
           }
-          s->keepon = FALSE;
+          s->keepon = KEEPON_DONE;
           break;
         }
 
-        if(s->keepon > TRUE) {
+        if(s->keepon == KEEPON_IGNORE) {
           /* This means we are currently ignoring a response-body */
 
           if(s->cl) {
@@ -365,7 +380,7 @@ static CURLcode CONNECT(struct connectdata *conn,
                and make sure to break out of the loop when we're done! */
             s->cl--;
             if(s->cl <= 0) {
-              s->keepon = FALSE;
+              s->keepon = KEEPON_DONE;
               s->tunnel_state = TUNNEL_COMPLETE;
               break;
             }
@@ -379,11 +394,11 @@ static CURLcode CONNECT(struct connectdata *conn,
 
             /* now parse the chunked piece of data so that we can
                properly tell when the stream ends */
-            r = Curl_httpchunk_read(conn, &byte, 1, &tookcareof, &extra);
+            r = Curl_httpchunk_read(data, &byte, 1, &tookcareof, &extra);
             if(r == CHUNKE_STOP) {
               /* we're done reading chunks! */
               infof(data, "chunk reading DONE\n");
-              s->keepon = FALSE;
+              s->keepon = KEEPON_DONE;
               /* we did the full CONNECT treatment, go COMPLETE */
               s->tunnel_state = TUNNEL_COMPLETE;
             }
@@ -410,8 +425,7 @@ static CURLcode CONNECT(struct connectdata *conn,
           return result;
 
         /* output debug if that is requested */
-        if(data->set.verbose)
-          Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
+        Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
 
         if(!data->set.suppress_connect_headers) {
           /* send the header to the callback */
@@ -419,13 +433,12 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(data->set.include_header)
             writetype |= CLIENTWRITE_BODY;
 
-          result = Curl_client_write(conn, writetype, linep, perline);
+          result = Curl_client_write(data, writetype, linep, perline);
           if(result)
             return result;
         }
 
         data->info.header_size += (long)perline;
-        data->req.headerbytecount += (long)perline;
 
         /* Newlines are CRLF, so the CR is ignored as the line isn't
            really terminated until the LF comes. Treat a following CR
@@ -439,7 +452,7 @@ static CURLcode CONNECT(struct connectdata *conn,
             /* If we get a 407 response code with content length
                when we have no auth problem, we must ignore the
                whole response-body */
-            s->keepon = 2;
+            s->keepon = KEEPON_IGNORE;
 
             if(s->cl) {
               infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
@@ -462,12 +475,12 @@ static CURLcode CONNECT(struct connectdata *conn,
 
               /* now parse the chunked piece of data so that we can properly
                  tell when the stream ends */
-              r = Curl_httpchunk_read(conn, linep + 1, 1, &gotbytes,
+              r = Curl_httpchunk_read(data, linep + 1, 1, &gotbytes,
                                       &extra);
               if(r == CHUNKE_STOP) {
                 /* we're done reading chunks! */
                 infof(data, "chunk reading DONE\n");
-                s->keepon = FALSE;
+                s->keepon = KEEPON_DONE;
                 /* we did the full CONNECT treatment, go to COMPLETE */
                 s->tunnel_state = TUNNEL_COMPLETE;
               }
@@ -476,14 +489,17 @@ static CURLcode CONNECT(struct connectdata *conn,
               /* without content-length or chunked encoding, we
                  can't keep the connection alive since the close is
                  the end signal so we bail out at once instead */
-              s->keepon = FALSE;
+              s->keepon = KEEPON_DONE;
             }
           }
           else
-            s->keepon = FALSE;
-          if(!s->cl)
+            s->keepon = KEEPON_DONE;
+
+          if(s->keepon == KEEPON_DONE && !s->cl)
             /* we did the full CONNECT treatment, go to COMPLETE */
             s->tunnel_state = TUNNEL_COMPLETE;
+
+          DEBUGASSERT(s->keepon == KEEPON_IGNORE || s->keepon == KEEPON_DONE);
           continue;
         }
 
@@ -497,7 +513,7 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(!auth)
             return CURLE_OUT_OF_MEMORY;
 
-          result = Curl_http_input_auth(conn, proxy, auth);
+          result = Curl_http_input_auth(data, proxy, auth);
 
           free(auth);
 
@@ -532,7 +548,7 @@ static CURLcode CONNECT(struct connectdata *conn,
             infof(data, "CONNECT responded chunked\n");
             s->chunked_encoding = TRUE;
             /* init our chunky engine */
-            Curl_httpchunk_init(conn);
+            Curl_httpchunk_init(data);
           }
         }
         else if(Curl_compareheader(linep, "Proxy-Connection:", "close"))
@@ -547,7 +563,7 @@ static CURLcode CONNECT(struct connectdata *conn,
         Curl_dyn_reset(&s->rcvbuf);
       } /* while there's buffer left and loop is requested */
 
-      if(Curl_pgrsUpdate(conn))
+      if(Curl_pgrsUpdate(data))
         return CURLE_ABORTED_BY_CALLBACK;
 
       if(error)
@@ -556,7 +572,7 @@ static CURLcode CONNECT(struct connectdata *conn,
       if(data->info.httpproxycode/100 != 2) {
         /* Deal with the possibly already received authenticate
            headers. 'newurl' is set to a new URL if we must loop. */
-        result = Curl_http_auth_act(conn);
+        result = Curl_http_auth_act(data);
         if(result)
           return result;
 
@@ -569,7 +585,7 @@ static CURLcode CONNECT(struct connectdata *conn,
 
       if(s->close_connection && data->req.newurl) {
         /* Connection closed by server. Don't use it anymore */
-        Curl_closesocket(conn, conn->sock[sockindex]);
+        Curl_closesocket(data, conn, conn->sock[sockindex]);
         conn->sock[sockindex] = CURL_SOCKET_BAD;
         break;
       }
@@ -579,7 +595,7 @@ static CURLcode CONNECT(struct connectdata *conn,
      * means the HTTP authentication is still going on so if the tunnel
      * is complete we start over in INIT state */
     if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
-      connect_init(conn, TRUE); /* reinit */
+      connect_init(data, TRUE); /* reinit */
     }
 
   } while(data->req.newurl);
@@ -588,14 +604,14 @@ static CURLcode CONNECT(struct connectdata *conn,
     if(s->close_connection && data->req.newurl) {
       conn->bits.proxy_connect_closed = TRUE;
       infof(data, "Connect me again please\n");
-      connect_done(conn);
+      connect_done(data);
     }
     else {
       free(data->req.newurl);
       data->req.newurl = NULL;
       /* failure, close this connection to avoid re-use */
       streamclose(conn, "proxy CONNECT failure");
-      Curl_closesocket(conn, conn->sock[sockindex]);
+      Curl_closesocket(data, conn, conn->sock[sockindex]);
       conn->sock[sockindex] = CURL_SOCKET_BAD;
     }
 
@@ -630,6 +646,225 @@ static CURLcode CONNECT(struct connectdata *conn,
   Curl_dyn_free(&s->rcvbuf);
   return CURLE_OK;
 }
+#else
+/* The Hyper version of CONNECT */
+{
+  struct connectdata *conn = data->conn;
+  struct hyptransfer *h = &data->hyp;
+  curl_socket_t tunnelsocket = conn->sock[sockindex];
+  struct http_connect_state *s = conn->connect_state;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  hyper_io *io = NULL;
+  hyper_request *req = NULL;
+  hyper_headers *headers = NULL;
+  hyper_clientconn_options *options = NULL;
+  hyper_task *handshake = NULL;
+  hyper_task *task = NULL; /* for the handshake */
+  hyper_task *sendtask = NULL; /* for the send */
+  hyper_clientconn *client = NULL;
+  hyper_error *hypererr = NULL;
+  char *hostheader = NULL; /* for CONNECT */
+  char *host = NULL; /* Host: */
+
+  if(Curl_connect_complete(conn))
+    return CURLE_OK; /* CONNECT is already completed */
+
+  conn->bits.proxy_connect_closed = FALSE;
+
+  do {
+    switch(s->tunnel_state) {
+    case TUNNEL_INIT:
+      /* BEGIN CONNECT PHASE */
+      io = hyper_io_new();
+      if(!io) {
+        failf(data, "Couldn't create hyper IO");
+        goto error;
+      }
+      /* tell Hyper how to read/write network data */
+      hyper_io_set_userdata(io, data);
+      hyper_io_set_read(io, Curl_hyper_recv);
+      hyper_io_set_write(io, Curl_hyper_send);
+      conn->sockfd = tunnelsocket;
+
+      /* create an executor to poll futures */
+      if(!h->exec) {
+        h->exec = hyper_executor_new();
+        if(!h->exec) {
+          failf(data, "Couldn't create hyper executor");
+          goto error;
+        }
+      }
+
+      options = hyper_clientconn_options_new();
+      if(!options) {
+        failf(data, "Couldn't create hyper client options");
+        goto error;
+      }
+
+      hyper_clientconn_options_exec(options, h->exec);
+
+      /* "Both the `io` and the `options` are consumed in this function
+         call" */
+      handshake = hyper_clientconn_handshake(io, options);
+      if(!handshake) {
+        failf(data, "Couldn't create hyper client handshake");
+        goto error;
+      }
+      io = NULL;
+      options = NULL;
+
+      if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+        failf(data, "Couldn't hyper_executor_push the handshake");
+        goto error;
+      }
+      handshake = NULL; /* ownership passed on */
+
+      task = hyper_executor_poll(h->exec);
+      if(!task) {
+        failf(data, "Couldn't hyper_executor_poll the handshake");
+        goto error;
+      }
+
+      client = hyper_task_value(task);
+      hyper_task_free(task);
+      req = hyper_request_new();
+      if(!req) {
+        failf(data, "Couldn't hyper_request_new");
+        goto error;
+      }
+      if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
+                                  strlen("CONNECT"))) {
+        failf(data, "error setting method");
+        goto error;
+      }
+
+      result = CONNECT_host(data, conn, hostname, remote_port,
+                            &hostheader, &host);
+      if(result)
+        goto error;
+
+      if(hyper_request_set_uri(req, (uint8_t *)hostheader,
+                               strlen(hostheader))) {
+        failf(data, "error setting path");
+        result = CURLE_OUT_OF_MEMORY;
+      }
+      /* Setup the proxy-authorization header, if any */
+      result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+                                     hostheader, TRUE);
+      if(result)
+        goto error;
+      Curl_safefree(hostheader);
+
+      /* default is 1.1 */
+      if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
+         (HYPERE_OK != hyper_request_set_version(req,
+                                                 HYPER_HTTP_VERSION_1_0))) {
+        failf(data, "error settting HTTP version");
+        goto error;
+      }
+
+      headers = hyper_request_headers(req);
+      if(!headers) {
+        failf(data, "hyper_request_headers");
+        goto error;
+      }
+      if(host && Curl_hyper_header(data, headers, host))
+        goto error;
+      Curl_safefree(host);
+
+      if(data->state.aptr.proxyuserpwd &&
+         Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
+        goto error;
+
+      if(data->set.str[STRING_USERAGENT] &&
+         *data->set.str[STRING_USERAGENT] &&
+         data->state.aptr.uagent &&
+         Curl_hyper_header(data, headers, data->state.aptr.uagent))
+        goto error;
+
+      if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
+         Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
+        goto error;
+
+      sendtask = hyper_clientconn_send(client, req);
+      if(!sendtask) {
+        failf(data, "hyper_clientconn_send");
+        goto error;
+      }
+
+      if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+        failf(data, "Couldn't hyper_executor_push the send");
+        goto error;
+      }
+
+      hyper_clientconn_free(client);
+
+      do {
+        task = hyper_executor_poll(h->exec);
+        if(task) {
+          bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
+          if(error)
+            hypererr = hyper_task_value(task);
+          hyper_task_free(task);
+          if(error)
+            goto error;
+        }
+      } while(task);
+      s->tunnel_state = TUNNEL_CONNECT;
+      /* FALLTHROUGH */
+    case TUNNEL_CONNECT: {
+      int didwhat;
+      bool done = FALSE;
+      result = Curl_hyper_stream(data, conn, &didwhat, &done,
+                                 CURL_CSELECT_IN | CURL_CSELECT_OUT);
+      if(result)
+        goto error;
+      if(!done)
+        break;
+      fprintf(stderr, "done\n");
+      s->tunnel_state = TUNNEL_COMPLETE;
+      if(h->exec) {
+        hyper_executor_free(h->exec);
+        h->exec = NULL;
+      }
+      if(h->read_waker) {
+        hyper_waker_free(h->read_waker);
+        h->read_waker = NULL;
+      }
+      if(h->write_waker) {
+        hyper_waker_free(h->write_waker);
+        h->write_waker = NULL;
+      }
+    }
+      /* FALLTHROUGH */
+    default:
+      break;
+    }
+  } while(data->req.newurl);
+
+  result = CURLE_OK;
+  error:
+  free(host);
+  free(hostheader);
+  if(io)
+    hyper_io_free(io);
+
+  if(options)
+    hyper_clientconn_options_free(options);
+
+  if(handshake)
+    hyper_task_free(handshake);
+
+  if(hypererr) {
+    uint8_t errbuf[256];
+    size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+    failf(data, "Hyper: %.*s", (int)errlen, errbuf);
+    hyper_error_free(hypererr);
+  }
+  return result;
+}
+
+#endif
 
 void Curl_connect_free(struct Curl_easy *data)
 {
@@ -647,21 +882,22 @@ void Curl_connect_free(struct Curl_easy *data)
  * this proxy. After that, the socket can be used just as a normal socket.
  */
 
-CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
                            int sockindex,
                            const char *hostname,
                            int remote_port)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   if(!conn->connect_state) {
-    result = connect_init(conn, FALSE);
+    result = connect_init(data, FALSE);
     if(result)
       return result;
   }
-  result = CONNECT(conn, sockindex, hostname, remote_port);
+  result = CONNECT(data, sockindex, hostname, remote_port);
 
   if(result || Curl_connect_complete(conn))
-    connect_done(conn);
+    connect_done(data);
 
   return result;
 }
index 29988a6..a78db0d 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 /* ftp can use this as well */
-CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
                            int tunnelsocket,
                            const char *hostname, int remote_port);
 
 /* Default proxy timeout in milliseconds */
 #define PROXY_TIMEOUT (3600*1000)
 
-CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex);
 
 bool Curl_connect_complete(struct connectdata *conn);
 bool Curl_connect_ongoing(struct connectdata *conn);
index 2f5850d..1d475a4 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 3938869..21e00b1 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index f193d42..e074e47 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index cad0e59..2d80699 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "memdebug.h"
 
 /* Local API functions */
-static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
-static CURLcode imap_do(struct connectdata *conn, bool *done);
-static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+static CURLcode imap_regular_transfer(struct Curl_easy *data, bool *done);
+static CURLcode imap_do(struct Curl_easy *data, bool *done);
+static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
                           bool premature);
-static CURLcode imap_connect(struct connectdata *conn, bool *done);
-static CURLcode imap_disconnect(struct connectdata *conn, bool dead);
-static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
-static int imap_getsock(struct connectdata *conn, curl_socket_t *socks);
-static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done);
-static CURLcode imap_setup_connection(struct connectdata *conn);
+static CURLcode imap_connect(struct Curl_easy *data, bool *done);
+static CURLcode imap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done);
+static int imap_getsock(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t *socks);
+static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode imap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
 static char *imap_atom(const char *str, bool escape_only);
-static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);
+static CURLcode imap_sendf(struct Curl_easy *data,
+                           struct connectdata *conn, const char *fmt, ...);
 static CURLcode imap_parse_url_options(struct connectdata *conn);
-static CURLcode imap_parse_url_path(struct connectdata *conn);
-static CURLcode imap_parse_custom_request(struct connectdata *conn);
-static CURLcode imap_perform_authenticate(struct connectdata *conn,
+static CURLcode imap_parse_url_path(struct Curl_easy *data);
+static CURLcode imap_parse_custom_request(struct Curl_easy *data);
+static CURLcode imap_perform_authenticate(struct Curl_easy *data,
+                                          struct connectdata *conn,
                                           const char *mech,
                                           const char *initresp);
-static CURLcode imap_continue_authenticate(struct connectdata *conn,
+static CURLcode imap_continue_authenticate(struct Curl_easy *data,
+                                           struct connectdata *conn,
                                            const char *resp);
 static void imap_get_message(char *buffer, char **outptr);
 
@@ -132,6 +138,7 @@ const struct Curl_handler Curl_handler_imap = {
   ZERO_NULL,                        /* connection_check */
   PORT_IMAP,                        /* defport */
   CURLPROTO_IMAP,                   /* protocol */
+  CURLPROTO_IMAP,                   /* family */
   PROTOPT_CLOSEACTION|              /* flags */
   PROTOPT_URLOPTIONS
 };
@@ -159,6 +166,7 @@ const struct Curl_handler Curl_handler_imaps = {
   ZERO_NULL,                        /* connection_check */
   PORT_IMAPS,                       /* defport */
   CURLPROTO_IMAPS,                  /* protocol */
+  CURLPROTO_IMAP,                   /* family */
   PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
   PROTOPT_URLOPTIONS
 };
@@ -241,10 +249,10 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd)
  * Checks whether the given string is a valid tagged, untagged or continuation
  * response which can be processed by the response handler.
  */
-static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
-                           int *resp)
+static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                           char *line, size_t len, int *resp)
 {
-  struct IMAP *imap = conn->data->req.protop;
+  struct IMAP *imap = data->req.p.imap;
   struct imap_conn *imapc = &conn->proto.imapc;
   const char *id = imapc->resptag;
   size_t id_len = strlen(id);
@@ -326,7 +334,7 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
         break;
 
       default:
-        failf(conn->data, "Unexpected continuation response");
+        failf(data, "Unexpected continuation response");
         *resp = -1;
         break;
     }
@@ -379,9 +387,9 @@ static void imap_get_message(char *buffer, char **outptr)
  *
  * This is the ONLY way to change IMAP state!
  */
-static void state(struct connectdata *conn, imapstate newstate)
+static void state(struct Curl_easy *data, imapstate newstate)
 {
-  struct imap_conn *imapc = &conn->proto.imapc;
+  struct imap_conn *imapc = &data->conn->proto.imapc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
   static const char * const names[]={
@@ -404,7 +412,7 @@ static void state(struct connectdata *conn, imapstate newstate)
   };
 
   if(imapc->state != newstate)
-    infof(conn->data, "IMAP %p state change from %s to %s\n",
+    infof(data, "IMAP %p state change from %s to %s\n",
           (void *)imapc, names[imapc->state], names[newstate]);
 #endif
 
@@ -418,7 +426,8 @@ static void state(struct connectdata *conn, imapstate newstate)
  * Sends the CAPABILITY command in order to obtain a list of server side
  * supported capabilities.
  */
-static CURLcode imap_perform_capability(struct connectdata *conn)
+static CURLcode imap_perform_capability(struct Curl_easy *data,
+                                        struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct imap_conn *imapc = &conn->proto.imapc;
@@ -427,10 +436,10 @@ static CURLcode imap_perform_capability(struct connectdata *conn)
   imapc->tls_supported = FALSE;           /* Clear the TLS capability */
 
   /* Send the CAPABILITY command */
-  result = imap_sendf(conn, "CAPABILITY");
+  result = imap_sendf(data, conn, "CAPABILITY");
 
   if(!result)
-    state(conn, IMAP_CAPABILITY);
+    state(data, IMAP_CAPABILITY);
 
   return result;
 }
@@ -441,13 +450,14 @@ static CURLcode imap_perform_capability(struct connectdata *conn)
  *
  * Sends the STARTTLS command to start the upgrade to TLS.
  */
-static CURLcode imap_perform_starttls(struct connectdata *conn)
+static CURLcode imap_perform_starttls(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   /* Send the STARTTLS command */
-  CURLcode result = imap_sendf(conn, "STARTTLS");
+  CURLcode result = imap_sendf(data, conn, "STARTTLS");
 
   if(!result)
-    state(conn, IMAP_STARTTLS);
+    state(data, IMAP_STARTTLS);
 
   return result;
 }
@@ -458,20 +468,21 @@ static CURLcode imap_perform_starttls(struct connectdata *conn)
  *
  * Performs the upgrade to TLS.
  */
-static CURLcode imap_perform_upgrade_tls(struct connectdata *conn)
+static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
+                                         struct connectdata *conn)
 {
   /* Start the SSL connection */
   struct imap_conn *imapc = &conn->proto.imapc;
-  CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
+  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
                                                  &imapc->ssldone);
 
   if(!result) {
     if(imapc->state != IMAP_UPGRADETLS)
-      state(conn, IMAP_UPGRADETLS);
+      state(data, IMAP_UPGRADETLS);
 
     if(imapc->ssldone) {
       imap_to_imaps(conn);
-      result = imap_perform_capability(conn);
+      result = imap_perform_capability(data, conn);
     }
   }
 
@@ -484,7 +495,8 @@ static CURLcode imap_perform_upgrade_tls(struct connectdata *conn)
  *
  * Sends a clear text LOGIN command to authenticate with.
  */
-static CURLcode imap_perform_login(struct connectdata *conn)
+static CURLcode imap_perform_login(struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   char *user;
@@ -493,7 +505,7 @@ static CURLcode imap_perform_login(struct connectdata *conn)
   /* Check we have a username and password to authenticate with and end the
      connect phase if we don't */
   if(!conn->bits.user_passwd) {
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
 
     return result;
   }
@@ -503,14 +515,14 @@ static CURLcode imap_perform_login(struct connectdata *conn)
   passwd = imap_atom(conn->passwd, false);
 
   /* Send the LOGIN command */
-  result = imap_sendf(conn, "LOGIN %s %s", user ? user : "",
+  result = imap_sendf(data, conn, "LOGIN %s %s", user ? user : "",
                       passwd ? passwd : "");
 
   free(user);
   free(passwd);
 
   if(!result)
-    state(conn, IMAP_LOGIN);
+    state(data, IMAP_LOGIN);
 
   return result;
 }
@@ -522,19 +534,21 @@ static CURLcode imap_perform_login(struct connectdata *conn)
  * Sends an AUTHENTICATE command allowing the client to login with the given
  * SASL authentication mechanism.
  */
-static CURLcode imap_perform_authenticate(struct connectdata *conn,
+static CURLcode imap_perform_authenticate(struct Curl_easy *data,
+                                          struct connectdata *conn,
                                           const char *mech,
                                           const char *initresp)
 {
   CURLcode result = CURLE_OK;
+  (void)data;
 
   if(initresp) {
     /* Send the AUTHENTICATE command with the initial response */
-    result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp);
+    result = imap_sendf(data, conn, "AUTHENTICATE %s %s", mech, initresp);
   }
   else {
     /* Send the AUTHENTICATE command */
-    result = imap_sendf(conn, "AUTHENTICATE %s", mech);
+    result = imap_sendf(data, conn, "AUTHENTICATE %s", mech);
   }
 
   return result;
@@ -546,12 +560,13 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn,
  *
  * Sends SASL continuation data or cancellation.
  */
-static CURLcode imap_continue_authenticate(struct connectdata *conn,
+static CURLcode imap_continue_authenticate(struct Curl_easy *data,
+                                           struct connectdata *conn,
                                            const char *resp)
 {
   struct imap_conn *imapc = &conn->proto.imapc;
 
-  return Curl_pp_sendf(&imapc->pp, "%s", resp);
+  return Curl_pp_sendf(data, &imapc->pp, "%s", resp);
 }
 
 /***********************************************************************
@@ -562,7 +577,8 @@ static CURLcode imap_continue_authenticate(struct connectdata *conn,
  * authentication mechanism, falling back to clear text should a common
  * mechanism not be available between the client and server.
  */
-static CURLcode imap_perform_authentication(struct connectdata *conn)
+static CURLcode imap_perform_authentication(struct Curl_easy *data,
+                                            struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct imap_conn *imapc = &conn->proto.imapc;
@@ -572,22 +588,23 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
      with and end the connect phase if we don't */
   if(imapc->preauth ||
      !Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
     return result;
   }
 
   /* Calculate the SASL login details */
-  result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress);
+  result = Curl_sasl_start(&imapc->sasl, data, conn,
+                           imapc->ir_supported, &progress);
 
   if(!result) {
     if(progress == SASL_INPROGRESS)
-      state(conn, IMAP_AUTHENTICATE);
+      state(data, IMAP_AUTHENTICATE);
     else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
       /* Perform clear text authentication */
-      result = imap_perform_login(conn);
+      result = imap_perform_login(data, conn);
     else {
       /* Other mechanisms not supported */
-      infof(conn->data, "No known authentication mechanisms supported!\n");
+      infof(data, "No known authentication mechanisms supported!\n");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -601,15 +618,15 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
  *
  * Sends a LIST command or an alternative custom request.
  */
-static CURLcode imap_perform_list(struct connectdata *conn)
+static CURLcode imap_perform_list(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
 
   if(imap->custom)
     /* Send the custom request */
-    result = imap_sendf(conn, "%s%s", imap->custom,
+    result = imap_sendf(data, conn, "%s%s", imap->custom,
                         imap->custom_params ? imap->custom_params : "");
   else {
     /* Make sure the mailbox is in the correct atom format if necessary */
@@ -619,13 +636,13 @@ static CURLcode imap_perform_list(struct connectdata *conn)
       return CURLE_OUT_OF_MEMORY;
 
     /* Send the LIST command */
-    result = imap_sendf(conn, "LIST \"%s\" *", mailbox);
+    result = imap_sendf(data, conn, "LIST \"%s\" *", mailbox);
 
     free(mailbox);
   }
 
   if(!result)
-    state(conn, IMAP_LIST);
+    state(data, IMAP_LIST);
 
   return result;
 }
@@ -636,11 +653,11 @@ static CURLcode imap_perform_list(struct connectdata *conn)
  *
  * Sends a SELECT command to ask the server to change the selected mailbox.
  */
-static CURLcode imap_perform_select(struct connectdata *conn)
+static CURLcode imap_perform_select(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
   struct imap_conn *imapc = &conn->proto.imapc;
   char *mailbox;
 
@@ -650,7 +667,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
 
   /* Check we have a mailbox */
   if(!imap->mailbox) {
-    failf(conn->data, "Cannot SELECT without a mailbox.");
+    failf(data, "Cannot SELECT without a mailbox.");
     return CURLE_URL_MALFORMAT;
   }
 
@@ -660,12 +677,12 @@ static CURLcode imap_perform_select(struct connectdata *conn)
     return CURLE_OUT_OF_MEMORY;
 
   /* Send the SELECT command */
-  result = imap_sendf(conn, "SELECT %s", mailbox);
+  result = imap_sendf(data, conn, "SELECT %s", mailbox);
 
   free(mailbox);
 
   if(!result)
-    state(conn, IMAP_SELECT);
+    state(data, IMAP_SELECT);
 
   return result;
 }
@@ -676,43 +693,39 @@ static CURLcode imap_perform_select(struct connectdata *conn)
  *
  * Sends a FETCH command to initiate the download of a message.
  */
-static CURLcode imap_perform_fetch(struct connectdata *conn)
+static CURLcode imap_perform_fetch(struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct IMAP *imap = conn->data->req.protop;
+  struct IMAP *imap = data->req.p.imap;
   /* Check we have a UID */
   if(imap->uid) {
 
     /* Send the FETCH command */
     if(imap->partial)
-      result = imap_sendf(conn, "UID FETCH %s BODY[%s]<%s>",
-                            imap->uid,
-                            imap->section ? imap->section : "",
-                            imap->partial);
+      result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]<%s>",
+                          imap->uid, imap->section ? imap->section : "",
+                          imap->partial);
     else
-      result = imap_sendf(conn, "UID FETCH %s BODY[%s]",
-                            imap->uid,
-                            imap->section ? imap->section : "");
+      result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]",
+                          imap->uid, imap->section ? imap->section : "");
   }
   else if(imap->mindex) {
-
     /* Send the FETCH command */
     if(imap->partial)
-      result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
-                            imap->mindex,
-                            imap->section ? imap->section : "",
-                            imap->partial);
+      result = imap_sendf(data, conn, "FETCH %s BODY[%s]<%s>",
+                          imap->mindex, imap->section ? imap->section : "",
+                          imap->partial);
     else
-      result = imap_sendf(conn, "FETCH %s BODY[%s]",
-                            imap->mindex,
-                            imap->section ? imap->section : "");
+      result = imap_sendf(data, conn, "FETCH %s BODY[%s]",
+                          imap->mindex, imap->section ? imap->section : "");
   }
   else {
-        failf(conn->data, "Cannot FETCH without a UID.");
-        return CURLE_URL_MALFORMAT;
+    failf(data, "Cannot FETCH without a UID.");
+    return CURLE_URL_MALFORMAT;
   }
   if(!result)
-    state(conn, IMAP_FETCH);
+    state(data, IMAP_FETCH);
 
   return result;
 }
@@ -723,11 +736,11 @@ static CURLcode imap_perform_fetch(struct connectdata *conn)
  *
  * Sends an APPEND command to initiate the upload of a message.
  */
-static CURLcode imap_perform_append(struct connectdata *conn)
+static CURLcode imap_perform_append(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
   char *mailbox;
 
   /* Check we have a mailbox */
@@ -747,7 +760,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
                                        NULL, MIMESTRATEGY_MAIL);
 
     if(!result)
-      if(!Curl_checkheaders(conn, "Mime-Version"))
+      if(!Curl_checkheaders(data, "Mime-Version"))
         result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
                                       "Mime-Version: 1.0");
 
@@ -767,7 +780,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
 
   /* Check we know the size of the upload */
   if(data->state.infilesize < 0) {
-    failf(data, "Cannot APPEND with unknown input file size\n");
+    failf(data, "Cannot APPEND with unknown input file size");
     return CURLE_UPLOAD_FAILED;
   }
 
@@ -777,13 +790,14 @@ static CURLcode imap_perform_append(struct connectdata *conn)
     return CURLE_OUT_OF_MEMORY;
 
   /* Send the APPEND command */
-  result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
+  result = imap_sendf(data, conn,
+                      "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
                       mailbox, data->state.infilesize);
 
   free(mailbox);
 
   if(!result)
-    state(conn, IMAP_APPEND);
+    state(data, IMAP_APPEND);
 
   return result;
 }
@@ -794,22 +808,23 @@ static CURLcode imap_perform_append(struct connectdata *conn)
  *
  * Sends a SEARCH command.
  */
-static CURLcode imap_perform_search(struct connectdata *conn)
+static CURLcode imap_perform_search(struct Curl_easy *data,
+                                    struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct IMAP *imap = conn->data->req.protop;
+  struct IMAP *imap = data->req.p.imap;
 
   /* Check we have a query string */
   if(!imap->query) {
-    failf(conn->data, "Cannot SEARCH without a query string.");
+    failf(data, "Cannot SEARCH without a query string.");
     return CURLE_URL_MALFORMAT;
   }
 
   /* Send the SEARCH command */
-  result = imap_sendf(conn, "SEARCH %s", imap->query);
+  result = imap_sendf(data, conn, "SEARCH %s", imap->query);
 
   if(!result)
-    state(conn, IMAP_SEARCH);
+    state(data, IMAP_SEARCH);
 
   return result;
 }
@@ -820,23 +835,24 @@ static CURLcode imap_perform_search(struct connectdata *conn)
  *
  * Performs the logout action prior to sclose() being called.
  */
-static CURLcode imap_perform_logout(struct connectdata *conn)
+static CURLcode imap_perform_logout(struct Curl_easy *data,
+                                    struct connectdata *conn)
 {
   /* Send the LOGOUT command */
-  CURLcode result = imap_sendf(conn, "LOGOUT");
+  CURLcode result = imap_sendf(data, conn, "LOGOUT");
 
   if(!result)
-    state(conn, IMAP_LOGOUT);
+    state(data, IMAP_LOGOUT);
 
   return result;
 }
 
 /* For the initial server greeting */
-static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
+static CURLcode imap_state_servergreet_resp(struct Curl_easy *data,
                                             int imapcode,
                                             imapstate instate)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   (void)instate; /* no use for this yet */
 
   if(imapcode == IMAP_RESP_PREAUTH) {
@@ -850,16 +866,16 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
     return CURLE_WEIRD_SERVER_REPLY;
   }
 
-  return imap_perform_capability(conn);
+  return imap_perform_capability(data, conn);
 }
 
 /* For CAPABILITY responses */
-static CURLcode imap_state_capability_resp(struct connectdata *conn,
+static CURLcode imap_state_capability_resp(struct Curl_easy *data,
                                            int imapcode,
                                            imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct imap_conn *imapc = &conn->proto.imapc;
   const char *line = data->state.buffer;
 
@@ -922,31 +938,31 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
       /* We don't have a SSL/TLS connection yet, but SSL is requested */
       if(imapc->tls_supported)
         /* Switch to TLS connection now */
-        result = imap_perform_starttls(conn);
+        result = imap_perform_starttls(data, conn);
       else if(data->set.use_ssl == CURLUSESSL_TRY)
         /* Fallback and carry on with authentication */
-        result = imap_perform_authentication(conn);
+        result = imap_perform_authentication(data, conn);
       else {
         failf(data, "STARTTLS not supported.");
         result = CURLE_USE_SSL_FAILED;
       }
     }
     else
-      result = imap_perform_authentication(conn);
+      result = imap_perform_authentication(data, conn);
   }
   else
-    result = imap_perform_authentication(conn);
+    result = imap_perform_authentication(data, conn);
 
   return result;
 }
 
 /* For STARTTLS responses */
-static CURLcode imap_state_starttls_resp(struct connectdata *conn,
+static CURLcode imap_state_starttls_resp(struct Curl_easy *data,
                                          int imapcode,
                                          imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   (void)instate; /* no use for this yet */
 
@@ -956,36 +972,36 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
       result = CURLE_USE_SSL_FAILED;
     }
     else
-      result = imap_perform_authentication(conn);
+      result = imap_perform_authentication(data, conn);
   }
   else
-    result = imap_perform_upgrade_tls(conn);
+    result = imap_perform_upgrade_tls(data, conn);
 
   return result;
 }
 
 /* For SASL authentication responses */
-static CURLcode imap_state_auth_resp(struct connectdata *conn,
+static CURLcode imap_state_auth_resp(struct Curl_easy *data,
+                                     struct connectdata *conn,
                                      int imapcode,
                                      imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct imap_conn *imapc = &conn->proto.imapc;
   saslprogress progress;
 
   (void)instate; /* no use for this yet */
 
-  result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress);
+  result = Curl_sasl_continue(&imapc->sasl, data, conn, imapcode, &progress);
   if(!result)
     switch(progress) {
     case SASL_DONE:
-      state(conn, IMAP_STOP);  /* Authenticated */
+      state(data, IMAP_STOP);  /* Authenticated */
       break;
     case SASL_IDLE:            /* No mechanism left after cancellation */
       if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
         /* Perform clear text authentication */
-        result = imap_perform_login(conn);
+        result = imap_perform_login(data, conn);
       else {
         failf(data, "Authentication cancelled");
         result = CURLE_LOGIN_DENIED;
@@ -999,13 +1015,11 @@ static CURLcode imap_state_auth_resp(struct connectdata *conn,
 }
 
 /* For LOGIN responses */
-static CURLcode imap_state_login_resp(struct connectdata *conn,
+static CURLcode imap_state_login_resp(struct Curl_easy *data,
                                       int imapcode,
                                       imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(imapcode != IMAP_RESP_OK) {
@@ -1014,18 +1028,18 @@ static CURLcode imap_state_login_resp(struct connectdata *conn,
   }
   else
     /* End of connect phase */
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
 
   return result;
 }
 
 /* For LIST and SEARCH responses */
-static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
+static CURLcode imap_state_listsearch_resp(struct Curl_easy *data,
                                            int imapcode,
                                            imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  char *line = conn->data->state.buffer;
+  char *line = data->state.buffer;
   size_t len = strlen(line);
 
   (void)instate; /* No use for this yet */
@@ -1033,25 +1047,25 @@ static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
   if(imapcode == '*') {
     /* Temporarily add the LF character back and send as body to the client */
     line[len] = '\n';
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
     line[len] = '\0';
   }
   else if(imapcode != IMAP_RESP_OK)
     result = CURLE_QUOTE_ERROR;
   else
     /* End of DO phase */
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
 
   return result;
 }
 
 /* For SELECT responses */
-static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
+static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
                                        imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = conn->data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
   struct imap_conn *imapc = &conn->proto.imapc;
   const char *line = data->state.buffer;
 
@@ -1069,7 +1083,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
     /* Check if the UIDVALIDITY has been specified and matches */
     if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
        !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
-      failf(conn->data, "Mailbox UIDVALIDITY has changed");
+      failf(data, "Mailbox UIDVALIDITY has changed");
       result = CURLE_REMOTE_FILE_NOT_FOUND;
     }
     else {
@@ -1077,11 +1091,11 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
       imapc->mailbox = strdup(imap->mailbox);
 
       if(imap->custom)
-        result = imap_perform_list(conn);
+        result = imap_perform_list(data);
       else if(imap->query)
-        result = imap_perform_search(conn);
+        result = imap_perform_search(data, conn);
       else
-        result = imap_perform_fetch(conn);
+        result = imap_perform_fetch(data, conn);
     }
   }
   else {
@@ -1093,11 +1107,11 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
 }
 
 /* For the (first line of the) FETCH responses */
-static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
+static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
+                                      struct connectdata *conn, int imapcode,
                                       imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct imap_conn *imapc = &conn->proto.imapc;
   struct pingpong *pp = &imapc->pp;
   const char *ptr = data->state.buffer;
@@ -1108,7 +1122,7 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
 
   if(imapcode != '*') {
     Curl_pgrsSetDownloadSize(data, -1);
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
     return CURLE_REMOTE_FILE_NOT_FOUND;
   }
 
@@ -1143,10 +1157,10 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
 
       if(!chunk) {
         /* no size, we're done with the data */
-        state(conn, IMAP_STOP);
+        state(data, IMAP_STOP);
         return CURLE_OK;
       }
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, pp->cache, chunk);
       if(result)
         return result;
 
@@ -1176,23 +1190,26 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
     else {
       /* IMAP download */
       data->req.maxdownload = size;
+      /* force a recv/send check of this connection, as the data might've been
+       read off the socket already */
+      data->conn->cselect_bits = CURL_CSELECT_IN;
       Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1);
     }
   }
   else {
     /* We don't know how to parse this line */
-    failf(pp->conn->data, "Failed to parse FETCH response.");
+    failf(data, "Failed to parse FETCH response.");
     result = CURLE_WEIRD_SERVER_REPLY;
   }
 
   /* End of DO phase */
-  state(conn, IMAP_STOP);
+  state(data, IMAP_STOP);
 
   return result;
 }
 
 /* For final FETCH responses performed after the download */
-static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
+static CURLcode imap_state_fetch_final_resp(struct Curl_easy *data,
                                             int imapcode,
                                             imapstate instate)
 {
@@ -1204,18 +1221,16 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
     result = CURLE_WEIRD_SERVER_REPLY;
   else
     /* End of DONE phase */
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
 
   return result;
 }
 
 /* For APPEND responses */
-static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
+static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode,
                                        imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* No use for this yet */
 
   if(imapcode != '+') {
@@ -1229,14 +1244,14 @@ static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
     Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
 
     /* End of DO phase */
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
   }
 
   return result;
 }
 
 /* For final APPEND responses performed after the upload */
-static CURLcode imap_state_append_final_resp(struct connectdata *conn,
+static CURLcode imap_state_append_final_resp(struct Curl_easy *data,
                                              int imapcode,
                                              imapstate instate)
 {
@@ -1248,12 +1263,13 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn,
     result = CURLE_UPLOAD_FAILED;
   else
     /* End of DONE phase */
-    state(conn, IMAP_STOP);
+    state(data, IMAP_STOP);
 
   return result;
 }
 
-static CURLcode imap_statemach_act(struct connectdata *conn)
+static CURLcode imap_statemachine(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
@@ -1261,18 +1277,19 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
   struct imap_conn *imapc = &conn->proto.imapc;
   struct pingpong *pp = &imapc->pp;
   size_t nread = 0;
+  (void)data;
 
   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
   if(imapc->state == IMAP_UPGRADETLS)
-    return imap_perform_upgrade_tls(conn);
+    return imap_perform_upgrade_tls(data, conn);
 
   /* Flush any data that needs to be sent */
   if(pp->sendleft)
-    return Curl_pp_flushsend(pp);
+    return Curl_pp_flushsend(data, pp);
 
   do {
     /* Read the response from the server */
-    result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
+    result = Curl_pp_readresp(data, sock, pp, &imapcode, &nread);
     if(result)
       return result;
 
@@ -1286,55 +1303,55 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
     /* We have now received a full IMAP server response */
     switch(imapc->state) {
     case IMAP_SERVERGREET:
-      result = imap_state_servergreet_resp(conn, imapcode, imapc->state);
+      result = imap_state_servergreet_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_CAPABILITY:
-      result = imap_state_capability_resp(conn, imapcode, imapc->state);
+      result = imap_state_capability_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_STARTTLS:
-      result = imap_state_starttls_resp(conn, imapcode, imapc->state);
+      result = imap_state_starttls_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_AUTHENTICATE:
-      result = imap_state_auth_resp(conn, imapcode, imapc->state);
+      result = imap_state_auth_resp(data, conn, imapcode, imapc->state);
       break;
 
     case IMAP_LOGIN:
-      result = imap_state_login_resp(conn, imapcode, imapc->state);
+      result = imap_state_login_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_LIST:
     case IMAP_SEARCH:
-      result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
+      result = imap_state_listsearch_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_SELECT:
-      result = imap_state_select_resp(conn, imapcode, imapc->state);
+      result = imap_state_select_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_FETCH:
-      result = imap_state_fetch_resp(conn, imapcode, imapc->state);
+      result = imap_state_fetch_resp(data, conn, imapcode, imapc->state);
       break;
 
     case IMAP_FETCH_FINAL:
-      result = imap_state_fetch_final_resp(conn, imapcode, imapc->state);
+      result = imap_state_fetch_final_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_APPEND:
-      result = imap_state_append_resp(conn, imapcode, imapc->state);
+      result = imap_state_append_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_APPEND_FINAL:
-      result = imap_state_append_final_resp(conn, imapcode, imapc->state);
+      result = imap_state_append_final_resp(data, imapcode, imapc->state);
       break;
 
     case IMAP_LOGOUT:
       /* fallthrough, just stop! */
     default:
       /* internal error */
-      state(conn, IMAP_STOP);
+      state(data, IMAP_STOP);
       break;
     }
   } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
@@ -1343,44 +1360,46 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
 }
 
 /* Called repeatedly until done from multi.c */
-static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
+static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct imap_conn *imapc = &conn->proto.imapc;
 
   if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
-    result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
+    result = Curl_ssl_connect_nonblocking(data, conn,
+                                          FIRSTSOCKET, &imapc->ssldone);
     if(result || !imapc->ssldone)
       return result;
   }
 
-  result = Curl_pp_statemach(&imapc->pp, FALSE, FALSE);
+  result = Curl_pp_statemach(data, &imapc->pp, FALSE, FALSE);
   *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
 
   return result;
 }
 
-static CURLcode imap_block_statemach(struct connectdata *conn,
+static CURLcode imap_block_statemach(struct Curl_easy *data,
+                                     struct connectdata *conn,
                                      bool disconnecting)
 {
   CURLcode result = CURLE_OK;
   struct imap_conn *imapc = &conn->proto.imapc;
 
   while(imapc->state != IMAP_STOP && !result)
-    result = Curl_pp_statemach(&imapc->pp, TRUE, disconnecting);
+    result = Curl_pp_statemach(data, &imapc->pp, TRUE, disconnecting);
 
   return result;
 }
 
 /* Allocate and initialize the struct IMAP for the current Curl_easy if
    required */
-static CURLcode imap_init(struct connectdata *conn)
+static CURLcode imap_init(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct IMAP *imap;
 
-  imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
+  imap = data->req.p.imap = calloc(sizeof(struct IMAP), 1);
   if(!imap)
     result = CURLE_OUT_OF_MEMORY;
 
@@ -1388,9 +1407,11 @@ static CURLcode imap_init(struct connectdata *conn)
 }
 
 /* For the IMAP "protocol connect" and "doing" phases only */
-static int imap_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int imap_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        curl_socket_t *socks)
 {
-  return Curl_pp_getsock(&conn->proto.imapc.pp, socks);
+  return Curl_pp_getsock(data, &conn->proto.imapc.pp, socks);
 }
 
 /***********************************************************************
@@ -1403,9 +1424,10 @@ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks)
  * The variable 'done' points to will be TRUE if the protocol-layer connect
  * phase is done when this function returns, or FALSE if not.
  */
-static CURLcode imap_connect(struct connectdata *conn, bool *done)
+static CURLcode imap_connect(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct imap_conn *imapc = &conn->proto.imapc;
   struct pingpong *pp = &imapc->pp;
 
@@ -1414,18 +1436,16 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done)
   /* We always support persistent connections in IMAP */
   connkeep(conn, "IMAP default");
 
-  /* Set the default response time-out */
-  pp->response_time = RESP_TIMEOUT;
-  pp->statemach_act = imap_statemach_act;
-  pp->endofresp = imap_endofresp;
-  pp->conn = conn;
+  PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp);
 
   /* Set the default preferred authentication type and mechanism */
   imapc->preftype = IMAP_TYPE_ANY;
   Curl_sasl_init(&imapc->sasl, &saslimap);
 
+  Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
   /* Initialise the pingpong layer */
-  Curl_pp_init(pp);
+  Curl_pp_setup(pp);
+  Curl_pp_init(data, pp);
 
   /* Parse the URL options */
   result = imap_parse_url_options(conn);
@@ -1433,12 +1453,12 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done)
     return result;
 
   /* Start off waiting for the server greeting response */
-  state(conn, IMAP_SERVERGREET);
+  state(data, IMAP_SERVERGREET);
 
   /* Start off with an response id of '*' */
   strcpy(imapc->resptag, "*");
 
-  result = imap_multi_statemach(conn, done);
+  result = imap_multi_statemach(data, done);
 
   return result;
 }
@@ -1452,12 +1472,12 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done)
  *
  * Input argument is already checked for validity.
  */
-static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
                           bool premature)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
 
   (void)premature;
 
@@ -1474,17 +1494,17 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
     /* Handle responses after FETCH or APPEND transfer has finished */
 
     if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
-      state(conn, IMAP_FETCH_FINAL);
+      state(data, IMAP_FETCH_FINAL);
     else {
       /* End the APPEND command first by sending an empty line */
-      result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "");
+      result = Curl_pp_sendf(data, &conn->proto.imapc.pp, "%s", "");
       if(!result)
-        state(conn, IMAP_APPEND_FINAL);
+        state(data, IMAP_APPEND_FINAL);
     }
 
     /* Run the state-machine */
     if(!result)
-      result = imap_block_statemach(conn, FALSE);
+      result = imap_block_statemach(data, conn, FALSE);
   }
 
   /* Cleanup our per-request based variables */
@@ -1511,19 +1531,19 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
  * This is the actual DO function for IMAP. Fetch or append a message, or do
  * other things according to the options previously setup.
  */
-static CURLcode imap_perform(struct connectdata *conn, bool *connected,
+static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
                              bool *dophase_done)
 {
   /* This is IMAP and no proxy */
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct IMAP *imap = data->req.p.imap;
   struct imap_conn *imapc = &conn->proto.imapc;
   bool selected = FALSE;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
-  if(conn->data->set.opt_no_body) {
+  if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
     imap->transfer = FTPTRANSFER_INFO;
   }
@@ -1539,36 +1559,36 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
     selected = TRUE;
 
   /* Start the first command in the DO phase */
-  if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE)
+  if(data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE)
     /* APPEND can be executed directly */
-    result = imap_perform_append(conn);
+    result = imap_perform_append(data);
   else if(imap->custom && (selected || !imap->mailbox))
     /* Custom command using the same mailbox or no mailbox */
-    result = imap_perform_list(conn);
+    result = imap_perform_list(data);
   else if(!imap->custom && selected && (imap->uid || imap->mindex))
     /* FETCH from the same mailbox */
-    result = imap_perform_fetch(conn);
+    result = imap_perform_fetch(data, conn);
   else if(!imap->custom && selected && imap->query)
     /* SEARCH the current mailbox */
-    result = imap_perform_search(conn);
+    result = imap_perform_search(data, conn);
   else if(imap->mailbox && !selected &&
          (imap->custom || imap->uid || imap->mindex || imap->query))
     /* SELECT the mailbox */
-    result = imap_perform_select(conn);
+    result = imap_perform_select(data);
   else
     /* LIST */
-    result = imap_perform_list(conn);
+    result = imap_perform_list(data);
 
   if(result)
     return result;
 
   /* Run the state-machine */
-  result = imap_multi_statemach(conn, dophase_done);
+  result = imap_multi_statemach(data, dophase_done);
 
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
 
   return result;
 }
@@ -1582,23 +1602,22 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
  *
  * The input argument is already checked for validity.
  */
-static CURLcode imap_do(struct connectdata *conn, bool *done)
+static CURLcode imap_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-
   *done = FALSE; /* default to false */
 
   /* Parse the URL path */
-  result = imap_parse_url_path(conn);
+  result = imap_parse_url_path(data);
   if(result)
     return result;
 
   /* Parse the custom request */
-  result = imap_parse_custom_request(conn);
+  result = imap_parse_custom_request(data);
   if(result)
     return result;
 
-  result = imap_regular_transfer(conn, done);
+  result = imap_regular_transfer(data, done);
 
   return result;
 }
@@ -1610,9 +1629,11 @@ static CURLcode imap_do(struct connectdata *conn, bool *done)
  * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
  * resources. BLOCKING.
  */
-static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode imap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
 {
   struct imap_conn *imapc = &conn->proto.imapc;
+  (void)data;
 
   /* We cannot send quit unconditionally. If this connection is stale or
      bad in any way, sending quit and waiting around here will make the
@@ -1620,12 +1641,14 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
 
   /* The IMAP session may or may not have been allocated/setup at this
      point! */
-  if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart)
-    if(!imap_perform_logout(conn))
-      (void)imap_block_statemach(conn, TRUE); /* ignore errors on LOGOUT */
+  if(!dead_connection && conn->bits.protoconnstart) {
+    if(!imap_perform_logout(data, conn))
+      (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
+  }
 
   /* Disconnect from the server */
   Curl_pp_disconnect(&imapc->pp);
+  Curl_dyn_free(&imapc->dyn);
 
   /* Cleanup the SASL module */
   Curl_sasl_cleanup(conn, imapc->sasl.authused);
@@ -1638,30 +1661,30 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
 }
 
 /* Call this when the DO phase has completed */
-static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
+static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
 {
-  struct IMAP *imap = conn->data->req.protop;
+  struct IMAP *imap = data->req.p.imap;
 
   (void)connected;
 
   if(imap->transfer != FTPTRANSFER_BODY)
     /* no data to transfer */
-    Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
+    Curl_setup_transfer(data, -1, -1, FALSE, -1);
 
   return CURLE_OK;
 }
 
 /* Called from multi.c while DOing */
-static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
+static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
 {
-  CURLcode result = imap_multi_statemach(conn, dophase_done);
+  CURLcode result = imap_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(conn->data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed\n"));
   else if(*dophase_done) {
-    result = imap_dophase_done(conn, FALSE /* not connected */);
+    result = imap_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
@@ -1676,12 +1699,11 @@ static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
  * Performs all commands done before a regular transfer between a local and a
  * remote host.
  */
-static CURLcode imap_regular_transfer(struct connectdata *conn,
+static CURLcode imap_regular_transfer(struct Curl_easy *data,
                                       bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
-  struct Curl_easy *data = conn->data;
 
   /* Make sure size is unknown at this point */
   data->req.size = -1;
@@ -1693,19 +1715,20 @@ static CURLcode imap_regular_transfer(struct connectdata *conn,
   Curl_pgrsSetDownloadSize(data, -1);
 
   /* Carry out the perform */
-  result = imap_perform(conn, &connected, dophase_done);
+  result = imap_perform(data, &connected, dophase_done);
 
   /* Perform post DO phase operations if necessary */
   if(!result && *dophase_done)
-    result = imap_dophase_done(conn, connected);
+    result = imap_dophase_done(data, connected);
 
   return result;
 }
 
-static CURLcode imap_setup_connection(struct connectdata *conn)
+static CURLcode imap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   /* Initialise the IMAP layer */
-  CURLcode result = imap_init(conn);
+  CURLcode result = imap_init(data);
   if(result)
     return result;
 
@@ -1723,34 +1746,30 @@ static CURLcode imap_setup_connection(struct connectdata *conn)
  *
  * Designed to never block.
  */
-static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
+static CURLcode imap_sendf(struct Curl_easy *data,
+                           struct connectdata *conn, const char *fmt, ...)
 {
   CURLcode result = CURLE_OK;
   struct imap_conn *imapc = &conn->proto.imapc;
-  char *taggedfmt;
-  va_list ap;
 
   DEBUGASSERT(fmt);
 
-  /* Calculate the next command ID wrapping at 3 digits */
-  imapc->cmdid = (imapc->cmdid + 1) % 1000;
-
   /* Calculate the tag based on the connection ID and command ID */
   msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
-            'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid);
-
-  /* Prefix the format with the tag */
-  taggedfmt = aprintf("%s %s", imapc->resptag, fmt);
-  if(!taggedfmt)
-    return CURLE_OUT_OF_MEMORY;
+            'A' + curlx_sltosi(conn->connection_id % 26),
+            (++imapc->cmdid)%1000);
 
-  /* Send the data with the tag */
-  va_start(ap, fmt);
-  result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap);
-  va_end(ap);
-
-  free(taggedfmt);
+  /* start with a blank buffer */
+  Curl_dyn_reset(&imapc->dyn);
 
+  /* append tag + space + fmt */
+  result = Curl_dyn_addf(&imapc->dyn, "%s %s", imapc->resptag, fmt);
+  if(!result) {
+    va_list ap;
+    va_start(ap, fmt);
+    result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap);
+    va_end(ap);
+  }
   return result;
 }
 
@@ -1937,12 +1956,11 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
  * Parse the URL path into separate path components.
  *
  */
-static CURLcode imap_parse_url_path(struct connectdata *conn)
+static CURLcode imap_parse_url_path(struct Curl_easy *data)
 {
   /* The imap struct is already initialised in imap_connect() */
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = data->req.protop;
+  struct IMAP *imap = data->req.p.imap;
   const char *begin = &data->state.up.path[1]; /* skip leading slash */
   const char *ptr = begin;
 
@@ -1997,7 +2015,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
       return result;
     }
 
-    DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value));
+    DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'\n", name, value));
 
     /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
        PARTIAL) stripping of the trailing slash character if it is present.
@@ -2070,11 +2088,10 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
  *
  * Parse the custom request.
  */
-static CURLcode imap_parse_custom_request(struct connectdata *conn)
+static CURLcode imap_parse_custom_request(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct IMAP *imap = data->req.protop;
+  struct IMAP *imap = data->req.p.imap;
   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
 
   if(custom) {
index 4786f56..ef6515d 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -75,13 +75,14 @@ struct imap_conn {
   bool preauth;               /* Is this connection PREAUTH? */
   struct SASL sasl;           /* SASL-related parameters */
   unsigned int preftype;      /* Preferred authentication type */
-  int cmdid;                  /* Last used command ID */
+  unsigned int cmdid;         /* Last used command ID */
   char resptag[5];            /* Response tag to wait for */
   bool tls_supported;         /* StartTLS capability supported by server */
   bool login_disabled;        /* LOGIN command disabled by server */
   bool ir_supported;          /* Initial response supported by server */
   char *mailbox;              /* The last selected mailbox */
   char *mailbox_uidvalidity;  /* UIDVALIDITY parsed from select response */
+  struct dynbuf dyn;          /* for the IMAP commands */
 };
 
 extern const struct Curl_handler Curl_handler_imap;
index 9d3f237..067632a 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 9c87a05..4923cae 100644 (file)
@@ -1,6 +1,6 @@
 /* This is from the BIND 4.9.4 release, modified to compile by itself */
 
-/* Copyright (c) 1996 - 2019 by Internet Software Consortium.
+/* Copyright (c) 1996 - 2020 by Internet Software Consortium.
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -112,7 +112,7 @@ inet_pton4(const char *src, unsigned char *dst)
       if(val > 255)
         return (0);
       *tp = (unsigned char)val;
-      if(! saw_digit) {
+      if(!saw_digit) {
         if(++octets > 4)
           return (0);
         saw_digit = 1;
index e695af9..ec12373 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 5bd8e71..46116ce 100644 (file)
@@ -2,7 +2,7 @@
  *
  * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
- * Copyright (c) 2004 - 2019 Daniel Stenberg
+ * Copyright (c) 2004 - 2021 Daniel Stenberg
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "ftp.h"
 #include "curl_gssapi.h"
 #include "sendf.h"
-#include "curl_sec.h"
+#include "curl_krb5.h"
 #include "warnless.h"
+#include "non-ascii.h"
+#include "strcase.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 CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
+                        const char *cmd)
+{
+  ssize_t bytes_written;
+#define SBUF_SIZE 1024
+  char s[SBUF_SIZE];
+  size_t write_len;
+  char *sptr = s;
+  CURLcode result = CURLE_OK;
+#ifdef HAVE_GSSAPI
+  enum protection_level data_sec = conn->data_prot;
+#endif
+
+  if(!cmd)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  write_len = strlen(cmd);
+  if(!write_len || write_len > (sizeof(s) -3))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  memcpy(&s, cmd, write_len);
+  strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
+  write_len += 2;
+  bytes_written = 0;
+
+  result = Curl_convert_to_network(data, s, write_len);
+  /* Curl_convert_to_network calls failf if unsuccessful */
+  if(result)
+    return result;
+
+  for(;;) {
+#ifdef HAVE_GSSAPI
+    conn->data_prot = PROT_CMD;
+#endif
+    result = Curl_write(data, conn->sock[FIRSTSOCKET], sptr, write_len,
+                        &bytes_written);
+#ifdef HAVE_GSSAPI
+    DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
+    conn->data_prot = data_sec;
+#endif
+
+    if(result)
+      break;
+
+    Curl_debug(data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written);
+
+    if(bytes_written != (ssize_t)write_len) {
+      write_len -= bytes_written;
+      sptr += bytes_written;
+    }
+    else
+      break;
+  }
+
+  return result;
+}
+
 static int
 krb5_init(void *app_data)
 {
@@ -143,14 +203,13 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to)
 }
 
 static int
-krb5_auth(void *app_data, struct connectdata *conn)
+krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
 {
   int ret = AUTH_OK;
   char *p;
   const char *host = conn->host.name;
   ssize_t nread;
   curl_socklen_t l = sizeof(conn->local_addr);
-  struct Curl_easy *data = conn->data;
   CURLcode result;
   const char *service = data->set.str[STRING_SERVICE_NAME] ?
                         data->set.str[STRING_SERVICE_NAME] :
@@ -183,11 +242,11 @@ krb5_auth(void *app_data, struct connectdata *conn)
   for(;;) {
     /* this really shouldn't be repeated here, but can't help it */
     if(service == srv_host) {
-      result = Curl_ftpsend(conn, "AUTH GSSAPI");
+      result = ftpsend(data, conn, "AUTH GSSAPI");
       if(result)
         return -2;
 
-      if(Curl_GetFTPResponse(&nread, conn, NULL))
+      if(Curl_GetFTPResponse(data, &nread, NULL))
         return -1;
 
       if(data->state.buffer[0] != '3')
@@ -260,7 +319,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
 
         cmd = aprintf("ADAT %s", p);
         if(cmd)
-          result = Curl_ftpsend(conn, cmd);
+          result = ftpsend(data, conn, cmd);
         else
           result = CURLE_OUT_OF_MEMORY;
 
@@ -272,7 +331,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
           break;
         }
 
-        if(Curl_GetFTPResponse(&nread, conn, NULL)) {
+        if(Curl_GetFTPResponse(data, &nread, NULL)) {
           ret = -1;
           break;
         }
@@ -326,16 +385,528 @@ static void krb5_end(void *app_data)
     }
 }
 
-struct Curl_sec_client_mech Curl_krb5_client_mech = {
-    "GSSAPI",
-    sizeof(gss_ctx_id_t),
-    krb5_init,
-    krb5_auth,
-    krb5_end,
-    krb5_check_prot,
-    krb5_overhead,
-    krb5_encode,
-    krb5_decode
+static struct Curl_sec_client_mech Curl_krb5_client_mech = {
+  "GSSAPI",
+  sizeof(gss_ctx_id_t),
+  krb5_init,
+  krb5_auth,
+  krb5_end,
+  krb5_check_prot,
+  krb5_overhead,
+  krb5_encode,
+  krb5_decode
+};
+
+static const struct {
+  enum protection_level level;
+  const char *name;
+} level_names[] = {
+  { PROT_CLEAR, "clear" },
+  { PROT_SAFE, "safe" },
+  { PROT_CONFIDENTIAL, "confidential" },
+  { PROT_PRIVATE, "private" }
 };
 
+static enum protection_level
+name_to_level(const char *name)
+{
+  int i;
+  for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
+    if(checkprefix(name, level_names[i].name))
+      return level_names[i].level;
+  return PROT_NONE;
+}
+
+/* Convert a protocol |level| to its char representation.
+   We take an int to catch programming mistakes. */
+static char level_to_char(int level)
+{
+  switch(level) {
+  case PROT_CLEAR:
+    return 'C';
+  case PROT_SAFE:
+    return 'S';
+  case PROT_CONFIDENTIAL:
+    return 'E';
+  case PROT_PRIVATE:
+    return 'P';
+  case PROT_CMD:
+    /* Fall through */
+  default:
+    /* Those 2 cases should not be reached! */
+    break;
+  }
+  DEBUGASSERT(0);
+  /* Default to the most secure alternative. */
+  return 'P';
+}
+
+/* Send an FTP command defined by |message| and the optional arguments. The
+   function returns the ftp_code. If an error occurs, -1 is returned. */
+static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
+{
+  int ftp_code;
+  ssize_t nread = 0;
+  va_list args;
+  char print_buffer[50];
+
+  va_start(args, message);
+  mvsnprintf(print_buffer, sizeof(print_buffer), message, args);
+  va_end(args);
+
+  if(ftpsend(data, data->conn, print_buffer)) {
+    ftp_code = -1;
+  }
+  else {
+    if(Curl_GetFTPResponse(data, &nread, &ftp_code))
+      ftp_code = -1;
+  }
+
+  (void)nread; /* Unused */
+  return ftp_code;
+}
+
+/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
+   saying whether an error occurred or CURLE_OK if |len| was read. */
+static CURLcode
+socket_read(curl_socket_t fd, void *to, size_t len)
+{
+  char *to_p = to;
+  CURLcode result;
+  ssize_t nread = 0;
+
+  while(len > 0) {
+    result = Curl_read_plain(fd, to_p, len, &nread);
+    if(!result) {
+      len -= nread;
+      to_p += nread;
+    }
+    else {
+      if(result == CURLE_AGAIN)
+        continue;
+      return result;
+    }
+  }
+  return CURLE_OK;
+}
+
+
+/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a
+   CURLcode saying whether an error occurred or CURLE_OK if |len| was
+   written. */
+static CURLcode
+socket_write(struct Curl_easy *data, curl_socket_t fd, const void *to,
+             size_t len)
+{
+  const char *to_p = to;
+  CURLcode result;
+  ssize_t written;
+
+  while(len > 0) {
+    result = Curl_write_plain(data, fd, to_p, len, &written);
+    if(!result) {
+      len -= written;
+      to_p += written;
+    }
+    else {
+      if(result == CURLE_AGAIN)
+        continue;
+      return result;
+    }
+  }
+  return CURLE_OK;
+}
+
+static CURLcode read_data(struct connectdata *conn,
+                          curl_socket_t fd,
+                          struct krb5buffer *buf)
+{
+  int len;
+  CURLcode result;
+
+  result = socket_read(fd, &len, sizeof(len));
+  if(result)
+    return result;
+
+  if(len) {
+    /* only realloc if there was a length */
+    len = ntohl(len);
+    buf->data = Curl_saferealloc(buf->data, len);
+  }
+  if(!len || !buf->data)
+    return CURLE_OUT_OF_MEMORY;
+
+  result = socket_read(fd, buf->data, len);
+  if(result)
+    return result;
+  buf->size = conn->mech->decode(conn->app_data, buf->data, len,
+                                 conn->data_prot, conn);
+  buf->index = 0;
+  return CURLE_OK;
+}
+
+static size_t
+buffer_read(struct krb5buffer *buf, void *data, size_t len)
+{
+  if(buf->size - buf->index < len)
+    len = buf->size - buf->index;
+  memcpy(data, (char *)buf->data + buf->index, len);
+  buf->index += len;
+  return len;
+}
+
+/* Matches Curl_recv signature */
+static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
+                        char *buffer, size_t len, CURLcode *err)
+{
+  size_t bytes_read;
+  size_t total_read = 0;
+  struct connectdata *conn = data->conn;
+  curl_socket_t fd = conn->sock[sockindex];
+
+  *err = CURLE_OK;
+
+  /* Handle clear text response. */
+  if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
+    return sread(fd, buffer, len);
+
+  if(conn->in_buffer.eof_flag) {
+    conn->in_buffer.eof_flag = 0;
+    return 0;
+  }
+
+  bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+  len -= bytes_read;
+  total_read += bytes_read;
+  buffer += bytes_read;
+
+  while(len > 0) {
+    if(read_data(conn, fd, &conn->in_buffer))
+      return -1;
+    if(conn->in_buffer.size == 0) {
+      if(bytes_read > 0)
+        conn->in_buffer.eof_flag = 1;
+      return bytes_read;
+    }
+    bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+    len -= bytes_read;
+    total_read += bytes_read;
+    buffer += bytes_read;
+  }
+  return total_read;
+}
+
+/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
+   and negotiating with the server. |from| can be NULL. */
+static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t fd, const char *from, int length)
+{
+  int bytes, htonl_bytes; /* 32-bit integers for htonl */
+  char *buffer = NULL;
+  char *cmd_buffer;
+  size_t cmd_size = 0;
+  CURLcode error;
+  enum protection_level prot_level = conn->data_prot;
+  bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE;
+
+  DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
+
+  if(iscmd) {
+    if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
+      prot_level = PROT_PRIVATE;
+    else
+      prot_level = conn->command_prot;
+  }
+  bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
+                             (void **)&buffer);
+  if(!buffer || bytes <= 0)
+    return; /* error */
+
+  if(iscmd) {
+    error = Curl_base64_encode(data, buffer, curlx_sitouz(bytes),
+                               &cmd_buffer, &cmd_size);
+    if(error) {
+      free(buffer);
+      return; /* error */
+    }
+    if(cmd_size > 0) {
+      static const char *enc = "ENC ";
+      static const char *mic = "MIC ";
+      if(prot_level == PROT_PRIVATE)
+        socket_write(data, fd, enc, 4);
+      else
+        socket_write(data, fd, mic, 4);
+
+      socket_write(data, fd, cmd_buffer, cmd_size);
+      socket_write(data, fd, "\r\n", 2);
+      infof(data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
+            cmd_buffer);
+      free(cmd_buffer);
+    }
+  }
+  else {
+    htonl_bytes = htonl(bytes);
+    socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
+    socket_write(data, fd, buffer, curlx_sitouz(bytes));
+  }
+  free(buffer);
+}
+
+static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t fd, const char *buffer, size_t length)
+{
+  ssize_t tx = 0, len = conn->buffer_size;
+
+  len -= conn->mech->overhead(conn->app_data, conn->data_prot,
+                              curlx_sztosi(len));
+  if(len <= 0)
+    len = length;
+  while(length) {
+    if(length < (size_t)len)
+      len = length;
+
+    do_sec_send(data, conn, fd, buffer, curlx_sztosi(len));
+    length -= len;
+    buffer += len;
+    tx += len;
+  }
+  return tx;
+}
+
+/* Matches Curl_send signature */
+static ssize_t sec_send(struct Curl_easy *data, int sockindex,
+                        const void *buffer, size_t len, CURLcode *err)
+{
+  struct connectdata *conn = data->conn;
+  curl_socket_t fd = conn->sock[sockindex];
+  *err = CURLE_OK;
+  return sec_write(data, conn, fd, buffer, len);
+}
+
+int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
+                      char *buffer, enum protection_level level)
+{
+  /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
+     int */
+  int decoded_len;
+  char *buf;
+  int ret_code = 0;
+  size_t decoded_sz = 0;
+  CURLcode error;
+
+  (void) data;
+
+  if(!conn->mech)
+    /* not inititalized, return error */
+    return -1;
+
+  DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+  error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
+  if(error || decoded_sz == 0)
+    return -1;
+
+  if(decoded_sz > (size_t)INT_MAX) {
+    free(buf);
+    return -1;
+  }
+  decoded_len = curlx_uztosi(decoded_sz);
+
+  decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
+                                   level, conn);
+  if(decoded_len <= 0) {
+    free(buf);
+    return -1;
+  }
+
+  {
+    buf[decoded_len] = '\n';
+    Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1);
+  }
+
+  buf[decoded_len] = '\0';
+  if(decoded_len <= 3)
+    /* suspiciously short */
+    return 0;
+
+  if(buf[3] != '-')
+    /* safe to ignore return code */
+    (void)sscanf(buf, "%d", &ret_code);
+
+  if(buf[decoded_len - 1] == '\n')
+    buf[decoded_len - 1] = '\0';
+  strcpy(buffer, buf);
+  free(buf);
+  return ret_code;
+}
+
+static int sec_set_protection_level(struct Curl_easy *data)
+{
+  int code;
+  struct connectdata *conn = data->conn;
+  enum protection_level level = conn->request_data_prot;
+
+  DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+  if(!conn->sec_complete) {
+    infof(data, "Trying to change the protection level after the"
+                " completion of the data exchange.\n");
+    return -1;
+  }
+
+  /* Bail out if we try to set up the same level */
+  if(conn->data_prot == level)
+    return 0;
+
+  if(level) {
+    char *pbsz;
+    static unsigned int buffer_size = 1 << 20; /* 1048576 */
+
+    code = ftp_send_command(data, "PBSZ %u", buffer_size);
+    if(code < 0)
+      return -1;
+
+    if(code/100 != 2) {
+      failf(data, "Failed to set the protection's buffer size.");
+      return -1;
+    }
+    conn->buffer_size = buffer_size;
+
+    pbsz = strstr(data->state.buffer, "PBSZ=");
+    if(pbsz) {
+      /* ignore return code, use default value if it fails */
+      (void)sscanf(pbsz, "PBSZ=%u", &buffer_size);
+      if(buffer_size < conn->buffer_size)
+        conn->buffer_size = buffer_size;
+    }
+  }
+
+  /* Now try to negiociate the protection level. */
+  code = ftp_send_command(data, "PROT %c", level_to_char(level));
+
+  if(code < 0)
+    return -1;
+
+  if(code/100 != 2) {
+    failf(data, "Failed to set the protection level.");
+    return -1;
+  }
+
+  conn->data_prot = level;
+  if(level == PROT_PRIVATE)
+    conn->command_prot = level;
+
+  return 0;
+}
+
+int
+Curl_sec_request_prot(struct connectdata *conn, const char *level)
+{
+  enum protection_level l = name_to_level(level);
+  if(l == PROT_NONE)
+    return -1;
+  DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
+  conn->request_data_prot = l;
+  return 0;
+}
+
+static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
+{
+  int ret;
+  void *tmp_allocation;
+  const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
+
+  tmp_allocation = realloc(conn->app_data, mech->size);
+  if(tmp_allocation == NULL) {
+    failf(data, "Failed realloc of size %zu", mech->size);
+    mech = NULL;
+    return CURLE_OUT_OF_MEMORY;
+  }
+  conn->app_data = tmp_allocation;
+
+  if(mech->init) {
+    ret = mech->init(conn->app_data);
+    if(ret) {
+      infof(data, "Failed initialization for %s. Skipping it.\n",
+            mech->name);
+      return CURLE_FAILED_INIT;
+    }
+  }
+
+  infof(data, "Trying mechanism %s...\n", mech->name);
+  ret = ftp_send_command(data, "AUTH %s", mech->name);
+  if(ret < 0)
+    return CURLE_COULDNT_CONNECT;
+
+  if(ret/100 != 3) {
+    switch(ret) {
+    case 504:
+      infof(data, "Mechanism %s is not supported by the server (server "
+            "returned ftp code: 504).\n", mech->name);
+      break;
+    case 534:
+      infof(data, "Mechanism %s was rejected by the server (server returned "
+            "ftp code: 534).\n", mech->name);
+      break;
+    default:
+      if(ret/100 == 5) {
+        infof(data, "server does not support the security extensions\n");
+        return CURLE_USE_SSL_FAILED;
+      }
+      break;
+    }
+    return CURLE_LOGIN_DENIED;
+  }
+
+  /* Authenticate */
+  ret = mech->auth(conn->app_data, data, conn);
+
+  if(ret != AUTH_CONTINUE) {
+    if(ret != AUTH_OK) {
+      /* Mechanism has dumped the error to stderr, don't error here. */
+      return CURLE_USE_SSL_FAILED;
+    }
+    DEBUGASSERT(ret == AUTH_OK);
+
+    conn->mech = mech;
+    conn->sec_complete = 1;
+    conn->recv[FIRSTSOCKET] = sec_recv;
+    conn->send[FIRSTSOCKET] = sec_send;
+    conn->recv[SECONDARYSOCKET] = sec_recv;
+    conn->send[SECONDARYSOCKET] = sec_send;
+    conn->command_prot = PROT_SAFE;
+    /* Set the requested protection level */
+    /* BLOCKING */
+    (void)sec_set_protection_level(data);
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode
+Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
+{
+  return choose_mech(data, conn);
+}
+
+
+void
+Curl_sec_end(struct connectdata *conn)
+{
+  if(conn->mech != NULL && conn->mech->end)
+    conn->mech->end(conn->app_data);
+  free(conn->app_data);
+  conn->app_data = NULL;
+  if(conn->in_buffer.data) {
+    free(conn->in_buffer.data);
+    conn->in_buffer.data = NULL;
+    conn->in_buffer.size = 0;
+    conn->in_buffer.index = 0;
+    conn->in_buffer.eof_flag = 0;
+  }
+  conn->sec_complete = 0;
+  conn->data_prot = PROT_CLEAR;
+  conn->mech = NULL;
+}
+
 #endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */
index 512def6..307ebeb 100644 (file)
@@ -5,11 +5,11 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -100,7 +100,8 @@ struct ldap_urldesc {
 #undef LDAPURLDesc
 #define LDAPURLDesc struct ldap_urldesc
 
-static int  _ldap_url_parse(const struct connectdata *conn,
+static int  _ldap_url_parse(struct Curl_easy *data,
+                            const struct connectdata *conn,
                             LDAPURLDesc **ludp);
 static void _ldap_free_urldesc(LDAPURLDesc *ludp);
 
@@ -126,7 +127,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp);
 #endif
 
 
-static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
+static CURLcode ldap_do(struct Curl_easy *data, bool *done);
 
 /*
  * LDAP protocol handler.
@@ -135,7 +136,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
 const struct Curl_handler Curl_handler_ldap = {
   "LDAP",                               /* scheme */
   ZERO_NULL,                            /* setup_connection */
-  Curl_ldap,                            /* do_it */
+  ldap_do,                              /* do_it */
   ZERO_NULL,                            /* done */
   ZERO_NULL,                            /* do_more */
   ZERO_NULL,                            /* connect_it */
@@ -150,6 +151,7 @@ const struct Curl_handler Curl_handler_ldap = {
   ZERO_NULL,                            /* connection_check */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
+  CURLPROTO_LDAP,                       /* family */
   PROTOPT_NONE                          /* flags */
 };
 
@@ -161,7 +163,7 @@ const struct Curl_handler Curl_handler_ldap = {
 const struct Curl_handler Curl_handler_ldaps = {
   "LDAPS",                              /* scheme */
   ZERO_NULL,                            /* setup_connection */
-  Curl_ldap,                            /* do_it */
+  ldap_do,                              /* do_it */
   ZERO_NULL,                            /* done */
   ZERO_NULL,                            /* do_more */
   ZERO_NULL,                            /* connect_it */
@@ -176,6 +178,7 @@ const struct Curl_handler Curl_handler_ldaps = {
   ZERO_NULL,                            /* connection_check */
   PORT_LDAPS,                           /* defport */
   CURLPROTO_LDAPS,                      /* protocol */
+  CURLPROTO_LDAP,                       /* family */
   PROTOPT_SSL                           /* flags */
 };
 #endif
@@ -230,7 +233,7 @@ static int ldap_win_bind_auth(LDAP *server, const char *user,
 }
 #endif /* #if defined(USE_WINDOWS_SSPI) */
 
-static int ldap_win_bind(struct connectdata *conn, LDAP *server,
+static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
                          const char *user, const char *passwd)
 {
   int rc = LDAP_INVALID_CREDENTIALS;
@@ -238,7 +241,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
   PTCHAR inuser = NULL;
   PTCHAR inpass = NULL;
 
-  if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) {
+  if(user && passwd && (data->set.httpauth & CURLAUTH_BASIC)) {
     inuser = curlx_convert_UTF8_to_tchar((char *) user);
     inpass = curlx_convert_UTF8_to_tchar((char *) passwd);
 
@@ -249,7 +252,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
   }
 #if defined(USE_WINDOWS_SSPI)
   else {
-    rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth);
+    rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
   }
 #endif
 
@@ -257,7 +260,14 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
 }
 #endif /* #if defined(USE_WIN32_LDAP) */
 
-static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
+#if defined(USE_WIN32_LDAP)
+#define FREE_ON_WINLDAP(x) curlx_unicodefree(x)
+#else
+#define FREE_ON_WINLDAP(x)
+#endif
+
+
+static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
   int rc = 0;
@@ -266,7 +276,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   LDAPMessage *ldapmsg = NULL;
   LDAPMessage *entryIterator;
   int num = 0;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   int ldap_proto = LDAP_VERSION3;
   int ldap_ssl = 0;
   char *val_b64 = NULL;
@@ -291,7 +301,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 #ifdef HAVE_LDAP_URL_PARSE
   rc = ldap_url_parse(data->change.url, &ludp);
 #else
-  rc = _ldap_url_parse(conn, &ludp);
+  rc = _ldap_url_parse(data, conn, &ludp);
 #endif
   if(rc != 0) {
     failf(data, "LDAP local: %s", ldap_err2string(rc));
@@ -463,10 +473,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   }
 #ifdef USE_WIN32_LDAP
   ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
-#endif
-
-#ifdef USE_WIN32_LDAP
-  rc = ldap_win_bind(conn, server, user, passwd);
+  rc = ldap_win_bind(data, server, user, passwd);
 #else
   rc = ldap_simple_bind_s(server, user, passwd);
 #endif
@@ -474,7 +481,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
     ldap_proto = LDAP_VERSION2;
     ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
 #ifdef USE_WIN32_LDAP
-    rc = ldap_win_bind(conn, server, user, passwd);
+    rc = ldap_win_bind(data, server, user, passwd);
 #else
     rc = ldap_simple_bind_s(server, user, passwd);
 #endif
@@ -507,7 +514,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 #if defined(USE_WIN32_LDAP)
     TCHAR *attribute;
 #else
-    char  *attribute;       /*! suspicious that this isn't 'const' */
+    char *attribute;
 #endif
     int i;
 
@@ -530,32 +537,24 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 #endif
       name_len = strlen(name);
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
       if(result) {
-#if defined(USE_WIN32_LDAP)
-        curlx_unicodefree(name);
-#endif
+        FREE_ON_WINLDAP(name);
         ldap_memfree(dn);
-
         goto quit;
       }
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name,
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) name,
                                  name_len);
       if(result) {
-#if defined(USE_WIN32_LDAP)
-        curlx_unicodefree(name);
-#endif
+        FREE_ON_WINLDAP(name);
         ldap_memfree(dn);
-
         goto quit;
       }
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
       if(result) {
-#if defined(USE_WIN32_LDAP)
-        curlx_unicodefree(name);
-#endif
+        FREE_ON_WINLDAP(name);
         ldap_memfree(dn);
 
         goto quit;
@@ -563,9 +562,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 
       dlsize += name_len + 5;
 
-#if defined(USE_WIN32_LDAP)
-      curlx_unicodefree(name);
-#endif
+      FREE_ON_WINLDAP(name);
       ldap_memfree(dn);
     }
 
@@ -593,12 +590,10 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
       vals = ldap_get_values_len(server, entryIterator, attribute);
       if(vals != NULL) {
         for(i = 0; (vals[i] != NULL); i++) {
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
           if(result) {
             ldap_value_free_len(vals);
-#if defined(USE_WIN32_LDAP)
-            curlx_unicodefree(attr);
-#endif
+            FREE_ON_WINLDAP(attr);
             ldap_memfree(attribute);
             if(ber)
               ber_free(ber, 0);
@@ -606,13 +601,11 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             goto quit;
           }
 
-          result = Curl_client_write(conn, CLIENTWRITE_BODY,
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
                                      (char *) attr, attr_len);
           if(result) {
             ldap_value_free_len(vals);
-#if defined(USE_WIN32_LDAP)
-            curlx_unicodefree(attr);
-#endif
+            FREE_ON_WINLDAP(attr);
             ldap_memfree(attribute);
             if(ber)
               ber_free(ber, 0);
@@ -620,12 +613,10 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             goto quit;
           }
 
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
           if(result) {
             ldap_value_free_len(vals);
-#if defined(USE_WIN32_LDAP)
-            curlx_unicodefree(attr);
-#endif
+            FREE_ON_WINLDAP(attr);
             ldap_memfree(attribute);
             if(ber)
               ber_free(ber, 0);
@@ -645,9 +636,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
                                         &val_b64_sz);
             if(result) {
               ldap_value_free_len(vals);
-#if defined(USE_WIN32_LDAP)
-              curlx_unicodefree(attr);
-#endif
+              FREE_ON_WINLDAP(attr);
               ldap_memfree(attribute);
               if(ber)
                 ber_free(ber, 0);
@@ -656,14 +645,12 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             }
 
             if(val_b64_sz > 0) {
-              result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+              result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
                                          val_b64_sz);
               free(val_b64);
               if(result) {
                 ldap_value_free_len(vals);
-#if defined(USE_WIN32_LDAP)
-                curlx_unicodefree(attr);
-#endif
+                FREE_ON_WINLDAP(attr);
                 ldap_memfree(attribute);
                 if(ber)
                   ber_free(ber, 0);
@@ -675,13 +662,11 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             }
           }
           else {
-            result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
+            result = Curl_client_write(data, CLIENTWRITE_BODY, vals[i]->bv_val,
                                        vals[i]->bv_len);
             if(result) {
               ldap_value_free_len(vals);
-#if defined(USE_WIN32_LDAP)
-              curlx_unicodefree(attr);
-#endif
+              FREE_ON_WINLDAP(attr);
               ldap_memfree(attribute);
               if(ber)
                 ber_free(ber, 0);
@@ -692,12 +677,10 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             dlsize += vals[i]->bv_len;
           }
 
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
           if(result) {
             ldap_value_free_len(vals);
-#if defined(USE_WIN32_LDAP)
-            curlx_unicodefree(attr);
-#endif
+            FREE_ON_WINLDAP(attr);
             ldap_memfree(attribute);
             if(ber)
               ber_free(ber, 0);
@@ -713,12 +696,10 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
       }
 
       /* Free the attribute as we are done with it */
-#if defined(USE_WIN32_LDAP)
-      curlx_unicodefree(attr);
-#endif
+      FREE_ON_WINLDAP(attr);
       ldap_memfree(attribute);
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
       if(result)
         goto quit;
       dlsize++;
@@ -745,9 +726,7 @@ quit:
     ldapssl_client_deinit();
 #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
 
-#if defined(USE_WIN32_LDAP)
-  curlx_unicodefree(host);
-#endif
+  FREE_ON_WINLDAP(host);
 
   /* no data to transfer */
   Curl_setup_transfer(data, -1, -1, FALSE, -1);
@@ -834,14 +813,15 @@ static bool split_str(char *str, char ***out, size_t *count)
  *
  * <hostname> already known from 'conn->host.name'.
  * <port>     already known from 'conn->remote_port'.
- * extract the rest from 'conn->data->state.path+1'. All fields are optional.
+ * extract the rest from 'data->state.path+1'. All fields are optional.
  * e.g.
  *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
  * yields ludp->lud_dn = "".
  *
  * Defined in RFC4516 section 2.
  */
-static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
+static int _ldap_url_parse2(struct Curl_easy *data,
+                            const struct connectdata *conn, LDAPURLDesc *ludp)
 {
   int rc = LDAP_SUCCESS;
   char *p;
@@ -850,10 +830,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
   char *query = NULL;
   size_t i;
 
-  if(!conn->data ||
-     !conn->data->state.up.path ||
-     conn->data->state.up.path[0] != '/' ||
-     !strncasecompare("LDAP", conn->data->state.up.scheme, 4))
+  if(!data ||
+     !data->state.up.path ||
+     data->state.up.path[0] != '/' ||
+     !strncasecompare("LDAP", data->state.up.scheme, 4))
     return LDAP_INVALID_SYNTAX;
 
   ludp->lud_scope = LDAP_SCOPE_BASE;
@@ -861,13 +841,13 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
   ludp->lud_host  = conn->host.name;
 
   /* Duplicate the path */
-  p = path = strdup(conn->data->state.up.path + 1);
+  p = path = strdup(data->state.up.path + 1);
   if(!path)
     return LDAP_NO_MEMORY;
 
   /* Duplicate the query if present */
-  if(conn->data->state.up.query) {
-    q = query = strdup(conn->data->state.up.query);
+  if(data->state.up.query) {
+    q = query = strdup(data->state.up.query);
     if(!query) {
       free(path);
       return LDAP_NO_MEMORY;
@@ -883,7 +863,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
     LDAP_TRACE(("DN '%s'\n", dn));
 
     /* Unescape the DN */
-    result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, REJECT_ZERO);
+    result = Curl_urldecode(data, dn, 0, &unescaped, NULL, REJECT_ZERO);
     if(result) {
       rc = LDAP_NO_MEMORY;
 
@@ -945,10 +925,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
       char *unescaped;
       CURLcode result;
 
-      LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i]));
+      LDAP_TRACE(("attr[%zu] '%s'\n", i, attributes[i]));
 
       /* Unescape the attribute */
-      result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL,
+      result = Curl_urldecode(data, attributes[i], 0, &unescaped, NULL,
                               REJECT_ZERO);
       if(result) {
         free(attributes);
@@ -1018,8 +998,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
     LDAP_TRACE(("filter '%s'\n", filter));
 
     /* Unescape the filter */
-    result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL,
-                            REJECT_ZERO);
+    result = Curl_urldecode(data, filter, 0, &unescaped, NULL, REJECT_ZERO);
     if(result) {
       rc = LDAP_NO_MEMORY;
 
@@ -1057,7 +1036,8 @@ quit:
   return rc;
 }
 
-static int _ldap_url_parse(const struct connectdata *conn,
+static int _ldap_url_parse(struct Curl_easy *data,
+                           const struct connectdata *conn,
                            LDAPURLDesc **ludpp)
 {
   LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
@@ -1067,7 +1047,7 @@ static int _ldap_url_parse(const struct connectdata *conn,
   if(!ludp)
      return LDAP_NO_MEMORY;
 
-  rc = _ldap_url_parse2(conn, ludp);
+  rc = _ldap_url_parse2(data, conn, ludp);
   if(rc != LDAP_SUCCESS) {
     _ldap_free_urldesc(ludp);
     ludp = NULL;
index 4839d0a..3f7ae16 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -44,7 +44,7 @@ BEGIN
   BEGIN
     BLOCK "040904b0"
     BEGIN
-      VALUE "CompanyName",      "The curl library, https://curl.haxx.se/\0"
+      VALUE "CompanyName",      "The curl library, https://curl.se/\0"
       VALUE "FileDescription",  "libcurl Shared Library\0"
       VALUE "FileVersion",      LIBCURL_VERSION "\0"
       VALUE "InternalName",     "libcurl\0"
@@ -52,7 +52,7 @@ BEGIN
       VALUE "ProductName",      "The curl library\0"
       VALUE "ProductVersion",   LIBCURL_VERSION "\0"
       VALUE "LegalCopyright",   "\xa9 " LIBCURL_COPYRIGHT "\0"  /* a9: Copyright symbol */
-      VALUE "License",          "https://curl.haxx.se/docs/copyright.html\0"
+      VALUE "License",          "https://curl.se/docs/copyright.html\0"
     END
   END
 
index e7c6f51..17a7be1 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -34,7 +34,7 @@
  * @unittest: 1300
  */
 void
-Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
+Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
 {
   l->size = 0;
   l->dtor = dtor;
@@ -54,9 +54,9 @@ Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
  * @unittest: 1300
  */
 void
-Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e,
+Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e,
                        const void *p,
-                       struct curl_llist_element *ne)
+                       struct Curl_llist_element *ne)
 {
   ne->ptr = (void *) p;
   if(list->size == 0) {
@@ -90,7 +90,7 @@ Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e,
  * @unittest: 1300
  */
 void
-Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
+Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
                   void *user)
 {
   void *ptr;
@@ -131,7 +131,7 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
 }
 
 void
-Curl_llist_destroy(struct curl_llist *list, void *user)
+Curl_llist_destroy(struct Curl_llist *list, void *user)
 {
   if(list) {
     while(list->size > 0)
@@ -140,7 +140,7 @@ Curl_llist_destroy(struct curl_llist *list, void *user)
 }
 
 size_t
-Curl_llist_count(struct curl_llist *list)
+Curl_llist_count(struct Curl_llist *list)
 {
   return list->size;
 }
index 0178c42..ceae2dd 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
 #include "curl_setup.h"
 #include <stddef.h>
 
-typedef void (*curl_llist_dtor)(void *, void *);
+typedef void (*Curl_llist_dtor)(void *, void *);
 
-struct curl_llist_element {
+struct Curl_llist_element {
   void *ptr;
-  struct curl_llist_element *prev;
-  struct curl_llist_element *next;
+  struct Curl_llist_element *prev;
+  struct Curl_llist_element *next;
 };
 
-struct curl_llist {
-  struct curl_llist_element *head;
-  struct curl_llist_element *tail;
-  curl_llist_dtor dtor;
+struct Curl_llist {
+  struct Curl_llist_element *head;
+  struct Curl_llist_element *tail;
+  Curl_llist_dtor dtor;
   size_t size;
 };
 
-void Curl_llist_init(struct curl_llist *, curl_llist_dtor);
-void Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *,
-                            const void *, struct curl_llist_element *node);
-void Curl_llist_remove(struct curl_llist *, struct curl_llist_element *,
+void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor);
+void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *,
+                            const void *, struct Curl_llist_element *node);
+void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *,
                        void *);
-size_t Curl_llist_count(struct curl_llist *);
-void Curl_llist_destroy(struct curl_llist *, void *);
+size_t Curl_llist_count(struct Curl_llist *);
+void Curl_llist_destroy(struct Curl_llist *, void *);
 #endif /* HEADER_CURL_LLIST_H */
index 67119cd..8ae6ac3 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index d21625f..513ffb2 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index da75c9f..881ee85 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
 #include "curl_memory.h"
 #include "memdebug.h"
 
-/*
- * Until 2011-08-17 libcurl's Memory Tracking feature also performed
- * automatic malloc and free filling operations using 0xA5 and 0x13
- * values. Our own preinitialization of dynamically allocated memory
- * might be useful when not using third party memory debuggers, but
- * on the other hand this would fool memory debuggers into thinking
- * that all dynamically allocated memory is properly initialized.
- *
- * As a default setting, libcurl's Memory Tracking feature no longer
- * performs preinitialization of dynamically allocated memory on its
- * own. If you know what you are doing, and really want to retain old
- * behavior, you can achieve this compiling with preprocessor symbols
- * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate
- * values.
- */
-
-#ifdef CURL_MT_MALLOC_FILL
-# if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff)
-#   error "invalid CURL_MT_MALLOC_FILL or out of range"
-# endif
-#endif
-
-#ifdef CURL_MT_FREE_FILL
-# if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff)
-#   error "invalid CURL_MT_FREE_FILL or out of range"
-# endif
-#endif
-
-#if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL)
-# if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL)
-#   error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL"
-# endif
-#endif
-
-#ifdef CURL_MT_MALLOC_FILL
-#  define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len))
-#else
-#  define mt_malloc_fill(buf,len) Curl_nop_stmt
-#endif
-
-#ifdef CURL_MT_FREE_FILL
-#  define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len))
-#else
-#  define mt_free_fill(buf,len) Curl_nop_stmt
-#endif
-
 struct memdebug {
   size_t size;
   union {
@@ -173,8 +127,6 @@ void *curl_dbg_malloc(size_t wantedsize, int line, const char *source)
 
   mem = (Curl_cmalloc)(size);
   if(mem) {
-    /* fill memory with junk */
-    mt_malloc_fill(mem->mem, wantedsize);
     mem->size = wantedsize;
   }
 
@@ -321,9 +273,6 @@ void curl_dbg_free(void *ptr, int line, const char *source)
 #  pragma warning(pop)
 #endif
 
-    /* destroy */
-    mt_free_fill(mem->mem, mem->size);
-
     /* free for real */
     (Curl_cfree)(mem);
   }
index 4edafdf..8e88cea 100644 (file)
@@ -12,7 +12,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 6a9b64a..abadcb0 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -1168,6 +1168,7 @@ static void cleanup_part_content(curl_mimepart *part)
   part->kind = MIMEKIND_NONE;
   part->flags &= ~MIME_FAST_READ;
   part->lastreadstatus = 1; /* Successful read status. */
+  part->state.state = MIMESTATE_BEGIN;
 }
 
 static void mime_subparts_free(void *ptr)
index 50b7ea6..56642ae 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -110,6 +110,7 @@ struct curl_mimepart {
   curl_mime *parent;               /* Parent mime structure. */
   curl_mimepart *nextpart;         /* Forward linked list. */
   enum mimekind kind;              /* The part kind. */
+  unsigned int flags;              /* Flags. */
   char *data;                      /* Memory data or file name. */
   curl_read_callback readfunc;     /* Read function. */
   curl_seek_callback seekfunc;     /* Seek function. */
@@ -122,7 +123,6 @@ struct curl_mimepart {
   char *filename;                  /* Remote file name. */
   char *name;                      /* Data name. */
   curl_off_t datasize;             /* Expected data size. */
-  unsigned int flags;              /* Flags. */
   struct mime_state state;         /* Current readback state. */
   const struct mime_encoder *encoder; /* Content data encoder. */
   struct mime_encoder_state encstate; /* Data encoder state. */
index 80735be..c681248 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -99,12 +99,12 @@ static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 /* Upper-case digits.  */
 static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
-#define OUTCHAR(x) \
-  do{ \
+#define OUTCHAR(x)                                     \
+  do {                                                 \
     if(stream((unsigned char)(x), (FILE *)data) != -1) \
-      done++; \
-    else \
-     return done; /* return immediately on failure */ \
+      done++;                                          \
+    else                                               \
+      return done; /* return immediately on failure */ \
   } while(0)
 
 /* Data type to read from the arglist */
@@ -169,7 +169,7 @@ struct nsprintf {
 };
 
 struct asprintf {
-  struct dynbuf b;
+  struct dynbuf *b;
   bool fail; /* if an alloc has failed and thus the output is not the complete
                 data */
 };
@@ -878,7 +878,7 @@ static int dprintf_formatf(
               OUTCHAR(' ');
           for(point = strnil; *point != '\0'; ++point)
             OUTCHAR(*point);
-          if(! (p->flags & FLAGS_LEFT))
+          if(!(p->flags & FLAGS_LEFT))
             while(width-- > 0)
               OUTCHAR(' ');
         }
@@ -1042,50 +1042,61 @@ static int alloc_addbyter(int output, FILE *data)
   struct asprintf *infop = (struct asprintf *)data;
   unsigned char outc = (unsigned char)output;
 
-  if(Curl_dyn_addn(&infop->b, &outc, 1)) {
+  if(Curl_dyn_addn(infop->b, &outc, 1)) {
     infop->fail = 1;
     return -1; /* fail */
   }
   return outc; /* fputc() returns like this on success */
 }
 
-char *curl_maprintf(const char *format, ...)
+extern int Curl_dyn_vprintf(struct dynbuf *dyn,
+                            const char *format, va_list ap_save);
+
+/* appends the formatted string, returns 0 on success, 1 on error */
+int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
 {
-  va_list ap_save; /* argument pointer */
   int retcode;
   struct asprintf info;
-  Curl_dyn_init(&info.b, DYN_APRINTF);
+  info.b = dyn;
   info.fail = 0;
 
-  va_start(ap_save, format);
   retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
-  va_end(ap_save);
   if((-1 == retcode) || info.fail) {
-    Curl_dyn_free(&info.b);
-    return NULL;
+    Curl_dyn_free(info.b);
+    return 1;
   }
-  if(Curl_dyn_len(&info.b))
-    return Curl_dyn_ptr(&info.b);
-  return strdup("");
+  return 0;
 }
 
 char *curl_mvaprintf(const char *format, va_list ap_save)
 {
   int retcode;
   struct asprintf info;
-  Curl_dyn_init(&info.b, DYN_APRINTF);
+  struct dynbuf dyn;
+  info.b = &dyn;
+  Curl_dyn_init(info.b, DYN_APRINTF);
   info.fail = 0;
 
   retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
   if((-1 == retcode) || info.fail) {
-    Curl_dyn_free(&info.b);
+    Curl_dyn_free(info.b);
     return NULL;
   }
-  if(Curl_dyn_len(&info.b))
-    return Curl_dyn_ptr(&info.b);
+  if(Curl_dyn_len(info.b))
+    return Curl_dyn_ptr(info.b);
   return strdup("");
 }
 
+char *curl_maprintf(const char *format, ...)
+{
+  va_list ap_save;
+  char *s;
+  va_start(ap_save, format);
+  s = curl_mvaprintf(format, ap_save);
+  va_end(ap_save);
+  return s;
+}
+
 static int storebuffer(int output, FILE *data)
 {
   char **buffer = (char **)data;
index f6f4416..2134409 100644 (file)
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2020 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2019, Björn Stenberg, <bjorn@haxx.se>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -23,7 +23,7 @@
 
 #include "curl_setup.h"
 
-#ifdef CURL_ENABLE_MQTT
+#ifndef CURL_DISABLE_MQTT
 
 #include "urldata.h"
 #include <curl/curl.h>
  * Forward declarations.
  */
 
-static CURLcode mqtt_do(struct connectdata *conn, bool *done);
-static CURLcode mqtt_doing(struct connectdata *conn, bool *done);
-static int mqtt_getsock(struct connectdata *conn, curl_socket_t *sock);
-static CURLcode mqtt_setup_conn(struct connectdata *conn);
+static CURLcode mqtt_do(struct Curl_easy *data, bool *done);
+static CURLcode mqtt_doing(struct Curl_easy *data, bool *done);
+static int mqtt_getsock(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t *sock);
+static CURLcode mqtt_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn);
 
 /*
  * MQTT protocol handler.
@@ -86,34 +88,36 @@ const struct Curl_handler Curl_handler_mqtt = {
   ZERO_NULL,                          /* connection_check */
   PORT_MQTT,                          /* defport */
   CURLPROTO_MQTT,                     /* protocol */
+  CURLPROTO_MQTT,                     /* family */
   PROTOPT_NONE                        /* flags */
 };
 
-static CURLcode mqtt_setup_conn(struct connectdata *conn)
+static CURLcode mqtt_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn)
 {
   /* allocate the HTTP-specific struct for the Curl_easy, only to survive
      during this request */
   struct MQTT *mq;
-  struct Curl_easy *data = conn->data;
-  DEBUGASSERT(data->req.protop == NULL);
+  (void)conn;
+  DEBUGASSERT(data->req.p.mqtt == NULL);
 
   mq = calloc(1, sizeof(struct MQTT));
   if(!mq)
     return CURLE_OUT_OF_MEMORY;
-  data->req.protop = mq;
+  data->req.p.mqtt = mq;
   return CURLE_OK;
 }
 
-static CURLcode mqtt_send(struct connectdata *conn,
+static CURLcode mqtt_send(struct Curl_easy *data,
                           char *buf, size_t len)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data = conn->data;
-  struct MQTT *mq = data->req.protop;
+  struct MQTT *mq = data->req.p.mqtt;
   ssize_t n;
-  result = Curl_write(conn, sockfd, buf, len, &n);
-  if(!result && data->set.verbose)
+  result = Curl_write(data, sockfd, buf, len, &n);
+  if(!result)
     Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
   if(len != (size_t)n) {
     size_t nsend = len - n;
@@ -129,20 +133,22 @@ static CURLcode mqtt_send(struct connectdata *conn,
 /* Generic function called by the multi interface to figure out what socket(s)
    to wait for and for what actions during the DOING and PROTOCONNECT
    states */
-static int mqtt_getsock(struct connectdata *conn,
+static int mqtt_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
                         curl_socket_t *sock)
 {
+  (void)data;
   sock[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_READSOCK(FIRSTSOCKET);
 }
 
-static CURLcode mqtt_connect(struct connectdata *conn)
+static CURLcode mqtt_connect(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
   const size_t client_id_offset = 14;
   const size_t packetlen = client_id_offset + MQTT_CLIENTID_LEN;
   char client_id[MQTT_CLIENTID_LEN + 1] = "curl";
-  const size_t curl_len = strlen("curl");
+  const size_t clen = strlen("curl");
   char packet[32] = {
     MQTT_MSG_CONNECT,  /* packet type */
     0x00,              /* remaining length */
@@ -156,36 +162,35 @@ static CURLcode mqtt_connect(struct connectdata *conn)
   packet[1] = (packetlen - 2) & 0x7f;
   packet[client_id_offset - 1] = MQTT_CLIENTID_LEN;
 
-  result = Curl_rand_hex(conn->data, (unsigned char *)&client_id[curl_len],
-                         MQTT_CLIENTID_LEN - curl_len + 1);
+  result = Curl_rand_hex(data, (unsigned char *)&client_id[clen],
+                         MQTT_CLIENTID_LEN - clen + 1);
   memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN);
-  infof(conn->data, "Using client id '%s'\n", client_id);
+  infof(data, "Using client id '%s'\n", client_id);
   if(!result)
-    result = mqtt_send(conn, packet, packetlen);
+    result = mqtt_send(data, packet, packetlen);
   return result;
 }
 
-static CURLcode mqtt_disconnect(struct connectdata *conn)
+static CURLcode mqtt_disconnect(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  result = mqtt_send(conn, (char *)"\xe0\x00", 2);
+  result = mqtt_send(data, (char *)"\xe0\x00", 2);
   return result;
 }
 
-static CURLcode mqtt_verify_connack(struct connectdata *conn)
+static CURLcode mqtt_verify_connack(struct Curl_easy *data)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   unsigned char readbuf[MQTT_CONNACK_LEN];
   ssize_t nread;
-  struct Curl_easy *data = conn->data;
 
-  result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread);
+  result = Curl_read(data, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread);
   if(result)
     goto fail;
 
-  if(data->set.verbose)
-    Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread);
+  Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread);
 
   /* fixme */
   if(nread < MQTT_CONNACK_LEN) {
@@ -204,18 +209,18 @@ fail:
   return result;
 }
 
-static CURLcode mqtt_get_topic(struct connectdata *conn,
+static CURLcode mqtt_get_topic(struct Curl_easy *data,
                                char **topic, size_t *topiclen)
 {
   CURLcode result = CURLE_OK;
-  char *path = conn->data->state.up.path;
+  char *path = data->state.up.path;
 
   if(strlen(path) > 1) {
-    result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen,
+    result = Curl_urldecode(data, path + 1, 0, topic, topiclen,
                             REJECT_NADA);
   }
   else {
-    failf(conn->data, "Error: No topic specified.");
+    failf(data, "Error: No topic specified.");
     result = CURLE_URL_MALFORMAT;
   }
   return result;
@@ -238,7 +243,7 @@ static int mqtt_encode_len(char *buf, size_t len)
   return i;
 }
 
-static CURLcode mqtt_subscribe(struct connectdata *conn)
+static CURLcode mqtt_subscribe(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
   char *topic = NULL;
@@ -247,8 +252,9 @@ static CURLcode mqtt_subscribe(struct connectdata *conn)
   size_t packetlen;
   char encodedsize[4];
   size_t n;
+  struct connectdata *conn = data->conn;
 
-  result = mqtt_get_topic(conn, &topic, &topiclen);
+  result = mqtt_get_topic(data, &topic, &topiclen);
   if(result)
     goto fail;
 
@@ -274,7 +280,7 @@ static CURLcode mqtt_subscribe(struct connectdata *conn)
   memcpy(&packet[5 + n], topic, topiclen);
   packet[5 + n + topiclen] = 0; /* QoS zero */
 
-  result = mqtt_send(conn, (char *)packet, packetlen);
+  result = mqtt_send(data, (char *)packet, packetlen);
 
 fail:
   free(topic);
@@ -285,20 +291,20 @@ fail:
 /*
  * Called when the first byte was already read.
  */
-static CURLcode mqtt_verify_suback(struct connectdata *conn)
+static CURLcode mqtt_verify_suback(struct Curl_easy *data)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   unsigned char readbuf[MQTT_SUBACK_LEN];
   ssize_t nread;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
 
-  result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_SUBACK_LEN, &nread);
+  result = Curl_read(data, sockfd, (char *)readbuf, MQTT_SUBACK_LEN, &nread);
   if(result)
     goto fail;
 
-  if(conn->data->set.verbose)
-    Curl_debug(conn->data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread);
+  Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread);
 
   /* fixme */
   if(nread < MQTT_SUBACK_LEN) {
@@ -316,11 +322,11 @@ fail:
   return result;
 }
 
-static CURLcode mqtt_publish(struct connectdata *conn)
+static CURLcode mqtt_publish(struct Curl_easy *data)
 {
   CURLcode result;
-  char *payload = conn->data->set.postfields;
-  size_t payloadlen = (size_t)conn->data->set.postfieldsize;
+  char *payload = data->set.postfields;
+  size_t payloadlen;
   char *topic = NULL;
   size_t topiclen;
   unsigned char *pkt = NULL;
@@ -328,8 +334,16 @@ static CURLcode mqtt_publish(struct connectdata *conn)
   size_t remaininglength;
   size_t encodelen;
   char encodedbytes[4];
+  curl_off_t postfieldsize = data->set.postfieldsize;
+
+  if(!payload)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  if(postfieldsize < 0)
+    payloadlen = strlen(payload);
+  else
+    payloadlen = (size_t)postfieldsize;
 
-  result = mqtt_get_topic(conn, &topic, &topiclen);
+  result = mqtt_get_topic(data, &topic, &topiclen);
   if(result)
     goto fail;
 
@@ -353,7 +367,7 @@ static CURLcode mqtt_publish(struct connectdata *conn)
   i += topiclen;
   memcpy(&pkt[i], payload, payloadlen);
   i += payloadlen;
-  result = mqtt_send(conn, (char *)pkt, i);
+  result = mqtt_send(data, (char *)pkt, i);
 
 fail:
   free(pkt);
@@ -396,13 +410,14 @@ static const char *statenames[]={
 #endif
 
 /* The only way to change state */
-static void mqstate(struct connectdata *conn,
+static void mqstate(struct Curl_easy *data,
                     enum mqttstate state,
                     enum mqttstate nextstate) /* used if state == FIRST */
 {
+  struct connectdata *conn = data->conn;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
 #ifdef CURLDEBUG
-  infof(conn->data, "%s (from %s) (next is %s)\n",
+  infof(data, "%s (from %s) (next is %s)\n",
         statenames[state],
         statenames[mqtt->state],
         (state == MQTT_FIRST)? statenames[nextstate] : "");
@@ -416,27 +431,26 @@ static void mqstate(struct connectdata *conn,
 /* for the publish packet */
 #define MQTT_HEADER_LEN 5    /* max 5 bytes */
 
-static CURLcode mqtt_read_publish(struct connectdata *conn,
-                                  bool *done)
+static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   ssize_t nread;
-  struct Curl_easy *data = conn->data;
   unsigned char *pkt = (unsigned char *)data->state.buffer;
   size_t remlen;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
-  struct MQTT *mq = data->req.protop;
+  struct MQTT *mq = data->req.p.mqtt;
   unsigned char packet;
 
   switch(mqtt->state) {
   MQTT_SUBACK_COMING:
   case MQTT_SUBACK_COMING:
-    result = mqtt_verify_suback(conn);
+    result = mqtt_verify_suback(data);
     if(result)
       break;
 
-    mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT);
+    mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
     break;
 
   case MQTT_SUBACK:
@@ -444,9 +458,9 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
     /* we are expecting PUBLISH or SUBACK */
     packet = mq->firstbyte & 0xf0;
     if(packet == MQTT_MSG_PUBLISH)
-      mqstate(conn, MQTT_PUB_REMAIN, MQTT_NOSTATE);
+      mqstate(data, MQTT_PUB_REMAIN, MQTT_NOSTATE);
     else if(packet == MQTT_MSG_SUBACK) {
-      mqstate(conn, MQTT_SUBACK_COMING, MQTT_NOSTATE);
+      mqstate(data, MQTT_SUBACK_COMING, MQTT_NOSTATE);
       goto MQTT_SUBACK_COMING;
     }
     else if(packet == MQTT_MSG_DISCONNECT) {
@@ -473,7 +487,7 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
     size_t rest = mq->npacket;
     if(rest > (size_t)data->set.buffer_size)
       rest = (size_t)data->set.buffer_size;
-    result = Curl_read(conn, sockfd, (char *)pkt, rest, &nread);
+    result = Curl_read(data, sockfd, (char *)pkt, rest, &nread);
     if(result) {
       if(CURLE_AGAIN == result) {
         infof(data, "EEEE AAAAGAIN\n");
@@ -485,8 +499,7 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
       result = CURLE_PARTIAL_FILE;
       goto end;
     }
-    if(data->set.verbose)
-      Curl_debug(data, CURLINFO_DATA_IN, (char *)pkt, (size_t)nread);
+    Curl_debug(data, CURLINFO_DATA_IN, (char *)pkt, (size_t)nread);
 
     mq->npacket -= nread;
     k->bytecount += nread;
@@ -494,13 +507,13 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
 
     /* if QoS is set, message contains packet id */
 
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)pkt, nread);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)pkt, nread);
     if(result)
       goto end;
 
     if(!mq->npacket)
       /* no more PUBLISH payload, back to subscribe wait state */
-      mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT);
+      mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
     break;
   }
   default:
@@ -512,28 +525,26 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
   return result;
 }
 
-static CURLcode mqtt_do(struct connectdata *conn, bool *done)
+static CURLcode mqtt_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   *done = FALSE; /* unconditionally */
 
-  result = mqtt_connect(conn);
+  result = mqtt_connect(data);
   if(result) {
     failf(data, "Error %d sending MQTT CONN request", result);
     return result;
   }
-  mqstate(conn, MQTT_FIRST, MQTT_CONNACK);
+  mqstate(data, MQTT_FIRST, MQTT_CONNACK);
   return CURLE_OK;
 }
 
-static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
+static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
-  struct Curl_easy *data = conn->data;
-  struct MQTT *mq = data->req.protop;
+  struct MQTT *mq = data->req.p.mqtt;
   ssize_t nread;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   unsigned char *pkt = (unsigned char *)data->state.buffer;
@@ -544,7 +555,7 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
   if(mq->nsend) {
     /* send the remainder of an outgoing packet */
     char *ptr = mq->sendleftovers;
-    result = mqtt_send(conn, mq->sendleftovers, mq->nsend);
+    result = mqtt_send(data, mq->sendleftovers, mq->nsend);
     free(ptr);
     if(result)
       return result;
@@ -554,22 +565,20 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
   switch(mqtt->state) {
   case MQTT_FIRST:
     /* Read the initial byte only */
-    result = Curl_read(conn, sockfd, (char *)&mq->firstbyte, 1, &nread);
-    if(result)
+    result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread);
+    if(!nread)
       break;
-    if(data->set.verbose)
-      Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
+    Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
     /* remember the first byte */
     mq->npacket = 0;
-    mqstate(conn, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
+    mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
     /* FALLTHROUGH */
   case MQTT_REMAINING_LENGTH:
     do {
-      result = Curl_read(conn, sockfd, (char *)&byte, 1, &nread);
-      if(result)
+      result = Curl_read(data, sockfd, (char *)&byte, 1, &nread);
+      if(!nread)
         break;
-      if(data->set.verbose)
-        Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
+      Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
       pkt[mq->npacket++] = byte;
     } while((byte & 0x80) && (mq->npacket < 4));
     if(result)
@@ -577,10 +586,10 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
     mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL);
     mq->npacket = 0;
     if(mq->remaining_length) {
-      mqstate(conn, mqtt->nextstate, MQTT_NOSTATE);
+      mqstate(data, mqtt->nextstate, MQTT_NOSTATE);
       break;
     }
-    mqstate(conn, MQTT_FIRST, MQTT_FIRST);
+    mqstate(data, MQTT_FIRST, MQTT_FIRST);
 
     if(mq->firstbyte == MQTT_MSG_DISCONNECT) {
       infof(data, "Got DISCONNECT\n");
@@ -588,22 +597,22 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
     }
     break;
   case MQTT_CONNACK:
-    result = mqtt_verify_connack(conn);
+    result = mqtt_verify_connack(data);
     if(result)
       break;
 
-    if(conn->data->state.httpreq == HTTPREQ_POST) {
-      result = mqtt_publish(conn);
+    if(data->state.httpreq == HTTPREQ_POST) {
+      result = mqtt_publish(data);
       if(!result) {
-        result = mqtt_disconnect(conn);
+        result = mqtt_disconnect(data);
         *done = TRUE;
       }
       mqtt->nextstate = MQTT_FIRST;
     }
     else {
-      result = mqtt_subscribe(conn);
+      result = mqtt_subscribe(data);
       if(!result) {
-        mqstate(conn, MQTT_FIRST, MQTT_SUBACK);
+        mqstate(data, MQTT_FIRST, MQTT_SUBACK);
       }
     }
     break;
@@ -611,11 +620,11 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
   case MQTT_SUBACK:
   case MQTT_PUBWAIT:
   case MQTT_PUB_REMAIN:
-    result = mqtt_read_publish(conn, done);
+    result = mqtt_read_publish(data, done);
     break;
 
   default:
-    failf(conn->data, "State not handled yet");
+    failf(data, "State not handled yet");
     *done = TRUE;
     break;
   }
@@ -625,4 +634,4 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
   return result;
 }
 
-#endif /* CURL_ENABLE_MQTT */
+#endif /* CURL_DISABLE_MQTT */
index 37463d5..fb52c72 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -22,7 +22,7 @@
  *
  ***************************************************************************/
 
-#ifdef CURL_ENABLE_MQTT
+#ifndef CURL_DISABLE_MQTT
 extern const struct Curl_handler Curl_handler_mqtt;
 #endif
 
index 3c7fb85..85707a1 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -69,7 +69,7 @@
 #define CURL_MULTI_HANDLE 0x000bab1e
 
 #define GOOD_MULTI_HANDLE(x) \
-  ((x) && (x)->type == CURL_MULTI_HANDLE)
+  ((x) && (x)->magic == CURL_MULTI_HANDLE)
 
 static CURLMcode singlesocket(struct Curl_multi *multi,
                               struct Curl_easy *data);
@@ -105,7 +105,14 @@ static const char * const statename[]={
 /* function pointer called once when switching TO a state */
 typedef void (*init_multistate_func)(struct Curl_easy *data);
 
-static void Curl_init_completed(struct Curl_easy *data)
+/* called when the PERFORM state starts  */
+static void init_perform(struct Curl_easy *data)
+{
+  data->req.chunk = FALSE;
+  Curl_pgrsTime(data, TIMER_PRETRANSFER);
+}
+
+static void init_completed(struct Curl_easy *data)
 {
   /* this is a completed transfer */
 
@@ -136,10 +143,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state
     NULL,              /* DOING */
     NULL,              /* DO_MORE */
     NULL,              /* DO_DONE */
-    NULL,              /* PERFORM */
+    init_perform,      /* PERFORM */
     NULL,              /* TOOFAST */
     NULL,              /* DONE */
-    Curl_init_completed, /* COMPLETED */
+    init_completed,    /* COMPLETED */
     NULL               /* MSGSENT */
   };
 
@@ -190,11 +197,11 @@ static void mstate(struct Curl_easy *data, CURLMstate state
  */
 
 struct Curl_sh_entry {
-  struct curl_hash transfers; /* hash of transfers using this socket */
+  struct Curl_hash transfers; /* hash of transfers using this socket */
   unsigned int action;  /* what combined action READ/WRITE this socket waits
                            for */
-  void *socketp; /* settable by users with curl_multi_assign() */
   unsigned int users; /* number of transfers using this */
+  void *socketp; /* settable by users with curl_multi_assign() */
   unsigned int readers; /* this many transfers want to read */
   unsigned int writers; /* this many transfers want to write */
 };
@@ -204,7 +211,7 @@ struct Curl_sh_entry {
 #define SH_WRITE 2
 
 /* look up a given socket in the socket hash, skip invalid sockets */
-static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
+static struct Curl_sh_entry *sh_getentry(struct Curl_hash *sh,
                                          curl_socket_t s)
 {
   if(s != CURL_SOCKET_BAD) {
@@ -238,7 +245,7 @@ static void trhash_dtor(void *nada)
 
 
 /* make sure this socket is present in the hash for this handle */
-static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
+static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
                                          curl_socket_t s)
 {
   struct Curl_sh_entry *there = sh_getentry(sh, s);
@@ -273,7 +280,7 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
 
 /* delete the given socket + handle from the hash */
 static void sh_delentry(struct Curl_sh_entry *entry,
-                        struct curl_hash *sh, curl_socket_t s)
+                        struct Curl_hash *sh, curl_socket_t s)
 {
   Curl_hash_destroy(&entry->transfers);
 
@@ -325,7 +332,7 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
  * per call."
  *
  */
-static int sh_init(struct curl_hash *hash, int hashsize)
+static int sh_init(struct Curl_hash *hash, int hashsize)
 {
   return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
                         sh_freeentry);
@@ -353,7 +360,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
   if(!multi)
     return NULL;
 
-  multi->type = CURL_MULTI_HANDLE;
+  multi->magic = CURL_MULTI_HANDLE;
 
   if(Curl_mk_dnscache(&multi->hostcache))
     goto error;
@@ -558,7 +565,7 @@ static CURLcode multi_done(struct Curl_easy *data,
   conn->data = data; /* ensure the connection uses this transfer now */
 
   /* Stop the resolver and free its own resources (but not dns_entry yet). */
-  Curl_resolver_kill(conn);
+  Curl_resolver_kill(data);
 
   /* Cleanup possible redirect junk */
   Curl_safefree(data->req.newurl);
@@ -579,14 +586,14 @@ static CURLcode multi_done(struct Curl_easy *data,
 
   /* this calls the protocol-specific function pointer previously set */
   if(conn->handler->done)
-    result = conn->handler->done(conn, status, premature);
+    result = conn->handler->done(data, status, premature);
   else
     result = status;
 
   if(CURLE_ABORTED_BY_CALLBACK != result) {
     /* avoid this if we already aborted by callback to avoid this calling
        another callback */
-    CURLcode rc = Curl_pgrsDone(conn);
+    CURLcode rc = Curl_pgrsDone(data);
     if(!result && rc)
       result = CURLE_ABORTED_BY_CALLBACK;
   }
@@ -690,17 +697,13 @@ static CURLcode multi_done(struct Curl_easy *data,
   return result;
 }
 
-static int close_connect_only(struct connectdata *conn, void *param)
+static int close_connect_only(struct Curl_easy *data,
+                              struct connectdata *conn, void *param)
 {
-  struct Curl_easy *data = param;
-
+  (void)param;
   if(data->state.lastconnect_id != conn->connection_id)
     return 0;
 
-  if(conn->data != data)
-    return 1;
-  conn->data = NULL;
-
   if(!conn->bits.connect_only)
     return 1;
 
@@ -716,7 +719,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
   struct Curl_easy *easy = data;
   bool premature;
   bool easy_owns_conn;
-  struct curl_llist_element *e;
+  struct Curl_llist_element *e;
 
   /* First, make some basic checks that the CURLM handle is a good handle */
   if(!GOOD_MULTI_HANDLE(multi))
@@ -809,7 +812,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
   if(data->state.lastconnect_id != -1) {
     /* Mark any connect-only connection for closure */
     Curl_conncache_foreach(data, data->state.conn_cache,
-                           data, &close_connect_only);
+                           NULL, close_connect_only);
   }
 
 #ifdef USE_LIBPSL
@@ -938,27 +941,30 @@ static int waitproxyconnect_getsock(struct connectdata *conn,
   return GETSOCK_WRITESOCK(0);
 }
 
-static int domore_getsock(struct connectdata *conn,
+static int domore_getsock(struct Curl_easy *data,
+                          struct connectdata *conn,
                           curl_socket_t *socks)
 {
   if(conn && conn->handler->domore_getsock)
-    return conn->handler->domore_getsock(conn, socks);
+    return conn->handler->domore_getsock(data, conn, socks);
   return GETSOCK_BLANK;
 }
 
-static int doing_getsock(struct connectdata *conn,
+static int doing_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
                          curl_socket_t *socks)
 {
   if(conn && conn->handler->doing_getsock)
-    return conn->handler->doing_getsock(conn, socks);
+    return conn->handler->doing_getsock(data, conn, socks);
   return GETSOCK_BLANK;
 }
 
-static int protocol_getsock(struct connectdata *conn,
+static int protocol_getsock(struct Curl_easy *data,
+                            struct connectdata *conn,
                             curl_socket_t *socks)
 {
   if(conn->handler->proto_getsock)
-    return conn->handler->proto_getsock(conn, socks);
+    return conn->handler->proto_getsock(data, conn, socks);
   /* Backup getsock logic. Since there is a live socket in use, we must wait
      for it or it will be removed from watching when the multi_socket API is
      used. */
@@ -971,10 +977,11 @@ static int protocol_getsock(struct connectdata *conn,
 static int multi_getsock(struct Curl_easy *data,
                          curl_socket_t *socks)
 {
+  struct connectdata *conn = data->conn;
   /* The no connection case can happen when this is called from
      curl_multi_remove_handle() => singlesocket() => multi_getsock().
   */
-  if(!data->conn)
+  if(!conn)
     return 0;
 
   if(data->mstate > CURLM_STATE_CONNECT &&
@@ -988,30 +995,30 @@ static int multi_getsock(struct Curl_easy *data,
     return 0;
 
   case CURLM_STATE_WAITRESOLVE:
-    return Curl_resolv_getsock(data->conn, socks);
+    return Curl_resolv_getsock(data, socks);
 
   case CURLM_STATE_PROTOCONNECT:
   case CURLM_STATE_SENDPROTOCONNECT:
-    return protocol_getsock(data->conn, socks);
+    return protocol_getsock(dataconn, socks);
 
   case CURLM_STATE_DO:
   case CURLM_STATE_DOING:
-    return doing_getsock(data->conn, socks);
+    return doing_getsock(dataconn, socks);
 
   case CURLM_STATE_WAITPROXYCONNECT:
-    return waitproxyconnect_getsock(data->conn, socks);
+    return waitproxyconnect_getsock(conn, socks);
 
   case CURLM_STATE_WAITCONNECT:
-    return waitconnect_getsock(data->conn, socks);
+    return waitconnect_getsock(conn, socks);
 
   case CURLM_STATE_DO_MORE:
-    return domore_getsock(data->conn, socks);
+    return domore_getsock(dataconn, socks);
 
   case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
                                to waiting for the same as the *PERFORM
                                states */
   case CURLM_STATE_PERFORM:
-    return Curl_single_getsock(data->conn, socks);
+    return Curl_single_getsock(dataconn, socks);
   }
 
 }
@@ -1067,13 +1074,13 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
 
 #define NUM_POLLS_ON_STACK 10
 
-static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
-                                 struct curl_waitfd extra_fds[],
-                                 unsigned int extra_nfds,
-                                 int timeout_ms,
-                                 int *ret,
-                                 bool extrawait, /* when no socket, wait */
-                                 bool use_wakeup)
+static CURLMcode multi_wait(struct Curl_multi *multi,
+                            struct curl_waitfd extra_fds[],
+                            unsigned int extra_nfds,
+                            int timeout_ms,
+                            int *ret,
+                            bool extrawait, /* when no socket, wait */
+                            bool use_wakeup)
 {
   struct Curl_easy *data;
   curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
@@ -1081,11 +1088,11 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
   unsigned int i;
   unsigned int nfds = 0;
   unsigned int curlfds;
-  bool ufds_malloc = FALSE;
   long timeout_internal;
   int retcode = 0;
   struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
   struct pollfd *ufds = &a_few_on_stack[0];
+  bool ufds_malloc = FALSE;
 
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
@@ -1157,7 +1164,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
     while(data) {
       bitmap = multi_getsock(data, sockbunch);
 
-      for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+      for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
         curl_socket_t s = CURL_SOCKET_BAD;
 
         if(bitmap & GETSOCK_READSOCK(i)) {
@@ -1203,10 +1210,8 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
 #endif
 
   if(nfds) {
-    int pollrc;
     /* wait... */
-    pollrc = Curl_poll(ufds, nfds, timeout_ms);
-
+    int pollrc = Curl_poll(ufds, nfds, timeout_ms);
     if(pollrc > 0) {
       retcode = pollrc;
       /* copy revents results from the poll to the curl_multi_wait poll
@@ -1222,7 +1227,6 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
           mask |= CURL_WAIT_POLLOUT;
         if(r & POLLPRI)
           mask |= CURL_WAIT_POLLPRI;
-
         extra_fds[i].revents = mask;
       }
 
@@ -1284,8 +1288,8 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
                           int timeout_ms,
                           int *ret)
 {
-  return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
-                         FALSE);
+  return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
+                    FALSE);
 }
 
 CURLMcode curl_multi_poll(struct Curl_multi *multi,
@@ -1294,8 +1298,8 @@ CURLMcode curl_multi_poll(struct Curl_multi *multi,
                           int timeout_ms,
                           int *ret)
 {
-  return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
-                         TRUE);
+  return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
+                    TRUE);
 }
 
 CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
@@ -1322,7 +1326,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
 
          The write socket is set to non-blocking, this way this function
          cannot block, making it safe to call even from the same thread
-         that will call Curl_multi_wait(). If swrite() returns that it
+         that will call curl_multi_wait(). If swrite() returns that it
          would block, it's considered successful because it means that
          previous calls to this function will wake up the poll(). */
       if(swrite(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
@@ -1386,18 +1390,6 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
   return rc;
 }
 
-/*
- * do_complete is called when the DO actions are complete.
- *
- * We init chunking and trailer bits to their default values here immediately
- * before receiving any header data for the current request.
- */
-static void do_complete(struct connectdata *conn)
-{
-  conn->data->req.chunk = FALSE;
-  Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
-}
-
 static CURLcode multi_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
@@ -1407,14 +1399,10 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
   DEBUGASSERT(conn->handler);
   DEBUGASSERT(conn->data == data);
 
-  if(conn->handler->do_it) {
+  if(conn->handler->do_it)
     /* generic protocol-specific function pointer set in curl_connect() */
-    result = conn->handler->do_it(conn, done);
+    result = conn->handler->do_it(data, done);
 
-    if(!result && *done)
-      /* do_complete must be called after the protocol-specific DO function */
-      do_complete(conn);
-  }
   return result;
 }
 
@@ -1427,18 +1415,15 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
  * DOING state there's more work to do!
  */
 
-static CURLcode multi_do_more(struct connectdata *conn, int *complete)
+static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   *complete = 0;
 
   if(conn->handler->do_more)
-    result = conn->handler->do_more(conn, complete);
-
-  if(!result && (*complete == 1))
-    /* do_complete must be called after the protocol-specific DO function */
-    do_complete(conn);
+    result = conn->handler->do_more(data, complete);
 
   return result;
 }
@@ -1449,14 +1434,14 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete)
  * protocol layer.
  */
 
-static CURLcode protocol_connecting(struct connectdata *conn,
-                                    bool *done)
+static CURLcode protocol_connecting(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   if(conn && conn->handler->connecting) {
     *done = FALSE;
-    result = conn->handler->connecting(conn, done);
+    result = conn->handler->connecting(data, done);
   }
   else
     *done = TRUE;
@@ -1469,13 +1454,14 @@ static CURLcode protocol_connecting(struct connectdata *conn,
  * until the DOING phase is done on protocol layer.
  */
 
-static CURLcode protocol_doing(struct connectdata *conn, bool *done)
+static CURLcode protocol_doing(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   if(conn && conn->handler->doing) {
     *done = FALSE;
-    result = conn->handler->doing(conn, done);
+    result = conn->handler->doing(data, done);
   }
   else
     *done = TRUE;
@@ -1488,11 +1474,11 @@ static CURLcode protocol_doing(struct connectdata *conn, bool *done)
  * proceed with some action.
  *
  */
-static CURLcode protocol_connect(struct connectdata *conn,
+static CURLcode protocol_connect(struct Curl_easy *data,
                                  bool *protocol_done)
 {
   CURLcode result = CURLE_OK;
-
+  struct connectdata *conn = data->conn;
   DEBUGASSERT(conn);
   DEBUGASSERT(protocol_done);
 
@@ -1513,7 +1499,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
 
   if(!conn->bits.protoconnstart) {
 #ifndef CURL_DISABLE_PROXY
-    result = Curl_proxy_connect(conn, FIRSTSOCKET);
+    result = Curl_proxy_connect(data, FIRSTSOCKET);
     if(result)
       return result;
 
@@ -1531,7 +1517,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
       /* is there a protocol-specific connect() procedure? */
 
       /* Call the protocol-specific connect function */
-      result = conn->handler->connect_it(conn, protocol_done);
+      result = conn->handler->connect_it(data, protocol_done);
     }
     else
       *protocol_done = TRUE;
@@ -1562,7 +1548,7 @@ CURLcode Curl_preconnect(struct Curl_easy *data)
 
 
 static CURLMcode multi_runsingle(struct Curl_multi *multi,
-                                 struct curltime now,
+                                 struct curltime *nowp,
                                  struct Curl_easy *data)
 {
   struct Curl_message *msg = NULL;
@@ -1592,9 +1578,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       process_pending_handles(multi); /* multiplexed */
     }
 
-    if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
+    if(data->mstate > CURLM_STATE_CONNECT &&
        data->mstate < CURLM_STATE_COMPLETED) {
       /* Make sure we set the connection's current owner */
+      DEBUGASSERT(data->conn);
+      if(!data->conn)
+        return CURLM_INTERNAL_ERROR;
       data->conn->data = data;
     }
 
@@ -1603,7 +1592,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
        (data->mstate < CURLM_STATE_COMPLETED)) {
       /* we need to wait for the connect state as only then is the start time
          stored, but we must not check already completed handles */
-      timeout_ms = Curl_timeleft(data, &now,
+      timeout_ms = Curl_timeleft(data, nowp,
                                  (data->mstate <= CURLM_STATE_DO)?
                                  TRUE:FALSE);
 
@@ -1612,25 +1601,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         if(data->mstate == CURLM_STATE_WAITRESOLVE)
           failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
                 " milliseconds",
-                Curl_timediff(now, data->progress.t_startsingle));
+                Curl_timediff(*nowp, data->progress.t_startsingle));
         else if(data->mstate == CURLM_STATE_WAITCONNECT)
           failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
                 " milliseconds",
-                Curl_timediff(now, data->progress.t_startsingle));
+                Curl_timediff(*nowp, data->progress.t_startsingle));
         else {
           struct SingleRequest *k = &data->req;
           if(k->size != -1) {
             failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
                   " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
                   CURL_FORMAT_CURL_OFF_T " bytes received",
-                  Curl_timediff(now, data->progress.t_startsingle),
+                  Curl_timediff(*nowp, data->progress.t_startsingle),
                   k->bytecount, k->size);
           }
           else {
             failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
                   " milliseconds with %" CURL_FORMAT_CURL_OFF_T
                   " bytes received",
-                  Curl_timediff(now, data->progress.t_startsingle),
+                  Curl_timediff(*nowp, data->progress.t_startsingle),
                   k->bytecount);
           }
         }
@@ -1655,7 +1644,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       if(!result) {
         /* after init, go CONNECT */
         multistate(data, CURLM_STATE_CONNECT);
-        Curl_pgrsTime(data, TIMER_STARTOP);
+        *nowp = Curl_pgrsTime(data, TIMER_STARTOP);
         rc = CURLM_CALL_MULTI_PERFORM;
       }
       break;
@@ -1672,7 +1661,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       if(result)
         break;
 
-      Curl_pgrsTime(data, TIMER_STARTSINGLE);
+      *nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
       if(data->set.timeout)
         Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
 
@@ -1740,19 +1729,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         hostname = conn->host.name;
 
       /* check if we have the name resolved by now */
-      dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+      dns = Curl_fetch_addr(data, hostname, (int)conn->port);
 
       if(dns) {
 #ifdef CURLRES_ASYNCH
-        conn->async.dns = dns;
-        conn->async.done = TRUE;
+        data->state.async.dns = dns;
+        data->state.async.done = TRUE;
 #endif
         result = CURLE_OK;
         infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
       }
 
       if(!dns)
-        result = Curl_resolv_check(data->conn, &dns);
+        result = Curl_resolv_check(data, &dns);
 
       /* Update sockets here, because the socket(s) may have been
          closed and the application thus needs to be told, even if it
@@ -1765,7 +1754,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       if(dns) {
         /* Perform the next step in the connection phase, and then move on
            to the WAITCONNECT state */
-        result = Curl_once_resolved(data->conn, &protocol_connected);
+        result = Curl_once_resolved(data, &protocol_connected);
 
         if(result)
           /* if Curl_once_resolved() returns failure, the connection struct
@@ -1799,7 +1788,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_WAITPROXYCONNECT:
       /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
       DEBUGASSERT(data->conn);
-      result = Curl_http_connect(data->conn, &protocol_connected);
+      result = Curl_http_connect(data, &protocol_connected);
 #ifndef CURL_DISABLE_PROXY
       if(data->conn->bits.proxy_connect_closed) {
         rc = CURLM_CALL_MULTI_PERFORM;
@@ -1830,7 +1819,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_WAITCONNECT:
       /* awaiting a completion of an asynch TCP connect */
       DEBUGASSERT(data->conn);
-      result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
+      result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
       if(connected && !result) {
 #ifndef CURL_DISABLE_HTTP
         if(
@@ -1863,7 +1852,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       break;
 
     case CURLM_STATE_SENDPROTOCONNECT:
-      result = protocol_connect(data->conn, &protocol_connected);
+      result = protocol_connect(data, &protocol_connected);
       if(!result && !protocol_connected)
         /* switch to waiting state */
         multistate(data, CURLM_STATE_PROTOCONNECT);
@@ -1882,7 +1871,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 
     case CURLM_STATE_PROTOCONNECT:
       /* protocol-specific connect phase */
-      result = protocol_connecting(data->conn, &protocol_connected);
+      result = protocol_connecting(data, &protocol_connected);
       if(!result && protocol_connected) {
         /* after the connect has completed, go WAITDO or DO */
         multistate(data, CURLM_STATE_DO);
@@ -1919,7 +1908,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
               if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
                 /* skip some states if it is important */
                 multi_done(data, CURLE_OK, FALSE);
-                multistate(data, CURLM_STATE_DONE);
+
+                /* if there's no connection left, skip the DONE state */
+                multistate(data, data->conn ?
+                           CURLM_STATE_DONE : CURLM_STATE_COMPLETED);
                 rc = CURLM_CALL_MULTI_PERFORM;
                 break;
               }
@@ -1955,7 +1947,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           followtype follow = FOLLOW_NONE;
           CURLcode drc;
 
-          drc = Curl_retry_request(data->conn, &newurl);
+          drc = Curl_retry_request(data, &newurl);
           if(drc) {
             /* a failure here pretty much implies an out of memory */
             result = drc;
@@ -2005,7 +1997,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_DOING:
       /* we continue DOING until the DO phase is complete */
       DEBUGASSERT(data->conn);
-      result = protocol_doing(data->conn, &dophase_done);
+      result = protocol_doing(data, &dophase_done);
       if(!result) {
         if(dophase_done) {
           /* after DO, go DO_DONE or DO_MORE */
@@ -2028,7 +2020,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
        * When we are connected, DO MORE and then go DO_DONE
        */
       DEBUGASSERT(data->conn);
-      result = multi_do_more(data->conn, &control);
+      result = multi_do_more(data, &control);
 
       if(!result) {
         if(control) {
@@ -2077,12 +2069,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
       DEBUGASSERT(data->conn);
       /* if both rates are within spec, resume transfer */
-      if(Curl_pgrsUpdate(data->conn))
+      if(Curl_pgrsUpdate(data))
         result = CURLE_ABORTED_BY_CALLBACK;
       else
-        result = Curl_speedcheck(data, now);
+        result = Curl_speedcheck(data, *nowp);
 
-      if(!result) {
+      if(result) {
+        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
+           result != CURLE_HTTP2_STREAM)
+          streamclose(data->conn, "Transfer returned error");
+
+        Curl_posttransfer(data);
+        multi_done(data, result, TRUE);
+      }
+      else {
         send_timeout_ms = 0;
         if(data->set.max_send_speed > 0)
           send_timeout_ms =
@@ -2090,7 +2090,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                    data->progress.ul_limit_size,
                                    data->set.max_send_speed,
                                    data->progress.ul_limit_start,
-                                   now);
+                                   *nowp);
 
         recv_timeout_ms = 0;
         if(data->set.max_recv_speed > 0)
@@ -2099,11 +2099,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                    data->progress.dl_limit_size,
                                    data->set.max_recv_speed,
                                    data->progress.dl_limit_start,
-                                   now);
+                                   *nowp);
 
         if(!send_timeout_ms && !recv_timeout_ms) {
           multistate(data, CURLM_STATE_PERFORM);
-          Curl_ratelimit(data, now);
+          Curl_ratelimit(data, *nowp);
         }
         else if(send_timeout_ms >= recv_timeout_ms)
           Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
@@ -2125,7 +2125,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                                  data->progress.ul_limit_size,
                                                  data->set.max_send_speed,
                                                  data->progress.ul_limit_start,
-                                                 now);
+                                                 *nowp);
 
       /* check if over recv speed */
       recv_timeout_ms = 0;
@@ -2134,10 +2134,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                                  data->progress.dl_limit_size,
                                                  data->set.max_recv_speed,
                                                  data->progress.dl_limit_start,
-                                                 now);
+                                                 *nowp);
 
       if(send_timeout_ms || recv_timeout_ms) {
-        Curl_ratelimit(data, now);
+        Curl_ratelimit(data, *nowp);
         multistate(data, CURLM_STATE_TOOFAST);
         if(send_timeout_ms >= recv_timeout_ms)
           Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
@@ -2154,7 +2154,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
          * condition and the server closed the re-used connection exactly when
          * we wanted to use it, so figure out if that is indeed the case.
          */
-        CURLcode ret = Curl_retry_request(data->conn, &newurl);
+        CURLcode ret = Curl_retry_request(data, &newurl);
         if(!ret)
           retry = (newurl)?TRUE:FALSE;
         else if(!result)
@@ -2169,7 +2169,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       }
       else if((CURLE_HTTP2_STREAM == result) &&
               Curl_h2_http_1_1_error(data->conn)) {
-        CURLcode ret = Curl_retry_request(data->conn, &newurl);
+        CURLcode ret = Curl_retry_request(data, &newurl);
 
         if(!ret) {
           infof(data, "Downgrades to HTTP/1.1!\n");
@@ -2206,7 +2206,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         multi_done(data, result, TRUE);
       }
       else if(done) {
-        followtype follow = FOLLOW_NONE;
 
         /* call this even if the readwrite function returned error */
         Curl_posttransfer(data);
@@ -2214,6 +2213,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         /* When we follow redirects or is set to retry the connection, we must
            to go back to the CONNECT state */
         if(data->req.newurl || retry) {
+          followtype follow = FOLLOW_NONE;
           if(!retry) {
             /* if the URL is a follow-location and not just a retried request
                then figure out the URL here */
@@ -2283,14 +2283,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         /* allow a previously set error code take precedence */
         if(!result)
           result = res;
-
-        /*
-         * If there are other handles on the connection, multi_done won't set
-         * conn to NULL.  In such a case, curl_multi_remove_handle() can
-         * access free'd data, if the connection is free'd and the handle
-         * removed before we perform the processing in CURLM_STATE_COMPLETED
-         */
-        Curl_detach_connnection(data);
       }
 
 #ifndef CURL_DISABLE_FTP
@@ -2360,7 +2352,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         rc = CURLM_CALL_MULTI_PERFORM;
       }
       /* if there's still a connection to use, call the progress function */
-      else if(data->conn && Curl_pgrsUpdate(data->conn)) {
+      else if(data->conn && Curl_pgrsUpdate(data)) {
         /* aborted due to progress callback return code must close the
            connection */
         result = CURLE_ABORTED_BY_CALLBACK;
@@ -2417,7 +2409,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
     SIGPIPE_VARIABLE(pipe_st);
 
     sigpipe_ignore(data, &pipe_st);
-    result = multi_runsingle(multi, now, data);
+    result = multi_runsingle(multi, &now, data);
     sigpipe_restore(&pipe_st);
 
     if(result)
@@ -2461,7 +2453,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     if(multi->in_callback)
       return CURLM_RECURSIVE_API_CALL;
 
-    multi->type = 0; /* not good anymore */
+    multi->magic = 0; /* not good anymore */
 
     /* Firsrt remove all remaining easy handles */
     data = multi->easyp;
@@ -2531,7 +2523,7 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
      !multi->in_callback &&
      Curl_llist_count(&multi->msglist)) {
     /* there is one or more messages in the list */
-    struct curl_llist_element *e;
+    struct Curl_llist_element *e;
 
     /* extract the head of the list to return */
     e = multi->msglist.head;
@@ -2761,15 +2753,15 @@ static CURLMcode add_next_timeout(struct curltime now,
                                   struct Curl_easy *d)
 {
   struct curltime *tv = &d->state.expiretime;
-  struct curl_llist *list = &d->state.timeoutlist;
-  struct curl_llist_element *e;
+  struct Curl_llist *list = &d->state.timeoutlist;
+  struct Curl_llist_element *e;
   struct time_node *node = NULL;
 
   /* move over the timeout list for this specific handle and remove all
      timeouts that are now passed tense and store the next pending
      timeout in *tv */
   for(e = list->head; e;) {
-    struct curl_llist_element *n = e->next;
+    struct Curl_llist_element *n = e->next;
     timediff_t diff;
     node = (struct time_node *)e->ptr;
     diff = Curl_timediff(node->time, now);
@@ -2839,8 +2831,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
          and just move on. */
       ;
     else {
-      struct curl_hash_iterator iter;
-      struct curl_hash_element *he;
+      struct Curl_hash_iterator iter;
+      struct Curl_hash_element *he;
 
       /* the socket can be shared by many transfers, iterate */
       Curl_hash_start_iterate(&entry->transfers, &iter);
@@ -2887,7 +2879,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
       SIGPIPE_VARIABLE(pipe_st);
 
       sigpipe_ignore(data, &pipe_st);
-      result = multi_runsingle(multi, now, data);
+      result = multi_runsingle(multi, &now, data);
       sigpipe_restore(&pipe_st);
 
       if(CURLM_OK >= result) {
@@ -3015,7 +3007,6 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
 }
 
 CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
-
 {
   CURLMcode result;
   if(multi->in_callback)
@@ -3123,8 +3114,8 @@ void Curl_update_timer(struct Curl_multi *multi)
 static void
 multi_deltimeout(struct Curl_easy *data, expire_id eid)
 {
-  struct curl_llist_element *e;
-  struct curl_llist *timeoutlist = &data->state.timeoutlist;
+  struct Curl_llist_element *e;
+  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
   /* find and remove the specific node from the list */
   for(e = timeoutlist->head; e; e = e->next) {
     struct time_node *n = (struct time_node *)e->ptr;
@@ -3147,11 +3138,11 @@ multi_addtimeout(struct Curl_easy *data,
                  struct curltime *stamp,
                  expire_id eid)
 {
-  struct curl_llist_element *e;
+  struct Curl_llist_element *e;
   struct time_node *node;
-  struct curl_llist_element *prev = NULL;
+  struct Curl_llist_element *prev = NULL;
   size_t n;
-  struct curl_llist *timeoutlist = &data->state.timeoutlist;
+  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
 
   node = &data->state.expires[eid];
 
@@ -3233,9 +3224,8 @@ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
 
     /* Since this is an updated time, we must remove the previous entry from
        the splay tree first and then re-add the new value */
-    rc = Curl_splayremovebyaddr(multi->timetree,
-                                &data->state.timenode,
-                                &multi->timetree);
+    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
+                          &multi->timetree);
     if(rc)
       infof(data, "Internal error removing splay node = %d\n", rc);
   }
@@ -3278,12 +3268,11 @@ void Curl_expire_clear(struct Curl_easy *data)
   if(nowp->tv_sec || nowp->tv_usec) {
     /* Since this is an cleared time, we must remove the previous entry from
        the splay tree */
-    struct curl_llist *list = &data->state.timeoutlist;
+    struct Curl_llist *list = &data->state.timeoutlist;
     int rc;
 
-    rc = Curl_splayremovebyaddr(multi->timetree,
-                                &data->state.timenode,
-                                &multi->timetree);
+    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
+                          &multi->timetree);
     if(rc)
       infof(data, "Internal error clearing splay node = %d\n", rc);
 
@@ -3335,21 +3324,23 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
  * When information about a connection has appeared, call this!
  */
 
-void Curl_multiuse_state(struct connectdata *conn,
+void Curl_multiuse_state(struct Curl_easy *data,
                          int bundlestate) /* use BUNDLE_* defines */
 {
+  struct connectdata *conn;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  conn = data->conn;
   DEBUGASSERT(conn);
   DEBUGASSERT(conn->bundle);
-  DEBUGASSERT(conn->data);
-  DEBUGASSERT(conn->data->multi);
 
   conn->bundle->multiuse = bundlestate;
-  process_pending_handles(conn->data->multi);
+  process_pending_handles(data->multi);
 }
 
 static void process_pending_handles(struct Curl_multi *multi)
 {
-  struct curl_llist_element *e = multi->pending.head;
+  struct Curl_llist_element *e = multi->pending.head;
   if(e) {
     struct Curl_easy *data = e->ptr;
 
index 9d73df0..f28c589 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
  *
  ***************************************************************************/
 
+#include "llist.h"
+#include "hash.h"
 #include "conncache.h"
 #include "psl.h"
 #include "socketpair.h"
 
+struct connectdata;
+
 struct Curl_message {
-  struct curl_llist_element list;
+  struct Curl_llist_element list;
   /* the 'CURLMsg' is the part that is visible to the external user */
   struct CURLMsg extmsg;
 };
@@ -67,11 +71,11 @@ typedef enum {
 
 #define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
 
-#if defined(USE_SOCKETPAIR) && !defined(USE_BLOCKING_SOCKETS)
+#if defined(USE_SOCKETPAIR) && !defined(USE_BLOCKING_SOCKETS) &&        \
+  !defined(CURL_DISABLE_SOCKETPAIR)
 #define ENABLE_WAKEUP
 #endif
 
-
 /* value for MAXIMUM CONCURRENT STREAMS upper limit */
 #define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)
 
@@ -79,7 +83,7 @@ typedef enum {
 struct Curl_multi {
   /* First a simple identifier to easier detect if a user mix up
      this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
-  long type;
+  unsigned int magic;
 
   /* We have a doubly-linked list with easy handles */
   struct Curl_easy *easyp;
@@ -89,9 +93,9 @@ struct Curl_multi {
   int num_alive; /* amount of easy handles that are added but have not yet
                     reached COMPLETE state */
 
-  struct curl_llist msglist; /* a list of messages from completed transfers */
+  struct Curl_llist msglist; /* a list of messages from completed transfers */
 
-  struct curl_llist pending; /* Curl_easys that are in the
+  struct Curl_llist pending; /* Curl_easys that are in the
                                 CURLM_STATE_CONNECT_PEND state */
 
   /* callback function and user data pointer for the *socket() API */
@@ -103,7 +107,7 @@ struct Curl_multi {
   void *push_userp;
 
   /* Hostname cache */
-  struct curl_hash hostcache;
+  struct Curl_hash hostcache;
 
 #ifdef USE_LIBPSL
   /* PSL cache. */
@@ -117,7 +121,7 @@ struct Curl_multi {
   /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
      the pluralis form, there can be more than one easy handle waiting on the
      same actual socket) */
-  struct curl_hash sockhash;
+  struct Curl_hash sockhash;
 
   /* Shared connection cache (bundles)*/
   struct conncache conn_cache;
index 7d574df..2fbef53 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -69,7 +69,7 @@ size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
 /* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
 size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
 
-void Curl_multiuse_state(struct connectdata *conn,
+void Curl_multiuse_state(struct Curl_easy *data,
                          int bundlestate); /* use BUNDLE_* defines */
 
 /*
index 1c9da31..13610bb 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 7f56c4b..4938a59 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index a48e67d..30c240b 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 5fb5771..458e8ef 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index abeb659..4a7bde5 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index d50d315..761dab4 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index beec0b3..7693268 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index c6c22cc..8894031 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 782d6a0..4070bbf 100644 (file)
@@ -5,12 +5,12 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2011 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
- * Copyright (C) 2011 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -76,12 +76,14 @@ extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
                         LDAP **ld);
 #endif
 
-static CURLcode ldap_setup_connection(struct connectdata *conn);
-static CURLcode ldap_do(struct connectdata *conn, bool *done);
-static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
-static CURLcode ldap_connect(struct connectdata *conn, bool *done);
-static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
-static CURLcode ldap_disconnect(struct connectdata *conn, bool dead);
+static CURLcode ldap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode ldap_do(struct Curl_easy *data, bool *done);
+static CURLcode ldap_done(struct Curl_easy *data, CURLcode, bool);
+static CURLcode ldap_connect(struct Curl_easy *data, bool *done);
+static CURLcode ldap_connecting(struct Curl_easy *data, bool *done);
+static CURLcode ldap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
 
 static Curl_recv ldap_recv;
 
@@ -107,6 +109,7 @@ const struct Curl_handler Curl_handler_ldap = {
   ZERO_NULL,                            /* connection_check */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
+  CURLPROTO_LDAP,                       /* family */
   PROTOPT_NONE                          /* flags */
 };
 
@@ -132,7 +135,8 @@ const struct Curl_handler Curl_handler_ldaps = {
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   PORT_LDAPS,                           /* defport */
-  CURLPROTO_LDAP,                       /* protocol */
+  CURLPROTO_LDAPS,                      /* protocol */
+  CURLPROTO_LDAP,                       /* family */
   PROTOPT_SSL                           /* flags */
 };
 #endif
@@ -167,11 +171,11 @@ struct ldapreqinfo {
   int nument;
 };
 
-static CURLcode ldap_setup_connection(struct connectdata *conn)
+static CURLcode ldap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   struct ldapconninfo *li;
   LDAPURLDesc *lud;
-  struct Curl_easy *data = conn->data;
   int rc, proto;
   CURLcode status;
 
@@ -184,7 +188,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
         status = CURLE_OUT_OF_MEMORY;
       msg = url_errs[rc];
     }
-    failf(conn->data, "LDAP local: %s", msg);
+    failf(data, "LDAP local: %s", msg);
     return status;
   }
   proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
@@ -203,10 +207,10 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
 static Sockbuf_IO ldapsb_tls;
 #endif
 
-static CURLcode ldap_connect(struct connectdata *conn, bool *done)
+static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  struct Curl_easy *data = conn->data;
   int rc, proto = LDAP_VERSION3;
   char hosturl[1024];
   char *ptr;
@@ -241,7 +245,8 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
 #ifdef USE_SSL
   if(conn->handler->flags & PROTOPT_SSL) {
     CURLcode result;
-    result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
+    result = Curl_ssl_connect_nonblocking(data, conn,
+                                          FIRSTSOCKET, &li->ssldone);
     if(result)
       return result;
   }
@@ -250,10 +255,10 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
+static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  struct Curl_easy *data = conn->data;
   LDAPMessage *msg = NULL;
   struct timeval tv = {0, 1}, *tvp;
   int rc, err;
@@ -263,7 +268,7 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
   if(conn->handler->flags & PROTOPT_SSL) {
     /* Is the SSL handshake complete yet? */
     if(!li->ssldone) {
-      CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
+      CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
                                                      &li->ssldone);
       if(result || !li->ssldone)
         return result;
@@ -355,10 +360,12 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode ldap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
 {
   struct ldapconninfo *li = conn->proto.ldapc;
   (void) dead_connection;
+  (void) data;
 
   if(li) {
     if(li->ld) {
@@ -371,15 +378,15 @@ static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
   return CURLE_OK;
 }
 
-static CURLcode ldap_do(struct connectdata *conn, bool *done)
+static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapreqinfo *lr;
   CURLcode status = CURLE_OK;
   int rc = 0;
   LDAPURLDesc *ludp = NULL;
   int msgid;
-  struct Curl_easy *data = conn->data;
 
   connkeep(conn, "OpenLDAP do");
 
@@ -394,7 +401,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
         status = CURLE_OUT_OF_MEMORY;
       msg = url_errs[rc];
     }
-    failf(conn->data, "LDAP local: %s", msg);
+    failf(data, "LDAP local: %s", msg);
     return status;
   }
 
@@ -410,16 +417,17 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
   if(!lr)
     return CURLE_OUT_OF_MEMORY;
   lr->msgid = msgid;
-  data->req.protop = lr;
+  data->req.p.ldap = lr;
   Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
   *done = TRUE;
   return CURLE_OK;
 }
 
-static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
+static CURLcode ldap_done(struct Curl_easy *data, CURLcode res,
                           bool premature)
 {
-  struct ldapreqinfo *lr = conn->data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct ldapreqinfo *lr = data->req.p.ldap;
 
   (void)res;
   (void)premature;
@@ -431,19 +439,19 @@ static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
       ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
       lr->msgid = 0;
     }
-    conn->data->req.protop = NULL;
+    data->req.p.ldap = NULL;
     free(lr);
   }
 
   return CURLE_OK;
 }
 
-static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
+static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
                          size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  struct Curl_easy *data = conn->data;
-  struct ldapreqinfo *lr = data->req.protop;
+  struct ldapreqinfo *lr = data->req.p.ldap;
   int rc, ret;
   LDAPMessage *msg = NULL;
   LDAPMessage *ent;
@@ -510,20 +518,20 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
       *err = CURLE_RECV_ERROR;
       return -1;
     }
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
     if(writeerr) {
       *err = writeerr;
       return -1;
     }
 
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
                                  bv.bv_len);
     if(writeerr) {
       *err = writeerr;
       return -1;
     }
 
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
     if(writeerr) {
       *err = writeerr;
       return -1;
@@ -544,18 +552,18 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
         binary = 0;
 
       if(bvals == NULL) {
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
                                      bv.bv_len);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":\n", 2);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":\n", 2);
         if(writeerr) {
           *err = writeerr;
           return -1;
@@ -566,20 +574,20 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
 
       for(i = 0; bvals[i].bv_val != NULL; i++) {
         int binval = 0;
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
 
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
                                      bv.bv_len);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
 
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":", 1);
         if(writeerr) {
           *err = writeerr;
           return -1;
@@ -617,7 +625,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
             *err = error;
             return -1;
           }
-          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
+          writeerr = Curl_client_write(data, CLIENTWRITE_BODY,
                                        (char *)": ", 2);
           if(writeerr) {
             *err = writeerr;
@@ -626,7 +634,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
 
           data->req.bytecount += 2;
           if(val_b64_sz > 0) {
-            writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+            writeerr = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
                                          val_b64_sz);
             if(writeerr) {
               *err = writeerr;
@@ -637,13 +645,13 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
           }
         }
         else {
-          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
+          writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)" ", 1);
           if(writeerr) {
             *err = writeerr;
             return -1;
           }
 
-          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
+          writeerr = Curl_client_write(data, CLIENTWRITE_BODY, bvals[i].bv_val,
                                        bvals[i].bv_len);
           if(writeerr) {
             *err = writeerr;
@@ -652,7 +660,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
 
           data->req.bytecount += bvals[i].bv_len + 1;
         }
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
         if(writeerr) {
           *err = writeerr;
           return -1;
@@ -661,14 +669,14 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
         data->req.bytecount++;
       }
       ber_memfree(bvals);
-      writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+      writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
       if(writeerr) {
         *err = writeerr;
         return -1;
       }
       data->req.bytecount++;
     }
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
     if(writeerr) {
       *err = writeerr;
       return -1;
@@ -722,7 +730,7 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
   ber_slen_t ret;
   CURLcode err = CURLE_RECV_ERROR;
 
-  ret = (li->recv)(conn, FIRSTSOCKET, buf, len, &err);
+  ret = (li->recv)(conn->data, FIRSTSOCKET, buf, len, &err);
   if(ret < 0 && err == CURLE_AGAIN) {
     SET_SOCKERRNO(EWOULDBLOCK);
   }
@@ -737,7 +745,7 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
   ber_slen_t ret;
   CURLcode err = CURLE_SEND_ERROR;
 
-  ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err);
+  ret = (li->send)(conn->data, FIRSTSOCKET, buf, len, &err);
   if(ret < 0 && err == CURLE_AGAIN) {
     SET_SOCKERRNO(EWOULDBLOCK);
   }
index 4c7a40c..3c38f2c 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -275,48 +275,21 @@ enum assume {
   DATE_TIME
 };
 
-/* this is a clone of 'struct tm' but with all fields we don't need or use
-   cut out */
-struct my_tm {
-  int tm_sec;
-  int tm_min;
-  int tm_hour;
-  int tm_mday;
-  int tm_mon;
-  int tm_year; /* full year */
-};
-
-/* struct tm to time since epoch in GMT time zone.
- * This is similar to the standard mktime function but for GMT only, and
- * doesn't suffer from the various bugs and portability problems that
- * some systems' implementations have.
- *
- * Returns 0 on success, otherwise non-zero.
+/*
+ * time2epoch: time stamp to seconds since epoch in GMT time zone.  Similar to
+ * mktime but for GMT only.
  */
-static void my_timegm(struct my_tm *tm, time_t *t)
+static time_t time2epoch(int sec, int min, int hour,
+                         int mday, int mon, int year)
 {
   static const int month_days_cumulative [12] =
     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-  int month, year, leap_days;
-
-  year = tm->tm_year;
-  month = tm->tm_mon;
-  if(month < 0) {
-    year += (11 - month) / 12;
-    month = 11 - (11 - month) % 12;
-  }
-  else if(month >= 12) {
-    year -= month / 12;
-    month = month % 12;
-  }
-
-  leap_days = year - (tm->tm_mon <= 1);
+  int leap_days = year - (mon <= 1);
   leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
                - (1969 / 4) + (1969 / 100) - (1969 / 400));
-
-  *t = ((((time_t) (year - 1970) * 365
-          + leap_days + month_days_cumulative[month] + tm->tm_mday - 1) * 24
-         + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
+  return ((((time_t) (year - 1970) * 365
+            + leap_days + month_days_cumulative[mon] + mday - 1) * 24
+           + hour) * 60 + min) * 60 + sec;
 }
 
 /*
@@ -341,7 +314,6 @@ static int parsedate(const char *date, time_t *output)
   int secnum = -1;
   int yearnum = -1;
   int tzoff = -1;
-  struct my_tm tm;
   enum assume dignext = DATE_MDAY;
   const char *indate = date; /* save the original pointer */
   int part = 0; /* max 6 parts */
@@ -533,18 +505,11 @@ static int parsedate(const char *date, time_t *output)
      (hournum > 23) || (minnum > 59) || (secnum > 60))
     return PARSEDATE_FAIL; /* clearly an illegal date */
 
-  tm.tm_sec = secnum;
-  tm.tm_min = minnum;
-  tm.tm_hour = hournum;
-  tm.tm_mday = mdaynum;
-  tm.tm_mon = monnum;
-  tm.tm_year = yearnum;
-
-  /* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on
+  /* time2epoch() returns a time_t. time_t is often 32 bits, sometimes even on
      architectures that feature 64 bit 'long' but ultimately time_t is the
      correct data type to use.
   */
-  my_timegm(&tm, &t);
+  t = time2epoch(secnum, minnum, hournum, mdaynum, monnum, yearnum);
 
   /* Add the time zone diff between local time zone and GMT. */
   if(tzoff == -1)
index 8c7ae94..a99faf9 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 3143315..4811739 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 
 /* Returns timeout in ms. 0 or negative number means the timeout has already
    triggered */
-timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
+timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
+                                 struct pingpong *pp, bool disconnecting)
 {
-  struct connectdata *conn = pp->conn;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   timediff_t timeout_ms; /* in milliseconds */
   timediff_t response_time = (data->set.server_response_timeout)?
     data->set.server_response_timeout: pp->response_time;
@@ -77,15 +77,15 @@ timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
 /*
  * Curl_pp_statemach()
  */
-CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
+CURLcode Curl_pp_statemach(struct Curl_easy *data,
+                           struct pingpong *pp, bool block,
                            bool disconnecting)
 {
-  struct connectdata *conn = pp->conn;
+  struct connectdata *conn = data->conn;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   int rc;
   timediff_t interval_ms;
-  timediff_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
-  struct Curl_easy *data = conn->data;
+  timediff_t timeout_ms = Curl_pp_state_timeout(data, pp, disconnecting);
   CURLcode result = CURLE_OK;
 
   if(timeout_ms <= 0) {
@@ -117,7 +117,7 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
 
   if(block) {
     /* if we didn't wait, we don't have to spend time on this now */
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
       result = Curl_speedcheck(data, Curl_now());
@@ -131,22 +131,26 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
     result = CURLE_OUT_OF_MEMORY;
   }
   else if(rc)
-    result = pp->statemach_act(conn);
+    result = pp->statemachine(data, data->conn);
 
   return result;
 }
 
 /* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct pingpong *pp)
+void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp)
 {
-  struct connectdata *conn = pp->conn;
+  DEBUGASSERT(data);
   pp->nread_resp = 0;
-  pp->linestart_resp = conn->data->state.buffer;
+  pp->linestart_resp = data->state.buffer;
   pp->pending_resp = TRUE;
   pp->response = Curl_now(); /* start response time-out now! */
 }
 
-
+/* setup for the coming transfer */
+void Curl_pp_setup(struct pingpong *pp)
+{
+  Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
+}
 
 /***********************************************************************
  *
@@ -158,17 +162,16 @@ void Curl_pp_init(struct pingpong *pp)
  *
  * made to never block
  */
-CURLcode Curl_pp_vsendf(struct pingpong *pp,
+CURLcode Curl_pp_vsendf(struct Curl_easy *data,
+                        struct pingpong *pp,
                         const char *fmt,
                         va_list args)
 {
-  ssize_t bytes_written;
+  ssize_t bytes_written = 0;
   size_t write_len;
-  char *fmt_crlf;
   char *s;
   CURLcode result;
-  struct connectdata *conn = pp->conn;
-  struct Curl_easy *data;
+  struct connectdata *conn = data->conn;
 
 #ifdef HAVE_GSSAPI
   enum protection_level data_sec;
@@ -182,47 +185,39 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
     /* can't send without a connection! */
     return CURLE_SEND_ERROR;
 
-  data = conn->data;
-
-  fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */
-  if(!fmt_crlf)
-    return CURLE_OUT_OF_MEMORY;
-
-  s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */
-  free(fmt_crlf);
-  if(!s)
-    return CURLE_OUT_OF_MEMORY;
+  Curl_dyn_reset(&pp->sendbuf);
+  result = Curl_dyn_vaddf(&pp->sendbuf, fmt, args);
+  if(result)
+    return result;
 
-  bytes_written = 0;
-  write_len = strlen(s);
+  /* append CRLF */
+  result = Curl_dyn_addn(&pp->sendbuf, "\r\n", 2);
+  if(result)
+    return result;
 
-  Curl_pp_init(pp);
+  write_len = Curl_dyn_len(&pp->sendbuf);
+  s = Curl_dyn_ptr(&pp->sendbuf);
+  Curl_pp_init(data, pp);
 
   result = Curl_convert_to_network(data, s, write_len);
   /* Curl_convert_to_network calls failf if unsuccessful */
-  if(result) {
-    free(s);
+  if(result)
     return result;
-  }
 
 #ifdef HAVE_GSSAPI
   conn->data_prot = PROT_CMD;
 #endif
-  result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len,
-                     &bytes_written);
+  result = Curl_write(data, conn->sock[FIRSTSOCKET], s, write_len,
+                      &bytes_written);
+  if(result)
+    return result;
 #ifdef HAVE_GSSAPI
   data_sec = conn->data_prot;
   DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
   conn->data_prot = data_sec;
 #endif
 
-  if(result) {
-    free(s);
-    return result;
-  }
-
-  if(conn->data->set.verbose)
-    Curl_debug(conn->data, CURLINFO_HEADER_OUT, s, (size_t)bytes_written);
+  Curl_debug(data, CURLINFO_HEADER_OUT, s, (size_t)bytes_written);
 
   if(bytes_written != (ssize_t)write_len) {
     /* the whole chunk was not sent, keep it around and adjust sizes */
@@ -231,7 +226,6 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
     pp->sendleft = write_len - bytes_written;
   }
   else {
-    free(s);
     pp->sendthis = NULL;
     pp->sendleft = pp->sendsize = 0;
     pp->response = Curl_now();
@@ -251,14 +245,14 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
  *
  * made to never block
  */
-CURLcode Curl_pp_sendf(struct pingpong *pp,
+CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
                        const char *fmt, ...)
 {
   CURLcode result;
   va_list ap;
   va_start(ap, fmt);
 
-  result = Curl_pp_vsendf(pp, fmt, ap);
+  result = Curl_pp_vsendf(data, pp, fmt, ap);
 
   va_end(ap);
 
@@ -270,7 +264,8 @@ CURLcode Curl_pp_sendf(struct pingpong *pp,
  *
  * Reads a piece of a server response.
  */
-CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+CURLcode Curl_pp_readresp(struct Curl_easy *data,
+                          curl_socket_t sockfd,
                           struct pingpong *pp,
                           int *code, /* return the server code if done */
                           size_t *size) /* size of the response */
@@ -279,8 +274,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
   bool keepon = TRUE;
   ssize_t gotbytes;
   char *ptr;
-  struct connectdata *conn = pp->conn;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   char * const buf = data->state.buffer;
   CURLcode result = CURLE_OK;
 
@@ -320,7 +314,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
 #endif
       DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <=
                   (buf + data->set.buffer_size + 1));
-      result = Curl_read(conn, sockfd, ptr,
+      result = Curl_read(data, sockfd, ptr,
                          data->set.buffer_size - pp->nread_resp,
                          &gotbytes);
 #ifdef HAVE_GSSAPI
@@ -368,21 +362,20 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
 #ifdef HAVE_GSSAPI
           if(!conn->sec_complete)
 #endif
-            if(data->set.verbose)
-              Curl_debug(data, CURLINFO_HEADER_IN,
-                         pp->linestart_resp, (size_t)perline);
+            Curl_debug(data, CURLINFO_HEADER_IN,
+                       pp->linestart_resp, (size_t)perline);
 
           /*
            * We pass all response-lines to the callback function registered
            * for "headers". The response lines can be seen as a kind of
            * headers.
            */
-          result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+          result = Curl_client_write(data, CLIENTWRITE_HEADER,
                                      pp->linestart_resp, perline);
           if(result)
             return result;
 
-          if(pp->endofresp(conn, pp->linestart_resp, perline, code)) {
+          if(pp->endofresp(data, conn, pp->linestart_resp, perline, code)) {
             /* This is the end of the last line, copy the last line to the
                start of the buffer and null-terminate, for old times sake */
             size_t n = ptr - pp->linestart_resp;
@@ -462,10 +455,10 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
   return result;
 }
 
-int Curl_pp_getsock(struct pingpong *pp,
-                    curl_socket_t *socks)
+int Curl_pp_getsock(struct Curl_easy *data,
+                    struct pingpong *pp, curl_socket_t *socks)
 {
-  struct connectdata *conn = pp->conn;
+  struct connectdata *conn = data->conn;
   socks[0] = conn->sock[FIRSTSOCKET];
 
   if(pp->sendleft) {
@@ -477,13 +470,14 @@ int Curl_pp_getsock(struct pingpong *pp,
   return GETSOCK_READSOCK(0);
 }
 
-CURLcode Curl_pp_flushsend(struct pingpong *pp)
+CURLcode Curl_pp_flushsend(struct Curl_easy *data,
+                           struct pingpong *pp)
 {
   /* we have a piece of a command still left to send */
-  struct connectdata *conn = pp->conn;
+  struct connectdata *conn = data->conn;
   ssize_t written;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize -
+  CURLcode result = Curl_write(data, sock, pp->sendthis + pp->sendsize -
                                pp->sendleft, pp->sendleft, &written);
   if(result)
     return result;
@@ -493,7 +487,6 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp)
     pp->sendleft -= written;
   }
   else {
-    free(pp->sendthis);
     pp->sendthis = NULL;
     pp->sendleft = pp->sendsize = 0;
     pp->response = Curl_now();
@@ -503,15 +496,15 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp)
 
 CURLcode Curl_pp_disconnect(struct pingpong *pp)
 {
-  free(pp->cache);
-  pp->cache = NULL;
+  Curl_dyn_free(&pp->sendbuf);
+  Curl_safefree(pp->cache);
   return CURLE_OK;
 }
 
 bool Curl_pp_moredata(struct pingpong *pp)
 {
   return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ?
-         TRUE : FALSE;
+    TRUE : FALSE;
 }
 
 #endif
index e874799..4f7d7ea 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -62,33 +62,42 @@ struct pingpong {
                                off, used to time-out response reading */
   timediff_t response_time; /* When no timeout is given, this is the amount of
                                milliseconds we await for a server response. */
-  struct connectdata *conn; /* points to the connectdata struct that this
-                               belongs to */
+  struct dynbuf sendbuf;
 
   /* Function pointers the protocols MUST implement and provide for the
      pingpong layer to function */
 
-  CURLcode (*statemach_act)(struct connectdata *conn);
-
-  bool (*endofresp)(struct connectdata *conn, char *ptr, size_t len,
-                    int *code);
+  CURLcode (*statemachine)(struct Curl_easy *data, struct connectdata *conn);
+  bool (*endofresp)(struct Curl_easy *data, struct connectdata *conn,
+                    char *ptr, size_t len, int *code);
 };
 
+#define PINGPONG_SETUP(pp,s,e)                   \
+  do {                                           \
+    pp->response_time = RESP_TIMEOUT;            \
+    pp->statemachine = s;                        \
+    pp->endofresp = e;                           \
+  } while(0)
+
 /*
  * Curl_pp_statemach()
  *
  * called repeatedly until done. Set 'wait' to make it wait a while on the
  * socket if there's no traffic.
  */
-CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
-                           bool disconnecting);
+CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
+                           bool block, bool disconnecting);
 
 /* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct pingpong *pp);
+void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp);
+
+/* setup for the transfer */
+void Curl_pp_setup(struct pingpong *pp);
 
 /* Returns timeout in ms. 0 or negative number means the timeout has already
    triggered */
-timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
+timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
+                                 struct pingpong *pp, bool disconnecting);
 
 
 /***********************************************************************
@@ -101,7 +110,8 @@ timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
  *
  * made to never block
  */
-CURLcode Curl_pp_sendf(struct pingpong *pp,
+CURLcode Curl_pp_sendf(struct Curl_easy *data,
+                       struct pingpong *pp,
                        const char *fmt, ...);
 
 /***********************************************************************
@@ -114,7 +124,8 @@ CURLcode Curl_pp_sendf(struct pingpong *pp,
  *
  * made to never block
  */
-CURLcode Curl_pp_vsendf(struct pingpong *pp,
+CURLcode Curl_pp_vsendf(struct Curl_easy *data,
+                        struct pingpong *pp,
                         const char *fmt,
                         va_list args);
 
@@ -123,18 +134,21 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
  *
  * Reads a piece of a server response.
  */
-CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+CURLcode Curl_pp_readresp(struct Curl_easy *data,
+                          curl_socket_t sockfd,
                           struct pingpong *pp,
                           int *code, /* return the server code if done */
                           size_t *size); /* size of the response */
 
 
-CURLcode Curl_pp_flushsend(struct pingpong *pp);
+CURLcode Curl_pp_flushsend(struct Curl_easy *data,
+                           struct pingpong *pp);
 
 /* call this when a pingpong connection is disconnected */
 CURLcode Curl_pp_disconnect(struct pingpong *pp);
 
-int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks);
+int Curl_pp_getsock(struct Curl_easy *data, struct pingpong *pp,
+                    curl_socket_t *socks);
 
 
 /***********************************************************************
index 9ff5c78..0ed3d3e 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "memdebug.h"
 
 /* Local API functions */
-static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
-static CURLcode pop3_do(struct connectdata *conn, bool *done);
-static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+static CURLcode pop3_regular_transfer(struct Curl_easy *data, bool *done);
+static CURLcode pop3_do(struct Curl_easy *data, bool *done);
+static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
                           bool premature);
-static CURLcode pop3_connect(struct connectdata *conn, bool *done);
-static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
-static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
-static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks);
-static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
-static CURLcode pop3_setup_connection(struct connectdata *conn);
+static CURLcode pop3_connect(struct Curl_easy *data, bool *done);
+static CURLcode pop3_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done);
+static int pop3_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
+static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode pop3_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
 static CURLcode pop3_parse_url_options(struct connectdata *conn);
-static CURLcode pop3_parse_url_path(struct connectdata *conn);
-static CURLcode pop3_parse_custom_request(struct connectdata *conn);
-static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech,
+static CURLcode pop3_parse_url_path(struct Curl_easy *data);
+static CURLcode pop3_parse_custom_request(struct Curl_easy *data);
+static CURLcode pop3_perform_auth(struct Curl_easy *data,
+                                  struct connectdata *conn, const char *mech,
                                   const char *initresp);
-static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp);
+static CURLcode pop3_continue_auth(struct Curl_easy *data,
+                                   struct connectdata *conn, const char *resp);
 static void pop3_get_message(char *buffer, char **outptr);
 
 /*
@@ -128,6 +133,7 @@ const struct Curl_handler Curl_handler_pop3 = {
   ZERO_NULL,                        /* connection_check */
   PORT_POP3,                        /* defport */
   CURLPROTO_POP3,                   /* protocol */
+  CURLPROTO_POP3,                   /* family */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
   PROTOPT_URLOPTIONS
 };
@@ -155,6 +161,7 @@ const struct Curl_handler Curl_handler_pop3s = {
   ZERO_NULL,                        /* connection_check */
   PORT_POP3S,                       /* defport */
   CURLPROTO_POP3S,                  /* protocol */
+  CURLPROTO_POP3,                   /* family */
   PROTOPT_CLOSEACTION | PROTOPT_SSL
   | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
 };
@@ -193,10 +200,11 @@ static void pop3_to_pop3s(struct connectdata *conn)
  * capabilities from the CAPA response including the supported authentication
  * types and allowed SASL mechanisms.
  */
-static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
-                           int *resp)
+static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                           char *line, size_t len, int *resp)
 {
   struct pop3_conn *pop3c = &conn->proto.pop3c;
+  (void)data;
 
   /* Do we have an error response? */
   if(len >= 4 && !memcmp("-ERR", line, 4)) {
@@ -277,9 +285,9 @@ static void pop3_get_message(char *buffer, char **outptr)
  *
  * This is the ONLY way to change POP3 state!
  */
-static void state(struct connectdata *conn, pop3state newstate)
+static void state(struct Curl_easy *data, pop3state newstate)
 {
-  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pop3_conn *pop3c = &data->conn->proto.pop3c;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
   static const char * const names[] = {
@@ -298,7 +306,7 @@ static void state(struct connectdata *conn, pop3state newstate)
   };
 
   if(pop3c->state != newstate)
-    infof(conn->data, "POP3 %p state change from %s to %s\n",
+    infof(data, "POP3 %p state change from %s to %s\n",
           (void *)pop3c, names[pop3c->state], names[newstate]);
 #endif
 
@@ -312,7 +320,8 @@ static void state(struct connectdata *conn, pop3state newstate)
  * Sends the CAPA command in order to obtain a list of server side supported
  * capabilities.
  */
-static CURLcode pop3_perform_capa(struct connectdata *conn)
+static CURLcode pop3_perform_capa(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
@@ -322,10 +331,10 @@ static CURLcode pop3_perform_capa(struct connectdata *conn)
   pop3c->tls_supported = FALSE;           /* Clear the TLS capability */
 
   /* Send the CAPA command */
-  result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
+  result = Curl_pp_sendf(data, &pop3c->pp, "%s", "CAPA");
 
   if(!result)
-    state(conn, POP3_CAPA);
+    state(data, POP3_CAPA);
 
   return result;
 }
@@ -336,13 +345,14 @@ static CURLcode pop3_perform_capa(struct connectdata *conn)
  *
  * Sends the STLS command to start the upgrade to TLS.
  */
-static CURLcode pop3_perform_starttls(struct connectdata *conn)
+static CURLcode pop3_perform_starttls(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   /* Send the STLS command */
-  CURLcode result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "STLS");
 
   if(!result)
-    state(conn, POP3_STARTTLS);
+    state(data, POP3_STARTTLS);
 
   return result;
 }
@@ -353,20 +363,21 @@ static CURLcode pop3_perform_starttls(struct connectdata *conn)
  *
  * Performs the upgrade to TLS.
  */
-static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
+static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
+                                         struct connectdata *conn)
 {
   /* Start the SSL connection */
   struct pop3_conn *pop3c = &conn->proto.pop3c;
-  CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
+  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
                                                  &pop3c->ssldone);
 
   if(!result) {
     if(pop3c->state != POP3_UPGRADETLS)
-      state(conn, POP3_UPGRADETLS);
+      state(data, POP3_UPGRADETLS);
 
     if(pop3c->ssldone) {
       pop3_to_pop3s(conn);
-      result = pop3_perform_capa(conn);
+      result = pop3_perform_capa(data, conn);
     }
   }
 
@@ -379,23 +390,24 @@ static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
  *
  * Sends a clear text USER command to authenticate with.
  */
-static CURLcode pop3_perform_user(struct connectdata *conn)
+static CURLcode pop3_perform_user(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
 
   /* Check we have a username and password to authenticate with and end the
      connect phase if we don't */
   if(!conn->bits.user_passwd) {
-    state(conn, POP3_STOP);
+    state(data, POP3_STOP);
 
     return result;
   }
 
   /* Send the USER command */
-  result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
+  result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "USER %s",
                          conn->user ? conn->user : "");
   if(!result)
-    state(conn, POP3_USER);
+    state(data, POP3_USER);
 
   return result;
 }
@@ -407,7 +419,8 @@ static CURLcode pop3_perform_user(struct connectdata *conn)
  *
  * Sends an APOP command to authenticate with.
  */
-static CURLcode pop3_perform_apop(struct connectdata *conn)
+static CURLcode pop3_perform_apop(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
@@ -419,7 +432,7 @@ static CURLcode pop3_perform_apop(struct connectdata *conn)
   /* Check we have a username and password to authenticate with and end the
      connect phase if we don't */
   if(!conn->bits.user_passwd) {
-    state(conn, POP3_STOP);
+    state(data, POP3_STOP);
 
     return result;
   }
@@ -442,10 +455,10 @@ static CURLcode pop3_perform_apop(struct connectdata *conn)
   for(i = 0; i < MD5_DIGEST_LEN; i++)
     msnprintf(&secret[2 * i], 3, "%02x", digest[i]);
 
-  result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
+  result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret);
 
   if(!result)
-    state(conn, POP3_APOP);
+    state(data, POP3_APOP);
 
   return result;
 }
@@ -458,7 +471,8 @@ static CURLcode pop3_perform_apop(struct connectdata *conn)
  * Sends an AUTH command allowing the client to login with the given SASL
  * authentication mechanism.
  */
-static CURLcode pop3_perform_auth(struct connectdata *conn,
+static CURLcode pop3_perform_auth(struct Curl_easy *data,
+                                  struct connectdata *conn,
                                   const char *mech,
                                   const char *initresp)
 {
@@ -467,11 +481,11 @@ static CURLcode pop3_perform_auth(struct connectdata *conn,
 
   if(initresp) {                                  /* AUTH <mech> ...<crlf> */
     /* Send the AUTH command with the initial response */
-    result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
+    result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, initresp);
   }
   else {
     /* Send the AUTH command */
-    result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
+    result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s", mech);
   }
 
   return result;
@@ -483,12 +497,13 @@ static CURLcode pop3_perform_auth(struct connectdata *conn,
  *
  * Sends SASL continuation data or cancellation.
  */
-static CURLcode pop3_continue_auth(struct connectdata *conn,
+static CURLcode pop3_continue_auth(struct Curl_easy *data,
+                                   struct connectdata *conn,
                                    const char *resp)
 {
   struct pop3_conn *pop3c = &conn->proto.pop3c;
 
-  return Curl_pp_sendf(&pop3c->pp, "%s", resp);
+  return Curl_pp_sendf(data, &pop3c->pp, "%s", resp);
 }
 
 /***********************************************************************
@@ -499,7 +514,8 @@ static CURLcode pop3_continue_auth(struct connectdata *conn,
  * authentication mechanism, falling back to APOP and clear text should a
  * common mechanism not be available between the client and server.
  */
-static CURLcode pop3_perform_authentication(struct connectdata *conn)
+static CURLcode pop3_perform_authentication(struct Curl_easy *data,
+                                            struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
@@ -508,32 +524,32 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)
   /* Check we have enough data to authenticate with and end the
      connect phase if we don't */
   if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
-    state(conn, POP3_STOP);
+    state(data, POP3_STOP);
     return result;
   }
 
   if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
     /* Calculate the SASL login details */
-    result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress);
+    result = Curl_sasl_start(&pop3c->sasl, data, conn, FALSE, &progress);
 
     if(!result)
       if(progress == SASL_INPROGRESS)
-        state(conn, POP3_AUTH);
+        state(data, POP3_AUTH);
   }
 
   if(!result && progress == SASL_IDLE) {
 #ifndef CURL_DISABLE_CRYPTO_AUTH
     if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
       /* Perform APOP authentication */
-      result = pop3_perform_apop(conn);
+      result = pop3_perform_apop(data, conn);
     else
 #endif
     if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
       /* Perform clear text authentication */
-      result = pop3_perform_user(conn);
+      result = pop3_perform_user(data, conn);
     else {
       /* Other mechanisms not supported */
-      infof(conn->data, "No known authentication mechanisms supported!\n");
+      infof(data, "No known authentication mechanisms supported!\n");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -547,15 +563,15 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)
  *
  * Sends a POP3 based command.
  */
-static CURLcode pop3_perform_command(struct connectdata *conn)
+static CURLcode pop3_perform_command(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct POP3 *pop3 = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct POP3 *pop3 = data->req.p.pop3;
   const char *command = NULL;
 
   /* Calculate the default command */
-  if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
+  if(pop3->id[0] == '\0' || data->set.ftp_list_only) {
     command = "LIST";
 
     if(pop3->id[0] != '\0')
@@ -567,16 +583,16 @@ static CURLcode pop3_perform_command(struct connectdata *conn)
 
   /* Send the command */
   if(pop3->id[0] != '\0')
-    result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
+    result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s %s",
                            (pop3->custom && pop3->custom[0] != '\0' ?
                             pop3->custom : command), pop3->id);
   else
-    result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
+    result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s",
                            (pop3->custom && pop3->custom[0] != '\0' ?
                             pop3->custom : command));
 
   if(!result)
-    state(conn, POP3_COMMAND);
+    state(data, POP3_COMMAND);
 
   return result;
 }
@@ -587,24 +603,25 @@ static CURLcode pop3_perform_command(struct connectdata *conn)
  *
  * Performs the quit action prior to sclose() be called.
  */
-static CURLcode pop3_perform_quit(struct connectdata *conn)
+static CURLcode pop3_perform_quit(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   /* Send the QUIT command */
-  CURLcode result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "QUIT");
 
   if(!result)
-    state(conn, POP3_QUIT);
+    state(data, POP3_QUIT);
 
   return result;
 }
 
 /* For the initial server greeting */
-static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
+static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data,
                                             int pop3code,
                                             pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   const char *line = data->state.buffer;
   size_t len = strlen(line);
@@ -652,18 +669,18 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
       }
     }
 
-    result = pop3_perform_capa(conn);
+    result = pop3_perform_capa(data, conn);
   }
 
   return result;
 }
 
 /* For CAPA responses */
-static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
+static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   const char *line = data->state.buffer;
   size_t len = strlen(line);
@@ -726,36 +743,35 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
       /* We don't have a SSL/TLS connection yet, but SSL is requested */
       if(pop3c->tls_supported)
         /* Switch to TLS connection now */
-        result = pop3_perform_starttls(conn);
+        result = pop3_perform_starttls(data, conn);
       else if(data->set.use_ssl == CURLUSESSL_TRY)
         /* Fallback and carry on with authentication */
-        result = pop3_perform_authentication(conn);
+        result = pop3_perform_authentication(data, conn);
       else {
         failf(data, "STLS not supported.");
         result = CURLE_USE_SSL_FAILED;
       }
     }
     else
-      result = pop3_perform_authentication(conn);
+      result = pop3_perform_authentication(data, conn);
   }
   else {
     /* Clear text is supported when CAPA isn't recognised */
     pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
 
-    result = pop3_perform_authentication(conn);
+    result = pop3_perform_authentication(data, conn);
   }
 
   return result;
 }
 
 /* For STARTTLS responses */
-static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
+static CURLcode pop3_state_starttls_resp(struct Curl_easy *data,
+                                         struct connectdata *conn,
                                          int pop3code,
                                          pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(pop3code != '+') {
@@ -764,42 +780,42 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
       result = CURLE_USE_SSL_FAILED;
     }
     else
-      result = pop3_perform_authentication(conn);
+      result = pop3_perform_authentication(data, conn);
   }
   else
-    result = pop3_perform_upgrade_tls(conn);
+    result = pop3_perform_upgrade_tls(data, conn);
 
   return result;
 }
 
 /* For SASL authentication responses */
-static CURLcode pop3_state_auth_resp(struct connectdata *conn,
+static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
                                      int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   saslprogress progress;
 
   (void)instate; /* no use for this yet */
 
-  result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress);
+  result = Curl_sasl_continue(&pop3c->sasl, data, conn, pop3code, &progress);
   if(!result)
     switch(progress) {
     case SASL_DONE:
-      state(conn, POP3_STOP);  /* Authenticated */
+      state(data, POP3_STOP);  /* Authenticated */
       break;
     case SASL_IDLE:            /* No mechanism left after cancellation */
 #ifndef CURL_DISABLE_CRYPTO_AUTH
       if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
         /* Perform APOP authentication */
-        result = pop3_perform_apop(conn);
+        result = pop3_perform_apop(data, conn);
       else
 #endif
       if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
         /* Perform clear text authentication */
-        result = pop3_perform_user(conn);
+        result = pop3_perform_user(data, conn);
       else {
         failf(data, "Authentication cancelled");
         result = CURLE_LOGIN_DENIED;
@@ -814,12 +830,10 @@ static CURLcode pop3_state_auth_resp(struct connectdata *conn,
 
 #ifndef CURL_DISABLE_CRYPTO_AUTH
 /* For APOP responses */
-static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
+static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(pop3code != '+') {
@@ -828,19 +842,18 @@ static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
   }
   else
     /* End of connect phase */
-    state(conn, POP3_STOP);
+    state(data, POP3_STOP);
 
   return result;
 }
 #endif
 
 /* For USER responses */
-static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
+static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
   (void)instate; /* no use for this yet */
 
   if(pop3code != '+') {
@@ -849,21 +862,19 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
   }
   else
     /* Send the PASS command */
-    result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
+    result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "PASS %s",
                            conn->passwd ? conn->passwd : "");
   if(!result)
-    state(conn, POP3_PASS);
+    state(data, POP3_PASS);
 
   return result;
 }
 
 /* For PASS responses */
-static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
+static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(pop3code != '+') {
@@ -872,26 +883,26 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
   }
   else
     /* End of connect phase */
-    state(conn, POP3_STOP);
+    state(data, POP3_STOP);
 
   return result;
 }
 
 /* For command responses */
-static CURLcode pop3_state_command_resp(struct connectdata *conn,
+static CURLcode pop3_state_command_resp(struct Curl_easy *data,
                                         int pop3code,
                                         pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct POP3 *pop3 = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct POP3 *pop3 = data->req.p.pop3;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   struct pingpong *pp = &pop3c->pp;
 
   (void)instate; /* no use for this yet */
 
   if(pop3code != '+') {
-    state(conn, POP3_STOP);
+    state(data, POP3_STOP);
     return CURLE_RECV_ERROR;
   }
 
@@ -915,7 +926,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn,
          "headers" after the body */
 
       if(!data->set.opt_no_body) {
-        result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
+        result = Curl_pop3_write(data, pp->cache, pp->cache_size);
         if(result)
           return result;
       }
@@ -929,12 +940,13 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn,
   }
 
   /* End of DO phase */
-  state(conn, POP3_STOP);
+  state(data, POP3_STOP);
 
   return result;
 }
 
-static CURLcode pop3_statemach_act(struct connectdata *conn)
+static CURLcode pop3_statemachine(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
@@ -942,20 +954,21 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   struct pingpong *pp = &pop3c->pp;
   size_t nread = 0;
+  (void)data;
 
   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
   if(pop3c->state == POP3_UPGRADETLS)
-    return pop3_perform_upgrade_tls(conn);
+    return pop3_perform_upgrade_tls(data, conn);
 
   /* Flush any data that needs to be sent */
   if(pp->sendleft)
-    return Curl_pp_flushsend(pp);
+    return Curl_pp_flushsend(data, pp);
 
  do {
     /* Read the response from the server */
-    result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
-    if(result)
-      return result;
+   result = Curl_pp_readresp(data, sock, pp, &pop3code, &nread);
+   if(result)
+     return result;
 
     if(!pop3code)
       break;
@@ -963,44 +976,44 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)
     /* We have now received a full POP3 server response */
     switch(pop3c->state) {
     case POP3_SERVERGREET:
-      result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_servergreet_resp(data, pop3code, pop3c->state);
       break;
 
     case POP3_CAPA:
-      result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_capa_resp(data, pop3code, pop3c->state);
       break;
 
     case POP3_STARTTLS:
-      result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_starttls_resp(data, conn, pop3code, pop3c->state);
       break;
 
     case POP3_AUTH:
-      result = pop3_state_auth_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_auth_resp(data, pop3code, pop3c->state);
       break;
 
 #ifndef CURL_DISABLE_CRYPTO_AUTH
     case POP3_APOP:
-      result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_apop_resp(data, pop3code, pop3c->state);
       break;
 #endif
 
     case POP3_USER:
-      result = pop3_state_user_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_user_resp(data, pop3code, pop3c->state);
       break;
 
     case POP3_PASS:
-      result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_pass_resp(data, pop3code, pop3c->state);
       break;
 
     case POP3_COMMAND:
-      result = pop3_state_command_resp(conn, pop3code, pop3c->state);
+      result = pop3_state_command_resp(data, pop3code, pop3c->state);
       break;
 
     case POP3_QUIT:
       /* fallthrough, just stop! */
     default:
       /* internal error */
-      state(conn, POP3_STOP);
+      state(data, POP3_STOP);
       break;
     }
   } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
@@ -1009,44 +1022,46 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)
 }
 
 /* Called repeatedly until done from multi.c */
-static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
+static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
 
   if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
-    result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
+    result = Curl_ssl_connect_nonblocking(data, conn,
+                                          FIRSTSOCKET, &pop3c->ssldone);
     if(result || !pop3c->ssldone)
       return result;
   }
 
-  result = Curl_pp_statemach(&pop3c->pp, FALSE, FALSE);
+  result = Curl_pp_statemach(data, &pop3c->pp, FALSE, FALSE);
   *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
 
   return result;
 }
 
-static CURLcode pop3_block_statemach(struct connectdata *conn,
+static CURLcode pop3_block_statemach(struct Curl_easy *data,
+                                     struct connectdata *conn,
                                      bool disconnecting)
 {
   CURLcode result = CURLE_OK;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
 
   while(pop3c->state != POP3_STOP && !result)
-    result = Curl_pp_statemach(&pop3c->pp, TRUE, disconnecting);
+    result = Curl_pp_statemach(data, &pop3c->pp, TRUE, disconnecting);
 
   return result;
 }
 
 /* Allocate and initialize the POP3 struct for the current Curl_easy if
    required */
-static CURLcode pop3_init(struct connectdata *conn)
+static CURLcode pop3_init(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct POP3 *pop3;
 
-  pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
+  pop3 = data->req.p.pop3 = calloc(sizeof(struct POP3), 1);
   if(!pop3)
     result = CURLE_OUT_OF_MEMORY;
 
@@ -1054,9 +1069,10 @@ static CURLcode pop3_init(struct connectdata *conn)
 }
 
 /* For the POP3 "protocol connect" and "doing" phases only */
-static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int pop3_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks)
 {
-  return Curl_pp_getsock(&conn->proto.pop3c.pp, socks);
+  return Curl_pp_getsock(data, &conn->proto.pop3c.pp, socks);
 }
 
 /***********************************************************************
@@ -1069,9 +1085,10 @@ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks)
  * The variable 'done' points to will be TRUE if the protocol-layer connect
  * phase is done when this function returns, or FALSE if not.
  */
-static CURLcode pop3_connect(struct connectdata *conn, bool *done)
+static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   struct pingpong *pp = &pop3c->pp;
 
@@ -1080,18 +1097,15 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
   /* We always support persistent connections in POP3 */
   connkeep(conn, "POP3 default");
 
-  /* Set the default response time-out */
-  pp->response_time = RESP_TIMEOUT;
-  pp->statemach_act = pop3_statemach_act;
-  pp->endofresp = pop3_endofresp;
-  pp->conn = conn;
+  PINGPONG_SETUP(pp, pop3_statemachine, pop3_endofresp);
 
   /* Set the default preferred authentication type and mechanism */
   pop3c->preftype = POP3_TYPE_ANY;
   Curl_sasl_init(&pop3c->sasl, &saslpop3);
 
   /* Initialise the pingpong layer */
-  Curl_pp_init(pp);
+  Curl_pp_setup(pp);
+  Curl_pp_init(data, pp);
 
   /* Parse the URL options */
   result = pop3_parse_url_options(conn);
@@ -1099,9 +1113,9 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
     return result;
 
   /* Start off waiting for the server greeting response */
-  state(conn, POP3_SERVERGREET);
+  state(data, POP3_SERVERGREET);
 
-  result = pop3_multi_statemach(conn, done);
+  result = pop3_multi_statemach(data, done);
 
   return result;
 }
@@ -1115,12 +1129,11 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
  *
  * Input argument is already checked for validity.
  */
-static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
                           bool premature)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct POP3 *pop3 = data->req.protop;
+  struct POP3 *pop3 = data->req.p.pop3;
 
   (void)premature;
 
@@ -1128,7 +1141,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
     return CURLE_OK;
 
   if(status) {
-    connclose(conn, "POP3 done with bad status");
+    connclose(data->conn, "POP3 done with bad status");
     result = status;         /* use the already set error code */
   }
 
@@ -1149,16 +1162,17 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
  * This is the actual DO function for POP3. Get a message/listing according to
  * the options previously setup.
  */
-static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
+static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
                              bool *dophase_done)
 {
   /* This is POP3 and no proxy */
   CURLcode result = CURLE_OK;
-  struct POP3 *pop3 = conn->data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct POP3 *pop3 = data->req.p.pop3;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
-  if(conn->data->set.opt_no_body) {
+  if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
     pop3->transfer = FTPTRANSFER_INFO;
   }
@@ -1166,17 +1180,16 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
   *dophase_done = FALSE; /* not done yet */
 
   /* Start the first command in the DO phase */
-  result = pop3_perform_command(conn);
+  result = pop3_perform_command(data);
   if(result)
     return result;
 
   /* Run the state-machine */
-  result = pop3_multi_statemach(conn, dophase_done);
-
+  result = pop3_multi_statemach(data, dophase_done);
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
 
   return result;
 }
@@ -1190,23 +1203,22 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
  *
  * The input argument is already checked for validity.
  */
-static CURLcode pop3_do(struct connectdata *conn, bool *done)
+static CURLcode pop3_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-
   *done = FALSE; /* default to false */
 
   /* Parse the URL path */
-  result = pop3_parse_url_path(conn);
+  result = pop3_parse_url_path(data);
   if(result)
     return result;
 
   /* Parse the custom request */
-  result = pop3_parse_custom_request(conn);
+  result = pop3_parse_custom_request(data);
   if(result)
     return result;
 
-  result = pop3_regular_transfer(conn, done);
+  result = pop3_regular_transfer(data, done);
 
   return result;
 }
@@ -1218,19 +1230,20 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done)
  * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
  * resources. BLOCKING.
  */
-static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode pop3_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
 {
   struct pop3_conn *pop3c = &conn->proto.pop3c;
+  (void)data;
 
   /* We cannot send quit unconditionally. If this connection is stale or
      bad in any way, sending quit and waiting around here will make the
      disconnect wait in vain and cause more problems than we need to. */
 
-  /* The POP3 session may or may not have been allocated/setup at this
-     point! */
-  if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
-    if(!pop3_perform_quit(conn))
-      (void)pop3_block_statemach(conn, TRUE); /* ignore errors on QUIT */
+  if(!dead_connection && conn->bits.protoconnstart) {
+    if(!pop3_perform_quit(data, conn))
+      (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */
+  }
 
   /* Disconnect from the server */
   Curl_pp_disconnect(&pop3c->pp);
@@ -1245,25 +1258,25 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
 }
 
 /* Call this when the DO phase has completed */
-static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
+static CURLcode pop3_dophase_done(struct Curl_easy *data, bool connected)
 {
-  (void)conn;
+  (void)data;
   (void)connected;
 
   return CURLE_OK;
 }
 
 /* Called from multi.c while DOing */
-static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
+static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done)
 {
-  CURLcode result = pop3_multi_statemach(conn, dophase_done);
+  CURLcode result = pop3_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(conn->data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed\n"));
   else if(*dophase_done) {
-    result = pop3_dophase_done(conn, FALSE /* not connected */);
+    result = pop3_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
@@ -1278,12 +1291,11 @@ static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
  * Performs all commands done before a regular transfer between a local and a
  * remote host.
  */
-static CURLcode pop3_regular_transfer(struct connectdata *conn,
+static CURLcode pop3_regular_transfer(struct Curl_easy *data,
                                       bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
-  struct Curl_easy *data = conn->data;
 
   /* Make sure size is unknown at this point */
   data->req.size = -1;
@@ -1295,19 +1307,20 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn,
   Curl_pgrsSetDownloadSize(data, -1);
 
   /* Carry out the perform */
-  result = pop3_perform(conn, &connected, dophase_done);
+  result = pop3_perform(data, &connected, dophase_done);
 
   /* Perform post DO phase operations if necessary */
   if(!result && *dophase_done)
-    result = pop3_dophase_done(conn, connected);
+    result = pop3_dophase_done(data, connected);
 
   return result;
 }
 
-static CURLcode pop3_setup_connection(struct connectdata *conn)
+static CURLcode pop3_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   /* Initialise the POP3 layer */
-  CURLcode result = pop3_init(conn);
+  CURLcode result = pop3_init(data);
   if(result)
     return result;
 
@@ -1382,11 +1395,10 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
  *
  * Parse the URL path into separate path components.
  */
-static CURLcode pop3_parse_url_path(struct connectdata *conn)
+static CURLcode pop3_parse_url_path(struct Curl_easy *data)
 {
   /* The POP3 struct is already initialised in pop3_connect() */
-  struct Curl_easy *data = conn->data;
-  struct POP3 *pop3 = data->req.protop;
+  struct POP3 *pop3 = data->req.p.pop3;
   const char *path = &data->state.up.path[1]; /* skip leading path */
 
   /* URL decode the path for the message ID */
@@ -1399,11 +1411,10 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
  *
  * Parse the custom request.
  */
-static CURLcode pop3_parse_custom_request(struct connectdata *conn)
+static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct POP3 *pop3 = data->req.protop;
+  struct POP3 *pop3 = data->req.p.pop3;
   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
 
   /* URL decode the custom request */
@@ -1420,13 +1431,12 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn)
  * This function scans the body after the end-of-body and writes everything
  * until the end is found.
  */
-CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
+CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
 {
   /* This code could be made into a special function in the handler struct */
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
-
+  struct connectdata *conn = data->conn;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   bool strip_dot = FALSE;
   size_t last = 0;
@@ -1447,7 +1457,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
 
         if(i) {
           /* Write out the body part that didn't match */
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
+          result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
                                      i - last);
 
           if(result)
@@ -1505,7 +1515,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
       if(prev) {
         /* If the partial match was the CRLF and dot then only write the CRLF
            as the server would have inserted the dot */
-        result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB,
+        result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
                                    strip_dot ? prev - 1 : prev);
 
         if(result)
@@ -1521,7 +1531,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
     /* We have a full match so the transfer is done, however we must transfer
     the CRLF at the start of the EOB as this is considered to be part of the
     message as per RFC-1939, sect. 3 */
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
 
     k->keepon &= ~KEEP_RECV;
     pop3c->eob = 0;
@@ -1534,7 +1544,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
     return CURLE_OK;
 
   if(nread - last) {
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
+    result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
                                nread - last);
   }
 
index 3ba7999..17629ee 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -61,6 +61,7 @@ struct pop3_conn {
   struct pingpong pp;
   pop3state state;        /* Always use pop3.c:state() to change state! */
   bool ssldone;           /* Is connect() over SSL done? */
+  bool tls_supported;     /* StartTLS capability supported by server */
   size_t eob;             /* Number of bytes of the EOB (End Of Body) that
                              have been received so far */
   size_t strip;           /* Number of bytes from the start to ignore as
@@ -69,7 +70,6 @@ struct pop3_conn {
   unsigned int authtypes; /* Accepted authentication types */
   unsigned int preftype;  /* Preferred authentication type */
   char *apoptimestamp;    /* APOP timestamp from the server greeting */
-  bool tls_supported;     /* StartTLS capability supported by server */
 };
 
 extern const struct Curl_handler Curl_handler_pop3;
@@ -90,6 +90,6 @@ extern const struct Curl_handler Curl_handler_pop3s;
 
 /* This function scans the body after the end-of-body and writes everything
  * until the end is found */
-CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread);
+CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread);
 
 #endif /* HEADER_CURL_POP3_H */
index 8951384..55e8ded 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -137,12 +137,11 @@ static char *max5data(curl_off_t bytes, char *max5)
 
 */
 
-int Curl_pgrsDone(struct connectdata *conn)
+int Curl_pgrsDone(struct Curl_easy *data)
 {
   int rc;
-  struct Curl_easy *data = conn->data;
   data->progress.lastshow = 0;
-  rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
+  rc = Curl_pgrsUpdate(data); /* the final (forced) update */
   if(rc)
     return rc;
 
@@ -164,9 +163,13 @@ void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
 }
 
 /*
+ *
+ * Curl_pgrsTime(). Store the current time at the given label. This fetches a
+ * fresh "now" and returns it.
+ *
  * @unittest: 1399
  */
-void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
+struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer)
 {
   struct curltime now = Curl_now();
   timediff_t *delta = NULL;
@@ -209,7 +212,7 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
      * changing the t_starttransfer time.
      */
     if(data->progress.is_t_startransfer_set) {
-      return;
+      return now;
     }
     else {
       data->progress.is_t_startransfer_set = true;
@@ -228,6 +231,7 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
       us = 1; /* make sure at least one microsecond passed */
     *delta += us;
   }
+  return now;
 }
 
 void Curl_pgrsStartNow(struct Curl_easy *data)
@@ -235,10 +239,8 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
   data->progress.speeder_c = 0; /* reset the progress meter display */
   data->progress.start = Curl_now();
   data->progress.is_t_startransfer_set = false;
-  data->progress.ul_limit_start.tv_sec = 0;
-  data->progress.ul_limit_start.tv_usec = 0;
-  data->progress.dl_limit_start.tv_sec = 0;
-  data->progress.dl_limit_start.tv_usec = 0;
+  data->progress.ul_limit_start = data->progress.start;
+  data->progress.dl_limit_start = data->progress.start;
   data->progress.downloaded = 0;
   data->progress.uploaded = 0;
   /* clear all bits except HIDE and HEADERS_OUT */
@@ -368,11 +370,10 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
 }
 
 /* returns TRUE if it's time to show the progress meter */
-static bool progress_calc(struct connectdata *conn, struct curltime now)
+static bool progress_calc(struct Curl_easy *data, struct curltime now)
 {
   curl_off_t timespent;
   curl_off_t timespent_ms; /* milliseconds */
-  struct Curl_easy *data = conn->data;
   curl_off_t dl = data->progress.downloaded;
   curl_off_t ul = data->progress.uploaded;
   bool timetoshow = FALSE;
@@ -462,9 +463,8 @@ static bool progress_calc(struct connectdata *conn, struct curltime now)
 }
 
 #ifndef CURL_DISABLE_PROGRESS_METER
-static void progress_meter(struct connectdata *conn)
+static void progress_meter(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   char max5[6][10];
   curl_off_t dlpercen = 0;
   curl_off_t ulpercen = 0;
@@ -578,11 +578,10 @@ static void progress_meter(struct connectdata *conn)
  * Curl_pgrsUpdate() returns 0 for success or the value returned by the
  * progress callback!
  */
-int Curl_pgrsUpdate(struct connectdata *conn)
+int Curl_pgrsUpdate(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   struct curltime now = Curl_now(); /* what time is it */
-  bool showprogress = progress_calc(conn, now);
+  bool showprogress = progress_calc(data, now);
   if(!(data->progress.flags & PGRS_HIDE)) {
     if(data->set.fxferinfo) {
       int result;
@@ -618,7 +617,7 @@ int Curl_pgrsUpdate(struct connectdata *conn)
     }
 
     if(showprogress)
-      progress_meter(conn);
+      progress_meter(data);
   }
 
   return 0;
index 3515ac6..ac4ebc0 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -40,16 +40,16 @@ typedef enum {
   TIMER_LAST /* must be last */
 } timerid;
 
-int Curl_pgrsDone(struct connectdata *);
+int Curl_pgrsDone(struct Curl_easy *data);
 void Curl_pgrsStartNow(struct Curl_easy *data);
 void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
 void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
 void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
 void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
 void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
-int Curl_pgrsUpdate(struct connectdata *);
+int Curl_pgrsUpdate(struct Curl_easy *data);
 void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
-void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
+struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
 timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
                                   curl_off_t startsize,
                                   curl_off_t limit,
index 568baff..e460918 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index e9f99d0..c103674 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 8e7df90..947f13e 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "urldata.h"
 
 /* functions provided by the specific backends */
-CURLcode Curl_quic_connect(struct connectdata *conn,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+                           struct connectdata *conn,
                            curl_socket_t sockfd,
                            int sockindex,
                            const struct sockaddr *addr,
                            socklen_t addrlen);
-CURLcode Curl_quic_is_connected(struct connectdata *conn,
-                                curl_socket_t sockfd,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                int sockindex,
                                 bool *connected);
 int Curl_quic_ver(char *p, size_t len);
-CURLcode Curl_quic_done_sending(struct connectdata *conn);
+CURLcode Curl_quic_done_sending(struct Curl_easy *data);
 void Curl_quic_done(struct Curl_easy *data, bool premature);
 bool Curl_quic_data_pending(const struct Curl_easy *data);
-void Curl_quic_disconnect(struct connectdata *conn, int tempindex);
+void Curl_quic_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn, int tempindex);
 
 #else /* ENABLE_QUIC */
 #define Curl_quic_done_sending(x)
 #define Curl_quic_done(x,y)
 #define Curl_quic_data_pending(x)
-#define Curl_quic_disconnect(x,y)
+#define Curl_quic_disconnect(x,y,z)
 #endif /* !ENABLE_QUIC */
 
 #endif /* HEADER_CURL_QUIC_H */
index c415048..951fedb 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 3c8e2b8..02d95d8 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index fe5f95d..f858d43 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -24,8 +24,8 @@
 
 #include "curl_setup.h"
 
-#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) ||  \
-  defined(USE_ALTSVC)
+#if (!defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_COOKIES)) || \
+  !defined(CURL_DISABLE_ALTSVC)
 
 #include "curl_multibyte.h"
 #include "timeval.h"
index d7442c8..534f747 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index dbd7dc6..5576675 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -22,7 +22,7 @@
 
 #include "curl_setup.h"
 
-#ifndef CURL_DISABLE_RTSP
+#if !defined(CURL_DISABLE_RTSP) && !defined(USE_HYPER)
 
 #include "urldata.h"
 #include <curl/curl.h>
                              ((int)((unsigned char)((p)[3]))))
 
 /* protocol-specific functions set up to be called by the main engine */
-static CURLcode rtsp_do(struct connectdata *conn, bool *done);
-static CURLcode rtsp_done(struct connectdata *conn, CURLcode, bool premature);
-static CURLcode rtsp_connect(struct connectdata *conn, bool *done);
-static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead);
-static int rtsp_getsock_do(struct connectdata *conn, curl_socket_t *socks);
+static CURLcode rtsp_do(struct Curl_easy *data, bool *done);
+static CURLcode rtsp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode rtsp_connect(struct Curl_easy *data, bool *done);
+static CURLcode rtsp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static int rtsp_getsock_do(struct Curl_easy *data,
+                           struct connectdata *conn, curl_socket_t *socks);
 
 /*
  * Parse and write out any available RTP data.
@@ -66,23 +68,26 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
                                    ssize_t *nread,
                                    bool *readmore);
 
-static CURLcode rtsp_setup_connection(struct connectdata *conn);
-static unsigned int rtsp_conncheck(struct connectdata *check,
+static CURLcode rtsp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static unsigned int rtsp_conncheck(struct Curl_easy *data,
+                                   struct connectdata *check,
                                    unsigned int checks_to_perform);
 
 /* this returns the socket to wait for in the DO and DOING state for the multi
    interface and then we're always _sending_ a request and thus we wait for
    the single socket to become writable only */
-static int rtsp_getsock_do(struct connectdata *conn,
+static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
                            curl_socket_t *socks)
 {
   /* write mode */
+  (void)data;
   socks[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_WRITESOCK(0);
 }
 
 static
-CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len);
+CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len);
 
 
 /*
@@ -106,15 +111,18 @@ const struct Curl_handler Curl_handler_rtsp = {
   rtsp_conncheck,                       /* connection_check */
   PORT_RTSP,                            /* defport */
   CURLPROTO_RTSP,                       /* protocol */
+  CURLPROTO_RTSP,                       /* family */
   PROTOPT_NONE                          /* flags */
 };
 
 
-static CURLcode rtsp_setup_connection(struct connectdata *conn)
+static CURLcode rtsp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   struct RTSP *rtsp;
+  (void)conn;
 
-  conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP));
+  data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
   if(!rtsp)
     return CURLE_OUT_OF_MEMORY;
 
@@ -155,13 +163,15 @@ static bool rtsp_connisdead(struct connectdata *check)
 /*
  * Function to check on various aspects of a connection.
  */
-static unsigned int rtsp_conncheck(struct connectdata *check,
+static unsigned int rtsp_conncheck(struct Curl_easy *data,
+                                   struct connectdata *conn,
                                    unsigned int checks_to_perform)
 {
   unsigned int ret_val = CONNRESULT_NONE;
+  (void)data;
 
   if(checks_to_perform & CONNCHECK_ISDEAD) {
-    if(rtsp_connisdead(check))
+    if(rtsp_connisdead(conn))
       ret_val |= CONNRESULT_DEAD;
   }
 
@@ -169,12 +179,11 @@ static unsigned int rtsp_conncheck(struct connectdata *check,
 }
 
 
-static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
+static CURLcode rtsp_connect(struct Curl_easy *data, bool *done)
 {
   CURLcode httpStatus;
-  struct Curl_easy *data = conn->data;
 
-  httpStatus = Curl_http_connect(conn, done);
+  httpStatus = Curl_http_connect(data, done);
 
   /* Initialize the CSeq if not already done */
   if(data->state.rtsp_next_client_CSeq == 0)
@@ -182,31 +191,32 @@ static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
   if(data->state.rtsp_next_server_CSeq == 0)
     data->state.rtsp_next_server_CSeq = 1;
 
-  conn->proto.rtspc.rtp_channel = -1;
+  data->conn->proto.rtspc.rtp_channel = -1;
 
   return httpStatus;
 }
 
-static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead)
+static CURLcode rtsp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead)
 {
   (void) dead;
+  (void) data;
   Curl_safefree(conn->proto.rtspc.rtp_buf);
   return CURLE_OK;
 }
 
 
-static CURLcode rtsp_done(struct connectdata *conn,
+static CURLcode rtsp_done(struct Curl_easy *data,
                           CURLcode status, bool premature)
 {
-  struct Curl_easy *data = conn->data;
-  struct RTSP *rtsp = data->req.protop;
+  struct RTSP *rtsp = data->req.p.rtsp;
   CURLcode httpStatus;
 
   /* Bypass HTTP empty-reply checks on receive */
   if(data->set.rtspreq == RTSPREQ_RECEIVE)
     premature = TRUE;
 
-  httpStatus = Curl_http_done(conn, status, premature);
+  httpStatus = Curl_http_done(data, status, premature);
 
   if(rtsp) {
     /* Check the sequence numbers */
@@ -219,7 +229,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
       return CURLE_RTSP_CSEQ_ERROR;
     }
     if(data->set.rtspreq == RTSPREQ_RECEIVE &&
-            (conn->proto.rtspc.rtp_channel == -1)) {
+            (data->conn->proto.rtspc.rtp_channel == -1)) {
       infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
     }
   }
@@ -227,12 +237,12 @@ static CURLcode rtsp_done(struct connectdata *conn,
   return httpStatus;
 }
 
-static CURLcode rtsp_do(struct connectdata *conn, bool *done)
+static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
   Curl_RtspReq rtspreq = data->set.rtspreq;
-  struct RTSP *rtsp = data->req.protop;
+  struct RTSP *rtsp = data->req.p.rtsp;
   struct dynbuf req_buffer;
   curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
   curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
@@ -329,7 +339,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   }
 
   /* Transport Header for SETUP requests */
-  p_transport = Curl_checkheaders(conn, "Transport");
+  p_transport = Curl_checkheaders(data, "Transport");
   if(rtspreq == RTSPREQ_SETUP && !p_transport) {
     /* New Transport: setting? */
     if(data->set.str[STRING_RTSP_TRANSPORT]) {
@@ -353,11 +363,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   /* Accept Headers for DESCRIBE requests */
   if(rtspreq == RTSPREQ_DESCRIBE) {
     /* Accept Header */
-    p_accept = Curl_checkheaders(conn, "Accept")?
+    p_accept = Curl_checkheaders(data, "Accept")?
       NULL:"Accept: application/sdp\r\n";
 
     /* Accept-Encoding header */
-    if(!Curl_checkheaders(conn, "Accept-Encoding") &&
+    if(!Curl_checkheaders(data, "Accept-Encoding") &&
        data->set.str[STRING_ENCODING]) {
       Curl_safefree(data->state.aptr.accept_encoding);
       data->state.aptr.accept_encoding =
@@ -374,17 +384,18 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
      it might have been used in the proxy connect, but if we have got a header
      with the user-agent string specified, we erase the previously made string
      here. */
-  if(Curl_checkheaders(conn, "User-Agent") && data->state.aptr.uagent) {
+  if(Curl_checkheaders(data, "User-Agent") && data->state.aptr.uagent) {
     Curl_safefree(data->state.aptr.uagent);
     data->state.aptr.uagent = NULL;
   }
-  else if(!Curl_checkheaders(conn, "User-Agent") &&
+  else if(!Curl_checkheaders(data, "User-Agent") &&
           data->set.str[STRING_USERAGENT]) {
     p_uagent = data->state.aptr.uagent;
   }
 
   /* setup the authentication headers */
-  result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE);
+  result = Curl_http_output_auth(data, conn, p_request, HTTPREQ_GET,
+                                 p_stream_uri, FALSE);
   if(result)
     return result;
 
@@ -393,7 +404,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 
   /* Referrer */
   Curl_safefree(data->state.aptr.ref);
-  if(data->change.referer && !Curl_checkheaders(conn, "Referer"))
+  if(data->change.referer && !Curl_checkheaders(data, "Referer"))
     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
   else
     data->state.aptr.ref = NULL;
@@ -410,7 +421,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
      (rtspreq  & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
 
     /* Check to see if there is a range set in the custom headers */
-    if(!Curl_checkheaders(conn, "Range") && data->state.range) {
+    if(!Curl_checkheaders(data, "Range") && data->state.range) {
       Curl_safefree(data->state.aptr.rangeline);
       data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
       p_range = data->state.aptr.rangeline;
@@ -420,11 +431,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   /*
    * Sanity check the custom headers
    */
-  if(Curl_checkheaders(conn, "CSeq")) {
+  if(Curl_checkheaders(data, "CSeq")) {
     failf(data, "CSeq cannot be set as a custom header.");
     return CURLE_RTSP_CSEQ_ERROR;
   }
-  if(Curl_checkheaders(conn, "Session")) {
+  if(Curl_checkheaders(data, "Session")) {
     failf(data, "Session ID cannot be set as a custom header.");
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
@@ -483,12 +494,12 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     return result;
 
   if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
-    result = Curl_add_timecondition(conn, &req_buffer);
+    result = Curl_add_timecondition(data, &req_buffer);
     if(result)
       return result;
   }
 
-  result = Curl_add_custom_headers(conn, FALSE, &req_buffer);
+  result = Curl_add_custom_headers(data, FALSE, &req_buffer);
   if(result)
     return result;
 
@@ -511,7 +522,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     if(putsize > 0 || postsize > 0) {
       /* As stated in the http comments, it is probably not wise to
        * actually set a custom Content-Length in the headers */
-      if(!Curl_checkheaders(conn, "Content-Length")) {
+      if(!Curl_checkheaders(data, "Content-Length")) {
         result =
           Curl_dyn_addf(&req_buffer,
                         "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
@@ -522,7 +533,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 
       if(rtspreq == RTSPREQ_SET_PARAMETER ||
          rtspreq == RTSPREQ_GET_PARAMETER) {
-        if(!Curl_checkheaders(conn, "Content-Type")) {
+        if(!Curl_checkheaders(data, "Content-Type")) {
           result = Curl_dyn_addf(&req_buffer,
                                  "Content-Type: text/parameters\r\n");
           if(result)
@@ -531,7 +542,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
       }
 
       if(rtspreq == RTSPREQ_ANNOUNCE) {
-        if(!Curl_checkheaders(conn, "Content-Type")) {
+        if(!Curl_checkheaders(data, "Content-Type")) {
           result = Curl_dyn_addf(&req_buffer,
                                  "Content-Type: application/sdp\r\n");
           if(result)
@@ -563,7 +574,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   }
 
   /* issue the request */
-  result = Curl_buffer_send(&req_buffer, conn,
+  result = Curl_buffer_send(&req_buffer, data,
                             &data->info.request_size, 0, FIRSTSOCKET);
   if(result) {
     failf(data, "Failed sending RTSP request");
@@ -579,7 +590,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     /* if a request-body has been sent off, we make sure this progress is
        noted properly */
     Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
   }
 
@@ -641,7 +652,7 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
        * Write out the header including the leading '$' */
       DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
              rtspc->rtp_channel, rtp_length));
-      result = rtp_client_write(conn, &rtp[0], rtp_length + 4);
+      result = rtp_client_write(data, &rtp[0], rtp_length + 4);
       if(result) {
         failf(data, "Got an error writing an RTP packet");
         *readmore = FALSE;
@@ -712,9 +723,8 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
 }
 
 static
-CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
+CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len)
 {
-  struct Curl_easy *data = conn->data;
   size_t wrote;
   curl_write_callback writeit;
   void *user_ptr;
@@ -754,17 +764,15 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
   return CURLE_OK;
 }
 
-CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
-                               char *header)
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
 {
-  struct Curl_easy *data = conn->data;
   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) {
-      struct RTSP *rtsp = data->req.protop;
+      struct RTSP *rtsp = data->req.p.rtsp;
       rtsp->CSeq_recv = CSeq; /* mark the request */
       data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
     }
@@ -775,6 +783,8 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
   }
   else if(checkprefix("Session:", header)) {
     char *start;
+    char *end;
+    size_t idlen;
 
     /* Find the first non-space letter */
     start = header + 8;
@@ -783,11 +793,25 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
 
     if(!*start) {
       failf(data, "Got a blank Session ID");
+      return CURLE_RTSP_SESSION_ERROR;
     }
-    else if(data->set.str[STRING_RTSP_SESSION_ID]) {
+
+    /* Find the end of Session ID
+     *
+     * Allow any non whitespace content, up to the field separator or end of
+     * line. RFC 2326 isn't 100% clear on the session ID and for example
+     * gstreamer does url-encoded session ID's not covered by the standard.
+     */
+    end = start;
+    while(*end && *end != ';' && !ISSPACE(*end))
+      end++;
+    idlen = end - start;
+
+    if(data->set.str[STRING_RTSP_SESSION_ID]) {
+
       /* If the Session ID is set, then compare */
-      if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID],
-                 strlen(data->set.str[STRING_RTSP_SESSION_ID]))  != 0) {
+      if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen ||
+         strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen) != 0) {
         failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
               start, data->set.str[STRING_RTSP_SESSION_ID]);
         return CURLE_RTSP_SESSION_ERROR;
@@ -796,24 +820,17 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
     else {
       /* If the Session ID is not set, and we find it in a response, then set
        * it.
-       *
-       * Allow any non whitespace content, up to the field separator or end of
-       * line. RFC 2326 isn't 100% clear on the session ID and for example
-       * gstreamer does url-encoded session ID's not covered by the standard.
        */
-      char *end = start;
-      while(*end && *end != ';' && !ISSPACE(*end))
-        end++;
 
       /* Copy the id substring into a new buffer */
-      data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1);
+      data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1);
       if(data->set.str[STRING_RTSP_SESSION_ID] == NULL)
         return CURLE_OUT_OF_MEMORY;
-      memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start);
-      (data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0';
+      memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen);
+      (data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0';
     }
   }
   return CURLE_OK;
 }
 
-#endif /* CURL_DISABLE_RTSP */
+#endif /* CURL_DISABLE_RTSP or using Hyper */
index 1aae864..1e9cb7d 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
  * KIND, either express or implied.
  *
  ***************************************************************************/
+#ifdef USE_HYPER
+#define CURL_DISABLE_RTSP
+#endif
+
 #ifndef CURL_DISABLE_RTSP
 
 extern const struct Curl_handler Curl_handler_rtsp;
 
-CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
 
 #else
 /* disabled */
diff --git a/Utilities/cmcurl/lib/security.c b/Utilities/cmcurl/lib/security.c
deleted file mode 100644 (file)
index 3b9c20a..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
- * use in Curl. His latest changes were done 2000-09-18.
- *
- * It has since been patched and modified a lot by Daniel Stenberg
- * <daniel@haxx.se> to make it better applied to curl conditions, and to make
- * it not use globals, pollute name space and more. This source code awaits a
- * rewrite to work around the paragraph 2 in the BSD licenses as explained
- * below.
- *
- * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- *
- * Copyright (C) 2001 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.  */
-
-#include "curl_setup.h"
-
-#ifndef CURL_DISABLE_FTP
-#ifdef HAVE_GSSAPI
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-
-#include <limits.h>
-
-#include "urldata.h"
-#include "curl_base64.h"
-#include "curl_memory.h"
-#include "curl_sec.h"
-#include "ftp.h"
-#include "sendf.h"
-#include "strcase.h"
-#include "warnless.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 const struct {
-  enum protection_level level;
-  const char *name;
-} level_names[] = {
-  { PROT_CLEAR, "clear" },
-  { PROT_SAFE, "safe" },
-  { PROT_CONFIDENTIAL, "confidential" },
-  { PROT_PRIVATE, "private" }
-};
-
-static enum protection_level
-name_to_level(const char *name)
-{
-  int i;
-  for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
-    if(checkprefix(name, level_names[i].name))
-      return level_names[i].level;
-  return PROT_NONE;
-}
-
-/* Convert a protocol |level| to its char representation.
-   We take an int to catch programming mistakes. */
-static char level_to_char(int level)
-{
-  switch(level) {
-  case PROT_CLEAR:
-    return 'C';
-  case PROT_SAFE:
-    return 'S';
-  case PROT_CONFIDENTIAL:
-    return 'E';
-  case PROT_PRIVATE:
-    return 'P';
-  case PROT_CMD:
-    /* Fall through */
-  default:
-    /* Those 2 cases should not be reached! */
-    break;
-  }
-  DEBUGASSERT(0);
-  /* Default to the most secure alternative. */
-  return 'P';
-}
-
-/* Send an FTP command defined by |message| and the optional arguments. The
-   function returns the ftp_code. If an error occurs, -1 is returned. */
-static int ftp_send_command(struct connectdata *conn, const char *message, ...)
-{
-  int ftp_code;
-  ssize_t nread = 0;
-  va_list args;
-  char print_buffer[50];
-
-  va_start(args, message);
-  mvsnprintf(print_buffer, sizeof(print_buffer), message, args);
-  va_end(args);
-
-  if(Curl_ftpsend(conn, print_buffer)) {
-    ftp_code = -1;
-  }
-  else {
-    if(Curl_GetFTPResponse(&nread, conn, &ftp_code))
-      ftp_code = -1;
-  }
-
-  (void)nread; /* Unused */
-  return ftp_code;
-}
-
-/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
-   saying whether an error occurred or CURLE_OK if |len| was read. */
-static CURLcode
-socket_read(curl_socket_t fd, void *to, size_t len)
-{
-  char *to_p = to;
-  CURLcode result;
-  ssize_t nread = 0;
-
-  while(len > 0) {
-    result = Curl_read_plain(fd, to_p, len, &nread);
-    if(!result) {
-      len -= nread;
-      to_p += nread;
-    }
-    else {
-      if(result == CURLE_AGAIN)
-        continue;
-      return result;
-    }
-  }
-  return CURLE_OK;
-}
-
-
-/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a
-   CURLcode saying whether an error occurred or CURLE_OK if |len| was
-   written. */
-static CURLcode
-socket_write(struct connectdata *conn, curl_socket_t fd, const void *to,
-             size_t len)
-{
-  const char *to_p = to;
-  CURLcode result;
-  ssize_t written;
-
-  while(len > 0) {
-    result = Curl_write_plain(conn, fd, to_p, len, &written);
-    if(!result) {
-      len -= written;
-      to_p += written;
-    }
-    else {
-      if(result == CURLE_AGAIN)
-        continue;
-      return result;
-    }
-  }
-  return CURLE_OK;
-}
-
-static CURLcode read_data(struct connectdata *conn,
-                          curl_socket_t fd,
-                          struct krb5buffer *buf)
-{
-  int len;
-  CURLcode result;
-
-  result = socket_read(fd, &len, sizeof(len));
-  if(result)
-    return result;
-
-  if(len) {
-    /* only realloc if there was a length */
-    len = ntohl(len);
-    buf->data = Curl_saferealloc(buf->data, len);
-  }
-  if(!len || !buf->data)
-    return CURLE_OUT_OF_MEMORY;
-
-  result = socket_read(fd, buf->data, len);
-  if(result)
-    return result;
-  buf->size = conn->mech->decode(conn->app_data, buf->data, len,
-                                 conn->data_prot, conn);
-  buf->index = 0;
-  return CURLE_OK;
-}
-
-static size_t
-buffer_read(struct krb5buffer *buf, void *data, size_t len)
-{
-  if(buf->size - buf->index < len)
-    len = buf->size - buf->index;
-  memcpy(data, (char *)buf->data + buf->index, len);
-  buf->index += len;
-  return len;
-}
-
-/* Matches Curl_recv signature */
-static ssize_t sec_recv(struct connectdata *conn, int sockindex,
-                        char *buffer, size_t len, CURLcode *err)
-{
-  size_t bytes_read;
-  size_t total_read = 0;
-  curl_socket_t fd = conn->sock[sockindex];
-
-  *err = CURLE_OK;
-
-  /* Handle clear text response. */
-  if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
-      return sread(fd, buffer, len);
-
-  if(conn->in_buffer.eof_flag) {
-    conn->in_buffer.eof_flag = 0;
-    return 0;
-  }
-
-  bytes_read = buffer_read(&conn->in_buffer, buffer, len);
-  len -= bytes_read;
-  total_read += bytes_read;
-  buffer += bytes_read;
-
-  while(len > 0) {
-    if(read_data(conn, fd, &conn->in_buffer))
-      return -1;
-    if(conn->in_buffer.size == 0) {
-      if(bytes_read > 0)
-        conn->in_buffer.eof_flag = 1;
-      return bytes_read;
-    }
-    bytes_read = buffer_read(&conn->in_buffer, buffer, len);
-    len -= bytes_read;
-    total_read += bytes_read;
-    buffer += bytes_read;
-  }
-  return total_read;
-}
-
-/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
-   and negotiating with the server. |from| can be NULL. */
-static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
-                        const char *from, int length)
-{
-  int bytes, htonl_bytes; /* 32-bit integers for htonl */
-  char *buffer = NULL;
-  char *cmd_buffer;
-  size_t cmd_size = 0;
-  CURLcode error;
-  enum protection_level prot_level = conn->data_prot;
-  bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE;
-
-  DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
-
-  if(iscmd) {
-    if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
-      prot_level = PROT_PRIVATE;
-    else
-      prot_level = conn->command_prot;
-  }
-  bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
-                             (void **)&buffer);
-  if(!buffer || bytes <= 0)
-    return; /* error */
-
-  if(iscmd) {
-    error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes),
-                               &cmd_buffer, &cmd_size);
-    if(error) {
-      free(buffer);
-      return; /* error */
-    }
-    if(cmd_size > 0) {
-      static const char *enc = "ENC ";
-      static const char *mic = "MIC ";
-      if(prot_level == PROT_PRIVATE)
-        socket_write(conn, fd, enc, 4);
-      else
-        socket_write(conn, fd, mic, 4);
-
-      socket_write(conn, fd, cmd_buffer, cmd_size);
-      socket_write(conn, fd, "\r\n", 2);
-      infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
-            cmd_buffer);
-      free(cmd_buffer);
-    }
-  }
-  else {
-    htonl_bytes = htonl(bytes);
-    socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes));
-    socket_write(conn, fd, buffer, curlx_sitouz(bytes));
-  }
-  free(buffer);
-}
-
-static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
-                         const char *buffer, size_t length)
-{
-  ssize_t tx = 0, len = conn->buffer_size;
-
-  len -= conn->mech->overhead(conn->app_data, conn->data_prot,
-                              curlx_sztosi(len));
-  if(len <= 0)
-    len = length;
-  while(length) {
-    if(length < (size_t)len)
-      len = length;
-
-    do_sec_send(conn, fd, buffer, curlx_sztosi(len));
-    length -= len;
-    buffer += len;
-    tx += len;
-  }
-  return tx;
-}
-
-/* Matches Curl_send signature */
-static ssize_t sec_send(struct connectdata *conn, int sockindex,
-                        const void *buffer, size_t len, CURLcode *err)
-{
-  curl_socket_t fd = conn->sock[sockindex];
-  *err = CURLE_OK;
-  return sec_write(conn, fd, buffer, len);
-}
-
-int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
-                      enum protection_level level)
-{
-  /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
-     int */
-  int decoded_len;
-  char *buf;
-  int ret_code = 0;
-  size_t decoded_sz = 0;
-  CURLcode error;
-
-  if(!conn->mech)
-    /* not inititalized, return error */
-    return -1;
-
-  DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
-
-  error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
-  if(error || decoded_sz == 0)
-    return -1;
-
-  if(decoded_sz > (size_t)INT_MAX) {
-    free(buf);
-    return -1;
-  }
-  decoded_len = curlx_uztosi(decoded_sz);
-
-  decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
-                                   level, conn);
-  if(decoded_len <= 0) {
-    free(buf);
-    return -1;
-  }
-
-  if(conn->data->set.verbose) {
-    buf[decoded_len] = '\n';
-    Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1);
-  }
-
-  buf[decoded_len] = '\0';
-  if(decoded_len <= 3)
-    /* suspiciously short */
-    return 0;
-
-  if(buf[3] != '-')
-    /* safe to ignore return code */
-    (void)sscanf(buf, "%d", &ret_code);
-
-  if(buf[decoded_len - 1] == '\n')
-    buf[decoded_len - 1] = '\0';
-  strcpy(buffer, buf);
-  free(buf);
-  return ret_code;
-}
-
-static int sec_set_protection_level(struct connectdata *conn)
-{
-  int code;
-  enum protection_level level = conn->request_data_prot;
-
-  DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
-
-  if(!conn->sec_complete) {
-    infof(conn->data, "Trying to change the protection level after the"
-                      " completion of the data exchange.\n");
-    return -1;
-  }
-
-  /* Bail out if we try to set up the same level */
-  if(conn->data_prot == level)
-    return 0;
-
-  if(level) {
-    char *pbsz;
-    static unsigned int buffer_size = 1 << 20; /* 1048576 */
-
-    code = ftp_send_command(conn, "PBSZ %u", buffer_size);
-    if(code < 0)
-      return -1;
-
-    if(code/100 != 2) {
-      failf(conn->data, "Failed to set the protection's buffer size.");
-      return -1;
-    }
-    conn->buffer_size = buffer_size;
-
-    pbsz = strstr(conn->data->state.buffer, "PBSZ=");
-    if(pbsz) {
-      /* ignore return code, use default value if it fails */
-      (void)sscanf(pbsz, "PBSZ=%u", &buffer_size);
-      if(buffer_size < conn->buffer_size)
-        conn->buffer_size = buffer_size;
-    }
-  }
-
-  /* Now try to negiociate the protection level. */
-  code = ftp_send_command(conn, "PROT %c", level_to_char(level));
-
-  if(code < 0)
-    return -1;
-
-  if(code/100 != 2) {
-    failf(conn->data, "Failed to set the protection level.");
-    return -1;
-  }
-
-  conn->data_prot = level;
-  if(level == PROT_PRIVATE)
-    conn->command_prot = level;
-
-  return 0;
-}
-
-int
-Curl_sec_request_prot(struct connectdata *conn, const char *level)
-{
-  enum protection_level l = name_to_level(level);
-  if(l == PROT_NONE)
-    return -1;
-  DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
-  conn->request_data_prot = l;
-  return 0;
-}
-
-static CURLcode choose_mech(struct connectdata *conn)
-{
-  int ret;
-  struct Curl_easy *data = conn->data;
-  void *tmp_allocation;
-  const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
-
-  tmp_allocation = realloc(conn->app_data, mech->size);
-  if(tmp_allocation == NULL) {
-    failf(data, "Failed realloc of size %zu", mech->size);
-    mech = NULL;
-    return CURLE_OUT_OF_MEMORY;
-  }
-  conn->app_data = tmp_allocation;
-
-  if(mech->init) {
-    ret = mech->init(conn->app_data);
-    if(ret) {
-      infof(data, "Failed initialization for %s. Skipping it.\n",
-            mech->name);
-      return CURLE_FAILED_INIT;
-    }
-  }
-
-  infof(data, "Trying mechanism %s...\n", mech->name);
-  ret = ftp_send_command(conn, "AUTH %s", mech->name);
-  if(ret < 0)
-    return CURLE_COULDNT_CONNECT;
-
-  if(ret/100 != 3) {
-    switch(ret) {
-    case 504:
-      infof(data, "Mechanism %s is not supported by the server (server "
-            "returned ftp code: 504).\n", mech->name);
-      break;
-    case 534:
-      infof(data, "Mechanism %s was rejected by the server (server returned "
-            "ftp code: 534).\n", mech->name);
-      break;
-    default:
-      if(ret/100 == 5) {
-        infof(data, "server does not support the security extensions\n");
-        return CURLE_USE_SSL_FAILED;
-      }
-      break;
-    }
-    return CURLE_LOGIN_DENIED;
-  }
-
-  /* Authenticate */
-  ret = mech->auth(conn->app_data, conn);
-
-  if(ret != AUTH_CONTINUE) {
-    if(ret != AUTH_OK) {
-      /* Mechanism has dumped the error to stderr, don't error here. */
-      return -1;
-    }
-    DEBUGASSERT(ret == AUTH_OK);
-
-    conn->mech = mech;
-    conn->sec_complete = 1;
-    conn->recv[FIRSTSOCKET] = sec_recv;
-    conn->send[FIRSTSOCKET] = sec_send;
-    conn->recv[SECONDARYSOCKET] = sec_recv;
-    conn->send[SECONDARYSOCKET] = sec_send;
-    conn->command_prot = PROT_SAFE;
-    /* Set the requested protection level */
-    /* BLOCKING */
-    (void)sec_set_protection_level(conn);
-  }
-
-  return CURLE_OK;
-}
-
-CURLcode
-Curl_sec_login(struct connectdata *conn)
-{
-  return choose_mech(conn);
-}
-
-
-void
-Curl_sec_end(struct connectdata *conn)
-{
-  if(conn->mech != NULL && conn->mech->end)
-    conn->mech->end(conn->app_data);
-  free(conn->app_data);
-  conn->app_data = NULL;
-  if(conn->in_buffer.data) {
-    free(conn->in_buffer.data);
-    conn->in_buffer.data = NULL;
-    conn->in_buffer.size = 0;
-    conn->in_buffer.index = 0;
-    conn->in_buffer.eof_flag = 0;
-  }
-  conn->sec_complete = 0;
-  conn->data_prot = PROT_CLEAR;
-  conn->mech = NULL;
-}
-
-#endif /* HAVE_GSSAPI */
-
-#endif /* CURL_DISABLE_FTP */
index 6832b42..44fe229 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -130,6 +130,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
   return r;
 }
 
+#ifndef HAVE_POLL_FINE
 /*
  * This is a wrapper around select() to aid in Windows compatibility.
  * A negative timeout value makes this function wait indefinitely,
@@ -141,23 +142,22 @@ int Curl_wait_ms(timediff_t timeout_ms)
  *    0 = timeout
  *    N = number of signalled file descriptors
  */
-int Curl_select(curl_socket_t maxfd,   /* highest socket number */
-                fd_set *fds_read,      /* sockets ready for reading */
-                fd_set *fds_write,     /* sockets ready for writing */
-                fd_set *fds_err,       /* sockets with errors */
-                timediff_t timeout_ms) /* milliseconds to wait */
+static int our_select(curl_socket_t maxfd,   /* highest socket number */
+                      fd_set *fds_read,      /* sockets ready for reading */
+                      fd_set *fds_write,     /* sockets ready for writing */
+                      fd_set *fds_err,       /* sockets with errors */
+                      timediff_t timeout_ms) /* milliseconds to wait */
 {
   struct timeval pending_tv;
   struct timeval *ptimeout;
-  int r;
 
 #ifdef USE_WINSOCK
   /* WinSock select() can't handle zero events.  See the comment below. */
   if((!fds_read || fds_read->fd_count == 0) &&
      (!fds_write || fds_write->fd_count == 0) &&
      (!fds_err || fds_err->fd_count == 0)) {
-    r = Curl_wait_ms(timeout_ms);
-    return r;
+    /* no sockets, just wait */
+    return Curl_wait_ms(timeout_ms);
   }
 #endif
 
@@ -209,19 +209,20 @@ int Curl_select(curl_socket_t maxfd,   /* highest socket number */
     descriptor set must contain at least one handle to a socket.
 
     It is unclear why WinSock doesn't just handle this for us instead of
-    calling this an error.
+    calling this an error. Luckily, with WinSock, we can _also_ ask how
+    many bits are set on an fd_set. So, let's just check it beforehand.
   */
-  r = select((int)maxfd + 1,
-             fds_read && fds_read->fd_count ? fds_read : NULL,
-             fds_write && fds_write->fd_count ? fds_write : NULL,
-             fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
+  return select((int)maxfd + 1,
+                fds_read && fds_read->fd_count ? fds_read : NULL,
+                fds_write && fds_write->fd_count ? fds_write : NULL,
+                fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
 #else
-  r = select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
+  return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
 #endif
-
-  return r;
 }
 
+#endif
+
 /*
  * Wait for read or write events on a set of file descriptors. It uses poll()
  * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
@@ -247,23 +248,14 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
                       curl_socket_t writefd, /* socket to write to */
                       timediff_t timeout_ms) /* milliseconds to wait */
 {
-#ifdef HAVE_POLL_FINE
   struct pollfd pfd[3];
   int num;
-#else
-  fd_set fds_read;
-  fd_set fds_write;
-  fd_set fds_err;
-  curl_socket_t maxfd;
-#endif
   int r;
-  int ret;
 
   if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
      (writefd == CURL_SOCKET_BAD)) {
     /* no sockets, just wait */
-    r = Curl_wait_ms(timeout_ms);
-    return r;
+    return Curl_wait_ms(timeout_ms);
   }
 
   /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
@@ -271,8 +263,6 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
      when function is called with a zero timeout or a negative timeout
      value indicating a blocking call should be performed. */
 
-#ifdef HAVE_POLL_FINE
-
   num = 0;
   if(readfd0 != CURL_SOCKET_BAD) {
     pfd[num].fd = readfd0;
@@ -288,7 +278,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
   }
   if(writefd != CURL_SOCKET_BAD) {
     pfd[num].fd = writefd;
-    pfd[num].events = POLLWRNORM|POLLOUT;
+    pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
     pfd[num].revents = 0;
     num++;
   }
@@ -297,101 +287,30 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
   if(r <= 0)
     return r;
 
-  ret = 0;
+  r = 0;
   num = 0;
   if(readfd0 != CURL_SOCKET_BAD) {
     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
-      ret |= CURL_CSELECT_IN;
+      r |= CURL_CSELECT_IN;
     if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
-      ret |= CURL_CSELECT_ERR;
+      r |= CURL_CSELECT_ERR;
     num++;
   }
   if(readfd1 != CURL_SOCKET_BAD) {
     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
-      ret |= CURL_CSELECT_IN2;
+      r |= CURL_CSELECT_IN2;
     if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
-      ret |= CURL_CSELECT_ERR;
+      r |= CURL_CSELECT_ERR;
     num++;
   }
   if(writefd != CURL_SOCKET_BAD) {
     if(pfd[num].revents & (POLLWRNORM|POLLOUT))
-      ret |= CURL_CSELECT_OUT;
-    if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL))
-      ret |= CURL_CSELECT_ERR;
-  }
-
-  return ret;
-
-#else  /* HAVE_POLL_FINE */
-
-  FD_ZERO(&fds_err);
-  maxfd = (curl_socket_t)-1;
-
-  FD_ZERO(&fds_read);
-  if(readfd0 != CURL_SOCKET_BAD) {
-    VERIFY_SOCK(readfd0);
-    FD_SET(readfd0, &fds_read);
-    FD_SET(readfd0, &fds_err);
-    maxfd = readfd0;
-  }
-  if(readfd1 != CURL_SOCKET_BAD) {
-    VERIFY_SOCK(readfd1);
-    FD_SET(readfd1, &fds_read);
-    FD_SET(readfd1, &fds_err);
-    if(readfd1 > maxfd)
-      maxfd = readfd1;
-  }
-
-  FD_ZERO(&fds_write);
-  if(writefd != CURL_SOCKET_BAD) {
-    VERIFY_SOCK(writefd);
-    FD_SET(writefd, &fds_write);
-    FD_SET(writefd, &fds_err);
-    if(writefd > maxfd)
-      maxfd = writefd;
-  }
-
-  /* We know that we have at least one bit set in at least two fd_sets in
-     this case, but we may have no bits set in either fds_read or fd_write,
-     so check for that and handle it.  Luckily, with WinSock, we can _also_
-     ask how many bits are set on an fd_set.
-
-     Note also that WinSock ignores the first argument, so we don't worry
-     about the fact that maxfd is computed incorrectly with WinSock (since
-     curl_socket_t is unsigned in such cases and thus -1 is the largest
-     value).
-  */
-  r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
-
-  if(r < 0)
-    return -1;
-  if(r == 0)
-    return 0;
-
-  ret = 0;
-  if(readfd0 != CURL_SOCKET_BAD) {
-    if(FD_ISSET(readfd0, &fds_read))
-      ret |= CURL_CSELECT_IN;
-    if(FD_ISSET(readfd0, &fds_err))
-      ret |= CURL_CSELECT_ERR;
+      r |= CURL_CSELECT_OUT;
+    if(pfd[num].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL))
+      r |= CURL_CSELECT_ERR;
   }
-  if(readfd1 != CURL_SOCKET_BAD) {
-    if(FD_ISSET(readfd1, &fds_read))
-      ret |= CURL_CSELECT_IN2;
-    if(FD_ISSET(readfd1, &fds_err))
-      ret |= CURL_CSELECT_ERR;
-  }
-  if(writefd != CURL_SOCKET_BAD) {
-    if(FD_ISSET(writefd, &fds_write))
-      ret |= CURL_CSELECT_OUT;
-    if(FD_ISSET(writefd, &fds_err))
-      ret |= CURL_CSELECT_ERR;
-  }
-
-  return ret;
-
-#endif  /* HAVE_POLL_FINE */
 
+  return r;
 }
 
 /*
@@ -431,8 +350,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
   }
   if(fds_none) {
     /* no sockets, just wait */
-    r = Curl_wait_ms(timeout_ms);
-    return r;
+    return Curl_wait_ms(timeout_ms);
   }
 
   /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
@@ -454,11 +372,8 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
   else
     pending_ms = 0;
   r = poll(ufds, nfds, pending_ms);
-
-  if(r < 0)
-    return -1;
-  if(r == 0)
-    return 0;
+  if(r <= 0)
+    return r;
 
   for(i = 0; i < nfds; i++) {
     if(ufds[i].fd == CURL_SOCKET_BAD)
@@ -466,7 +381,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
     if(ufds[i].revents & POLLHUP)
       ufds[i].revents |= POLLIN;
     if(ufds[i].revents & POLLERR)
-      ufds[i].revents |= (POLLIN|POLLOUT);
+      ufds[i].revents |= POLLIN|POLLOUT;
   }
 
 #else  /* HAVE_POLL_FINE */
@@ -482,7 +397,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
       continue;
     VERIFY_SOCK(ufds[i].fd);
     if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
-                          POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
+                         POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
       if(ufds[i].fd > maxfd)
         maxfd = ufds[i].fd;
       if(ufds[i].events & (POLLRDNORM|POLLIN))
@@ -494,24 +409,39 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
     }
   }
 
-  r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
-
-  if(r < 0)
-    return -1;
-  if(r == 0)
-    return 0;
+  /*
+     Note also that WinSock ignores the first argument, so we don't worry
+     about the fact that maxfd is computed incorrectly with WinSock (since
+     curl_socket_t is unsigned in such cases and thus -1 is the largest
+     value).
+  */
+  r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
+  if(r <= 0)
+    return r;
 
   r = 0;
   for(i = 0; i < nfds; i++) {
     ufds[i].revents = 0;
     if(ufds[i].fd == CURL_SOCKET_BAD)
       continue;
-    if(FD_ISSET(ufds[i].fd, &fds_read))
-      ufds[i].revents |= POLLIN;
-    if(FD_ISSET(ufds[i].fd, &fds_write))
-      ufds[i].revents |= POLLOUT;
-    if(FD_ISSET(ufds[i].fd, &fds_err))
-      ufds[i].revents |= POLLPRI;
+    if(FD_ISSET(ufds[i].fd, &fds_read)) {
+      if(ufds[i].events & POLLRDNORM)
+        ufds[i].revents |= POLLRDNORM;
+      if(ufds[i].events & POLLIN)
+        ufds[i].revents |= POLLIN;
+    }
+    if(FD_ISSET(ufds[i].fd, &fds_write)) {
+      if(ufds[i].events & POLLWRNORM)
+        ufds[i].revents |= POLLWRNORM;
+      if(ufds[i].events & POLLOUT)
+        ufds[i].revents |= POLLOUT;
+    }
+    if(FD_ISSET(ufds[i].fd, &fds_err)) {
+      if(ufds[i].events & POLLRDBAND)
+        ufds[i].revents |= POLLRDBAND;
+      if(ufds[i].events & POLLPRI)
+        ufds[i].revents |= POLLPRI;
+    }
     if(ufds[i].revents != 0)
       r++;
   }
index 95181f4..4db6487 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -72,12 +72,6 @@ struct pollfd
    therefore defined here */
 #define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1)
 
-int Curl_select(curl_socket_t maxfd,
-                fd_set *fds_read,
-                fd_set *fds_write,
-                fd_set *fds_err,
-                timediff_t timeout_ms);
-
 int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
                       curl_socket_t writefd,
                       timediff_t timeout_ms);
@@ -94,12 +88,23 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
                        fd_set* excepts, struct timeval *tv);
 #endif
 
-/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which
+/* TPF sockets are not in range [0..FD_SETSIZE-1], which
    unfortunately makes it impossible for us to easily check if they're valid
+
+   With Winsock the valid range is [0..INVALID_SOCKET-1] according to
+   https://docs.microsoft.com/en-us/windows/win32/winsock/socket-data-type-2
 */
-#if defined(USE_WINSOCK) || defined(TPF)
+#if defined(TPF)
 #define VALID_SOCK(x) 1
 #define VERIFY_SOCK(x) Curl_nop_stmt
+#elif defined(USE_WINSOCK)
+#define VALID_SOCK(s) ((s) < INVALID_SOCKET)
+#define VERIFY_SOCK(x) do { \
+  if(!VALID_SOCK(x)) { \
+    SET_SOCKERRNO(WSAEINVAL); \
+    return -1; \
+  } \
+} while(0)
 #else
 #define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
 #define VERIFY_SOCK(x) do { \
index 6943fa8..b3c7fe3 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -28,6 +28,8 @@
 
 #ifdef HAVE_LINUX_TCP_H
 #include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
 #endif
 
 #include <curl/curl.h>
@@ -140,7 +142,8 @@ bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
          psnd->recv_size > psnd->recv_processed;
 }
 
-static void pre_receive_plain(struct connectdata *conn, int num)
+static CURLcode pre_receive_plain(struct Curl_easy *data,
+                                  struct connectdata *conn, int num)
 {
   const curl_socket_t sockfd = conn->sock[num];
   struct postponed_data * const psnd = &(conn->postponed[num]);
@@ -159,8 +162,10 @@ static void pre_receive_plain(struct connectdata *conn, int num)
       /* Have some incoming data */
       if(!psnd->buffer) {
         /* Use buffer double default size for intermediate buffer */
-        psnd->allocated_size = 2 * conn->data->set.buffer_size;
+        psnd->allocated_size = 2 * data->set.buffer_size;
         psnd->buffer = malloc(psnd->allocated_size);
+        if(!psnd->buffer)
+          return CURLE_OUT_OF_MEMORY;
         psnd->recv_size = 0;
         psnd->recv_processed = 0;
 #ifdef DEBUGBUILD
@@ -180,6 +185,7 @@ static void pre_receive_plain(struct connectdata *conn, int num)
         psnd->allocated_size = 0;
     }
   }
+  return CURLE_OK;
 }
 
 static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf,
@@ -225,7 +231,7 @@ bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
   (void)sockindex;
   return false;
 }
-#define pre_receive_plain(c,n) do {} while(0)
+#define pre_receive_plain(d,c,n) CURLE_OK
 #define get_pre_recved(c,n,b,l) 0
 #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
 
@@ -262,6 +268,7 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
 
 void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
 {
+  DEBUGASSERT(!strchr(fmt, '\n'));
   if(data->set.verbose || data->set.errorbuffer) {
     va_list ap;
     size_t len;
@@ -274,61 +281,12 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
       strcpy(data->set.errorbuffer, error);
       data->state.errorbuf = TRUE; /* wrote error string */
     }
-    if(data->set.verbose) {
-      error[len] = '\n';
-      error[++len] = '\0';
-      Curl_debug(data, CURLINFO_TEXT, error, len);
-    }
+    error[len++] = '\n';
+    Curl_debug(data, CURLINFO_TEXT, error, len);
     va_end(ap);
   }
 }
 
-/* Curl_sendf() sends formatted data to the server */
-CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
-                    const char *fmt, ...)
-{
-  struct Curl_easy *data = conn->data;
-  ssize_t bytes_written;
-  size_t write_len;
-  CURLcode result = CURLE_OK;
-  char *s;
-  char *sptr;
-  va_list ap;
-  va_start(ap, fmt);
-  s = vaprintf(fmt, ap); /* returns an allocated string */
-  va_end(ap);
-  if(!s)
-    return CURLE_OUT_OF_MEMORY; /* failure */
-
-  bytes_written = 0;
-  write_len = strlen(s);
-  sptr = s;
-
-  for(;;) {
-    /* Write the buffer to the socket */
-    result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
-
-    if(result)
-      break;
-
-    if(data->set.verbose)
-      Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written);
-
-    if((size_t)bytes_written != write_len) {
-      /* if not all was written at once, we must advance the pointer, decrease
-         the size left and try again! */
-      write_len -= bytes_written;
-      sptr += bytes_written;
-    }
-    else
-      break;
-  }
-
-  free(s); /* free the output string */
-
-  return result;
-}
-
 /*
  * Curl_write() is an internal write function that sends data to the
  * server. Works with plain sockets, SCP, SSL or kerberos.
@@ -336,7 +294,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
  * If the write would block (CURLE_AGAIN), we return CURLE_OK and
  * (*written == 0). Otherwise we return regular CURLcode value.
  */
-CURLcode Curl_write(struct connectdata *conn,
+CURLcode Curl_write(struct Curl_easy *data,
                     curl_socket_t sockfd,
                     const void *mem,
                     size_t len,
@@ -344,9 +302,14 @@ CURLcode Curl_write(struct connectdata *conn,
 {
   ssize_t bytes_written;
   CURLcode result = CURLE_OK;
-  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+  struct connectdata *conn;
+  int num;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+  num = (sockfd == conn->sock[SECONDARYSOCKET]);
 
-  bytes_written = conn->send[num](conn, num, mem, len, &result);
+  bytes_written = conn->send[num](data, num, mem, len, &result);
 
   *written = bytes_written;
   if(bytes_written >= 0)
@@ -369,17 +332,26 @@ CURLcode Curl_write(struct connectdata *conn,
   }
 }
 
-ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ssize_t Curl_send_plain(struct Curl_easy *data, int num,
                         const void *mem, size_t len, CURLcode *code)
 {
-  curl_socket_t sockfd = conn->sock[num];
+  struct connectdata *conn;
+  curl_socket_t sockfd;
   ssize_t bytes_written;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+  sockfd = conn->sock[num];
   /* WinSock will destroy unread received data if send() is
      failed.
      To avoid lossage of received data, recv() must be
      performed before every send() if any incoming data is
      available. */
-  pre_receive_plain(conn, num);
+  if(pre_receive_plain(data, conn, num)) {
+    *code = CURLE_OUT_OF_MEMORY;
+    return -1;
+  }
 
 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
   if(conn->bits.tcp_fastopen) {
@@ -413,9 +385,9 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
     }
     else {
       char buffer[STRERROR_LEN];
-      failf(conn->data, "Send failure: %s",
+      failf(data, "Send failure: %s",
             Curl_strerror(err, buffer, sizeof(buffer)));
-      conn->data->state.os_errno = err;
+      data->state.os_errno = err;
       *code = CURLE_SEND_ERROR;
     }
   }
@@ -427,28 +399,33 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
  * server using plain sockets only. Otherwise meant to have the exact same
  * proto as Curl_write()
  */
-CURLcode Curl_write_plain(struct connectdata *conn,
+CURLcode Curl_write_plain(struct Curl_easy *data,
                           curl_socket_t sockfd,
                           const void *mem,
                           size_t len,
                           ssize_t *written)
 {
-  ssize_t bytes_written;
   CURLcode result;
-  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+  struct connectdata *conn = data->conn;
+  int num;
+  DEBUGASSERT(conn);
+  num = (sockfd == conn->sock[SECONDARYSOCKET]);
 
-  bytes_written = Curl_send_plain(conn, num, mem, len, &result);
-
-  *written = bytes_written;
+  *written = Curl_send_plain(data, num, mem, len, &result);
 
   return result;
 }
 
-ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
                         size_t len, CURLcode *code)
 {
-  curl_socket_t sockfd = conn->sock[num];
+  struct connectdata *conn;
+  curl_socket_t sockfd;
   ssize_t nread;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+  sockfd = conn->sock[num];
   /* Check and return data that already received and storied in internal
      intermediate buffer */
   nread = get_pre_recved(conn, num, buf, len);
@@ -479,9 +456,9 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
     }
     else {
       char buffer[STRERROR_LEN];
-      failf(conn->data, "Recv failure: %s",
+      failf(data, "Recv failure: %s",
             Curl_strerror(err, buffer, sizeof(buffer)));
-      conn->data->state.os_errno = err;
+      data->state.os_errno = err;
       *code = CURLE_RECV_ERROR;
     }
   }
@@ -540,12 +517,12 @@ static CURLcode pausewrite(struct Curl_easy *data,
  * client write callback(s) and takes care of pause requests from the
  * callbacks.
  */
-static CURLcode chop_write(struct connectdata *conn,
+static CURLcode chop_write(struct Curl_easy *data,
                            int type,
                            char *optr,
                            size_t olen)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_write_callback writeheader = NULL;
   curl_write_callback writebody = NULL;
   char *ptr = optr;
@@ -635,13 +612,12 @@ static CURLcode chop_write(struct connectdata *conn,
    local character encoding.  This is a problem and should be changed in
    the future to leave the original data alone.
  */
-CURLcode Curl_client_write(struct connectdata *conn,
+CURLcode Curl_client_write(struct Curl_easy *data,
                            int type,
                            char *ptr,
                            size_t len)
 {
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
   if(0 == len)
     len = strlen(ptr);
 
@@ -663,7 +639,7 @@ CURLcode Curl_client_write(struct connectdata *conn,
 #endif /* CURL_DO_LINEEND_CONV */
     }
 
-  return chop_write(conn, type, ptr, len);
+  return chop_write(data, type, ptr, len);
 }
 
 CURLcode Curl_read_plain(curl_socket_t sockfd,
@@ -698,7 +674,7 @@ CURLcode Curl_read_plain(curl_socket_t sockfd,
  *
  * Returns a regular CURLcode value.
  */
-CURLcode Curl_read(struct connectdata *conn, /* connection data */
+CURLcode Curl_read(struct Curl_easy *data,   /* transfer */
                    curl_socket_t sockfd,     /* read from this socket */
                    char *buf,                /* store read data here */
                    size_t sizerequested,     /* max amount to read */
@@ -708,7 +684,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
   ssize_t nread = 0;
   size_t bytesfromsocket = 0;
   char *buffertofill = NULL;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
      If it is the second socket, we set num to 1. Otherwise to 0. This lets
@@ -720,7 +696,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
   bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
   buffertofill = buf;
 
-  nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result);
+  nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
   if(nread < 0)
     return result;
 
@@ -733,72 +709,74 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
 int Curl_debug(struct Curl_easy *data, curl_infotype type,
                char *ptr, size_t size)
 {
-  static const char s_infotype[CURLINFO_END][3] = {
-    "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
   int rc = 0;
+  if(data->set.verbose) {
+    static const char s_infotype[CURLINFO_END][3] = {
+      "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
 
 #ifdef CURL_DOES_CONVERSIONS
-  char *buf = NULL;
-  size_t conv_size = 0;
-
-  switch(type) {
-  case CURLINFO_HEADER_OUT:
-    buf = Curl_memdup(ptr, size);
-    if(!buf)
-      return 1;
-    conv_size = size;
-
-    /* Special processing is needed for this block if it
-     * contains both headers and data (separated by CRLFCRLF).
-     * We want to convert just the headers, leaving the data as-is.
-     */
-    if(size > 4) {
-      size_t i;
-      for(i = 0; i < size-4; i++) {
-        if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
-          /* convert everything through this CRLFCRLF but no further */
-          conv_size = i + 4;
-          break;
+    char *buf = NULL;
+    size_t conv_size = 0;
+
+    switch(type) {
+    case CURLINFO_HEADER_OUT:
+      buf = Curl_memdup(ptr, size);
+      if(!buf)
+        return 1;
+      conv_size = size;
+
+      /* Special processing is needed for this block if it
+       * contains both headers and data (separated by CRLFCRLF).
+       * We want to convert just the headers, leaving the data as-is.
+       */
+      if(size > 4) {
+        size_t i;
+        for(i = 0; i < size-4; i++) {
+          if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
+            /* convert everything through this CRLFCRLF but no further */
+            conv_size = i + 4;
+            break;
+          }
         }
       }
-    }
 
-    Curl_convert_from_network(data, buf, conv_size);
-    /* Curl_convert_from_network calls failf if unsuccessful */
-    /* we might as well continue even if it fails...   */
-    ptr = buf; /* switch pointer to use my buffer instead */
-    break;
-  default:
-    /* leave everything else as-is */
-    break;
-  }
+      Curl_convert_from_network(data, buf, conv_size);
+      /* Curl_convert_from_network calls failf if unsuccessful */
+      /* we might as well continue even if it fails...   */
+      ptr = buf; /* switch pointer to use my buffer instead */
+      break;
+    default:
+      /* leave everything else as-is */
+      break;
+    }
 #endif /* CURL_DOES_CONVERSIONS */
 
-  if(data->set.fdebug) {
-    Curl_set_in_callback(data, true);
-    rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
-    Curl_set_in_callback(data, false);
-  }
-  else {
-    switch(type) {
-    case CURLINFO_TEXT:
-    case CURLINFO_HEADER_OUT:
-    case CURLINFO_HEADER_IN:
-      fwrite(s_infotype[type], 2, 1, data->set.err);
-      fwrite(ptr, size, 1, data->set.err);
+    if(data->set.fdebug) {
+      Curl_set_in_callback(data, true);
+      rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
+      Curl_set_in_callback(data, false);
+    }
+    else {
+      switch(type) {
+      case CURLINFO_TEXT:
+      case CURLINFO_HEADER_OUT:
+      case CURLINFO_HEADER_IN:
+        fwrite(s_infotype[type], 2, 1, data->set.err);
+        fwrite(ptr, size, 1, data->set.err);
 #ifdef CURL_DOES_CONVERSIONS
-      if(size != conv_size) {
-        /* we had untranslated data so we need an explicit newline */
-        fwrite("\n", 1, 1, data->set.err);
-      }
+        if(size != conv_size) {
+          /* we had untranslated data so we need an explicit newline */
+          fwrite("\n", 1, 1, data->set.err);
+        }
 #endif
-      break;
-    default: /* nada */
-      break;
+        break;
+      default: /* nada */
+        break;
+      }
     }
-  }
 #ifdef CURL_DOES_CONVERSIONS
-  free(buf);
+    free(buf);
 #endif
+  }
   return rc;
 }
index c68b017..108a5e9 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -24,8 +24,6 @@
 
 #include "curl_setup.h"
 
-CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
-                    const char *fmt, ...);
 void Curl_infof(struct Curl_easy *, const char *fmt, ...);
 void Curl_failf(struct Curl_easy *, const char *fmt, ...);
 
@@ -51,7 +49,7 @@ void Curl_failf(struct Curl_easy *, const char *fmt, ...);
 #define CLIENTWRITE_HEADER (1<<1)
 #define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
 
-CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
+CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
                            size_t len) WARN_UNUSED_RESULT;
 
 bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex);
@@ -62,23 +60,24 @@ CURLcode Curl_read_plain(curl_socket_t sockfd,
                          size_t bytesfromsocket,
                          ssize_t *n);
 
-ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
                         size_t len, CURLcode *code);
-ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ssize_t Curl_send_plain(struct Curl_easy *data, int num,
                         const void *mem, size_t len, CURLcode *code);
 
 /* internal read-function, does plain socket, SSL and krb4 */
-CURLcode Curl_read(struct connectdata *conn, curl_socket_t sockfd,
+CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd,
                    char *buf, size_t buffersize,
                    ssize_t *n);
+
 /* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
-CURLcode Curl_write(struct connectdata *conn,
+CURLcode Curl_write(struct Curl_easy *data,
                     curl_socket_t sockfd,
                     const void *mem, size_t len,
                     ssize_t *written);
 
 /* internal write-function, does plain sockets ONLY */
-CURLcode Curl_write_plain(struct connectdata *conn,
+CURLcode Curl_write_plain(struct Curl_easy *data,
                           curl_socket_t sockfd,
                           const void *mem, size_t len,
                           ssize_t *written);
index d621335..ce73a34 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -30,6 +30,8 @@
 
 #ifdef HAVE_LINUX_TCP_H
 #include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
 #endif
 
 #include "urldata.h"
@@ -45,6 +47,7 @@
 #include "setopt.h"
 #include "multiif.h"
 #include "altsvc.h"
+#include "hsts.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -271,11 +274,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * Do not include the body part in the output data stream.
      */
     data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
+#ifndef CURL_DISABLE_HTTP
     if(data->set.opt_no_body)
       /* in HTTP lingo, no body means using the HEAD request... */
       data->set.method = HTTPREQ_HEAD;
     else if(data->set.method == HTTPREQ_HEAD)
       data->set.method = HTTPREQ_GET;
+#endif
     break;
   case CURLOPT_FAILONERROR:
     /*
@@ -430,104 +435,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       primary->version_max = version_max;
     }
 #else
-    result = CURLE_UNKNOWN_OPTION;
+    result = CURLE_NOT_BUILT_IN;
 #endif
     break;
 
-#ifndef CURL_DISABLE_HTTP
-  case CURLOPT_AUTOREFERER:
-    /*
-     * Switch on automatic referer that gets set if curl follows locations.
-     */
-    data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_ACCEPT_ENCODING:
-    /*
-     * String to use at the value of Accept-Encoding header.
-     *
-     * If the encoding is set to "" we use an Accept-Encoding header that
-     * encompasses all the encodings we support.
-     * If the encoding is set to NULL we don't send an Accept-Encoding header
-     * and ignore an received Content-Encoding header.
-     *
-     */
-    argptr = va_arg(param, char *);
-    if(argptr && !*argptr) {
-      argptr = Curl_all_content_encodings();
-      if(!argptr)
-        result = CURLE_OUT_OF_MEMORY;
-      else {
-        result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
-        free(argptr);
-      }
-    }
-    else
-      result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
-    break;
-
-  case CURLOPT_TRANSFER_ENCODING:
-    data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
-      TRUE : FALSE;
-    break;
-
-  case CURLOPT_FOLLOWLOCATION:
-    /*
-     * Follow Location: header hints on a HTTP-server.
-     */
-    data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_UNRESTRICTED_AUTH:
-    /*
-     * Send authentication (user+password) when following locations, even when
-     * hostname changed.
-     */
-    data->set.allow_auth_to_other_hosts =
-      (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_MAXREDIRS:
-    /*
-     * The maximum amount of hops you allow curl to follow Location:
-     * headers. This should mostly be used to detect never-ending loops.
-     */
-    arg = va_arg(param, long);
-    if(arg < -1)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.maxredirs = arg;
-    break;
-
-  case CURLOPT_POSTREDIR:
-    /*
-     * Set the behaviour of POST when redirecting
-     * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
-     * CURL_REDIR_POST_301 - POST is kept as POST after 301
-     * CURL_REDIR_POST_302 - POST is kept as POST after 302
-     * CURL_REDIR_POST_303 - POST is kept as POST after 303
-     * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
-     * other - POST is kept as POST after 301 and 302
-     */
-    arg = va_arg(param, long);
-    if(arg < CURL_REDIR_GET_ALL)
-      /* no return error on too high numbers since the bitmask could be
-         extended in a future */
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.keep_post = arg & CURL_REDIR_POST_ALL;
-    break;
-
-  case CURLOPT_POST:
-    /* Does this option serve a purpose anymore? Yes it does, when
-       CURLOPT_POSTFIELDS isn't used and the POST data is read off the
-       callback! */
-    if(va_arg(param, long)) {
-      data->set.method = HTTPREQ_POST;
-      data->set.opt_no_body = FALSE; /* this is implied */
-    }
-    else
-      data->set.method = HTTPREQ_GET;
-    break;
-
+    /* MQTT "borrows" some of the HTTP options */
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
   case CURLOPT_COPYPOSTFIELDS:
     /*
      * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
@@ -622,6 +535,100 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 
     data->set.postfieldsize = bigsize;
     break;
+#endif
+#ifndef CURL_DISABLE_HTTP
+  case CURLOPT_AUTOREFERER:
+    /*
+     * Switch on automatic referer that gets set if curl follows locations.
+     */
+    data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_ACCEPT_ENCODING:
+    /*
+     * String to use at the value of Accept-Encoding header.
+     *
+     * If the encoding is set to "" we use an Accept-Encoding header that
+     * encompasses all the encodings we support.
+     * If the encoding is set to NULL we don't send an Accept-Encoding header
+     * and ignore an received Content-Encoding header.
+     *
+     */
+    argptr = va_arg(param, char *);
+    if(argptr && !*argptr) {
+      argptr = Curl_all_content_encodings();
+      if(!argptr)
+        result = CURLE_OUT_OF_MEMORY;
+      else {
+        result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+        free(argptr);
+      }
+    }
+    else
+      result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+    break;
+
+  case CURLOPT_TRANSFER_ENCODING:
+    data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
+      TRUE : FALSE;
+    break;
+
+  case CURLOPT_FOLLOWLOCATION:
+    /*
+     * Follow Location: header hints on a HTTP-server.
+     */
+    data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_UNRESTRICTED_AUTH:
+    /*
+     * Send authentication (user+password) when following locations, even when
+     * hostname changed.
+     */
+    data->set.allow_auth_to_other_hosts =
+      (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_MAXREDIRS:
+    /*
+     * The maximum amount of hops you allow curl to follow Location:
+     * headers. This should mostly be used to detect never-ending loops.
+     */
+    arg = va_arg(param, long);
+    if(arg < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.maxredirs = arg;
+    break;
+
+  case CURLOPT_POSTREDIR:
+    /*
+     * Set the behavior of POST when redirecting
+     * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+     * CURL_REDIR_POST_301 - POST is kept as POST after 301
+     * CURL_REDIR_POST_302 - POST is kept as POST after 302
+     * CURL_REDIR_POST_303 - POST is kept as POST after 303
+     * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
+     * other - POST is kept as POST after 301 and 302
+     */
+    arg = va_arg(param, long);
+    if(arg < CURL_REDIR_GET_ALL)
+      /* no return error on too high numbers since the bitmask could be
+         extended in a future */
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.keep_post = arg & CURL_REDIR_POST_ALL;
+    break;
+
+  case CURLOPT_POST:
+    /* Does this option serve a purpose anymore? Yes it does, when
+       CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+       callback! */
+    if(va_arg(param, long)) {
+      data->set.method = HTTPREQ_POST;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    else
+      data->set.method = HTTPREQ_GET;
+    break;
 
   case CURLOPT_HTTPPOST:
     /*
@@ -631,6 +638,21 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.method = HTTPREQ_POST_FORM;
     data->set.opt_no_body = FALSE; /* this is implied */
     break;
+
+  case CURLOPT_AWS_SIGV4:
+    /*
+     * String that is merged to some authentication
+     * parameters are used by the algorithm.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4],
+                            va_arg(param, char *));
+    /*
+     * Basic been set by default it need to be unset here
+     */
+    if(data->set.str[STRING_AWS_SIGV4])
+      data->set.httpauth = CURLAUTH_AWS_SIGV4;
+    break;
+
 #endif   /* CURL_DISABLE_HTTP */
 
   case CURLOPT_MIMEPOST:
@@ -720,6 +742,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     argptr = (char *)va_arg(param, void *);
     if(argptr) {
       struct curl_slist *cl;
+      /* general protection against mistakes and abuse */
+      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
       /* append the cookie file name to the list of file names, and deal with
          them later */
       cl = curl_slist_append(data->change.cookielist, argptr);
@@ -804,6 +829,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
         /* if cookie engine was not running, activate it */
         data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
 
+      /* general protection against mistakes and abuse */
+      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
+        return CURLE_BAD_FUNCTION_ARGUMENT;
       argptr = strdup(argptr);
       if(!argptr || !data->cookies) {
         result = CURLE_OUT_OF_MEMORY;
@@ -854,7 +882,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       ;
     else
 #endif
-#ifndef USE_NGHTTP2
+#if !defined(USE_NGHTTP2) && !defined(USE_HYPER)
     if(arg >= CURL_HTTP_VERSION_2)
       return CURLE_UNSUPPORTED_PROTOCOL;
 #else
@@ -1069,7 +1097,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       break;
     default:
       /* reserve other values for future use */
-      result = CURLE_UNKNOWN_OPTION;
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
       break;
     }
     break;
@@ -1222,21 +1250,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * An FTP/SFTP option that modifies an upload to create missing
      * directories on the server.
      */
-    switch(va_arg(param, long)) {
-    case 0:
-      data->set.ftp_create_missing_dirs = 0;
-      break;
-    case 1:
-      data->set.ftp_create_missing_dirs = 1;
-      break;
-    case 2:
-      data->set.ftp_create_missing_dirs = 2;
-      break;
-    default:
-      /* reserve other values for future use */
-      result = CURLE_UNKNOWN_OPTION;
-      break;
-    }
+    arg = va_arg(param, long);
+    /* reserve other values for future use */
+    if((arg < CURLFTP_CREATE_DIR_NONE) ||
+       (arg > CURLFTP_CREATE_DIR_RETRY))
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
+    else
+      data->set.ftp_create_missing_dirs = (int)arg;
     break;
   case CURLOPT_READDATA:
     /*
@@ -1441,13 +1461,16 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_RESOLVE:
     /*
-     * List of NAME:[address] names to populate the DNS cache with
-     * Prefix the NAME with dash (-) to _remove_ the name from the cache.
-     *
-     * Names added with this API will remain in the cache until explicitly
+     * List of HOST:PORT:[addresses] strings to populate the DNS cache with
+     * Entries added this way will remain in the cache until explicitly
      * removed or the handle is cleaned up.
      *
-     * This API can remove any name from the DNS cache, but only entries
+     * Prefix the HOST with plus sign (+) to have the entry expire just like
+     * automatically added entries.
+     *
+     * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
+     *
+     * This API can remove any entry from the DNS cache, but only entries
      * that aren't actually in use right now will be pruned immediately.
      */
     data->set.resolve = va_arg(param, struct curl_slist *);
@@ -2075,6 +2098,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * The application kindly asks for a differently sized receive buffer.
      * If it seems reasonable, we'll use it.
      */
+    if(data->state.buffer)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
     arg = va_arg(param, long);
 
     if(arg > READBUFFER_MAX)
@@ -2084,18 +2110,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     else if(arg < READBUFFER_MIN)
       arg = READBUFFER_MIN;
 
-    /* Resize if new size */
-    if((arg != data->set.buffer_size) && data->state.buffer) {
-      char *newbuff = realloc(data->state.buffer, arg + 1);
-      if(!newbuff) {
-        DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
-        result = CURLE_OUT_OF_MEMORY;
-      }
-      else
-        data->state.buffer = newbuff;
-    }
     data->set.buffer_size = arg;
-
     break;
 
   case CURLOPT_UPLOAD_BUFFERSIZE:
@@ -2155,8 +2170,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       data->share = NULL;
     }
 
-    /* use new share if it set */
-    data->share = set;
+    if(GOOD_SHARE_HANDLE(set))
+      /* use new share if it set */
+      data->share = set;
     if(data->share) {
 
       Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
@@ -2243,12 +2259,20 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
 #endif
 
+  case CURLOPT_SSL_EC_CURVES:
+    /*
+     * Set accepted curves in SSL connection setup.
+     * Specify colon-delimited list of curve algorithm names.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES],
+                            va_arg(param, char *));
+    break;
 #endif
   case CURLOPT_IPRESOLVE:
     arg = va_arg(param, long);
     if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6))
       return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.ipver = arg;
+    data->set.ipver = (unsigned char) arg;
     break;
 
   case CURLOPT_MAXFILESIZE_LARGE:
@@ -2513,9 +2537,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
      * Would this be better if the RTSPREQ_* were just moved into here?
      */
-    long curl_rtspreq = va_arg(param, long);
+    long in_rtspreq = va_arg(param, long);
     Curl_RtspReq rtspreq = RTSPREQ_NONE;
-    switch(curl_rtspreq) {
+    switch(in_rtspreq) {
     case CURL_RTSPREQ_OPTIONS:
       rtspreq = RTSPREQ_OPTIONS;
       break;
@@ -2839,7 +2863,46 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.trailer_data = va_arg(param, void *);
 #endif
     break;
-#ifdef USE_ALTSVC
+#ifdef USE_HSTS
+  case CURLOPT_HSTSREADFUNCTION:
+    data->set.hsts_read = va_arg(param, curl_hstsread_callback);
+    break;
+  case CURLOPT_HSTSREADDATA:
+    data->set.hsts_read_userp = va_arg(param, void *);
+    break;
+  case CURLOPT_HSTSWRITEFUNCTION:
+    data->set.hsts_write = va_arg(param, curl_hstswrite_callback);
+    break;
+  case CURLOPT_HSTSWRITEDATA:
+    data->set.hsts_write_userp = va_arg(param, void *);
+    break;
+  case CURLOPT_HSTS:
+    if(!data->hsts) {
+      data->hsts = Curl_hsts_init();
+      if(!data->hsts)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    argptr = va_arg(param, char *);
+    result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
+    if(result)
+      return result;
+    if(argptr)
+      (void)Curl_hsts_loadfile(data, data->hsts, argptr);
+    break;
+  case CURLOPT_HSTS_CTRL:
+    arg = va_arg(param, long);
+    if(arg & CURLHSTS_ENABLE) {
+      if(!data->hsts) {
+        data->hsts = Curl_hsts_init();
+        if(!data->hsts)
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else
+      Curl_hsts_cleanup(&data->hsts);
+    break;
+#endif
+#ifndef CURL_DISABLE_ALTSVC
   case CURLOPT_ALTSVC:
     if(!data->asi) {
       data->asi = Curl_altsvc_init();
index 5fc4368..affbfd9 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index b693cb3..8c97371 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 0e39c9f..ba75dc2 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 45b5847..c35dec8 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -60,7 +60,6 @@
 
 /*
  * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
- * define USE_WINSOCK to 1 if we have and use WINSOCK  API, else
  * undefine USE_WINSOCK.
  */
 
@@ -70,7 +69,7 @@
 #  define USE_WINSOCK 2
 #else
 #  ifdef HAVE_WINSOCK_H
-#    define USE_WINSOCK 1
+#    error "WinSock version 1 is no longer supported, version 2 is required!"
 #  endif
 #endif
 
index ee5d273..d915117 100644 (file)
@@ -10,7 +10,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -27,6 +27,7 @@
 
 #include "warnless.h"
 #include "curl_sha256.h"
+#include "curl_hmac.h"
 
 #if defined(USE_OPENSSL)
 
@@ -343,11 +344,14 @@ static int sha256_compress(struct sha256_state *md,
   }
 
   /* Compress */
-#define RND(a,b,c,d,e,f,g,h,i)                                  \
-  unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
-  unsigned long t1 = Sigma0(a) + Maj(a, b, c);                  \
-  d += t0;                                                      \
-  h = t0 + t1;
+#define RND(a,b,c,d,e,f,g,h,i)                                          \
+  do {                                                                  \
+    unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];       \
+    unsigned long t1 = Sigma0(a) + Maj(a, b, c);                        \
+    d += t0;                                                            \
+    h = t0 + t1;                                                        \
+  } while(0)
+
   for(i = 0; i < 64; ++i) {
     unsigned long t;
     RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
@@ -491,4 +495,23 @@ void Curl_sha256it(unsigned char *output, const unsigned char *input,
   SHA256_Final(output, &ctx);
 }
 
+
+const struct HMAC_params Curl_HMAC_SHA256[] = {
+  {
+    /* Hash initialization function. */
+    CURLX_FUNCTION_CAST(HMAC_hinit_func, SHA256_Init),
+    /* Hash update function. */
+    CURLX_FUNCTION_CAST(HMAC_hupdate_func, SHA256_Update),
+    /* Hash computation end function. */
+    CURLX_FUNCTION_CAST(HMAC_hfinal_func, SHA256_Final),
+    /* Size of hash context structure. */
+    sizeof(SHA256_CTX),
+    /* Maximum key length. */
+    64,
+    /* Result size. */
+    32
+  }
+};
+
+
 #endif /* CURL_DISABLE_CRYPTO_AUTH */
index a2d8960..4f1804d 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -37,6 +37,7 @@ curl_share_init(void)
 {
   struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
   if(share) {
+    share->magic = CURL_GOOD_SHARE;
     share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
 
     if(Curl_mk_dnscache(&share->hostcache)) {
@@ -59,6 +60,9 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
   void *ptr;
   CURLSHcode res = CURLSHE_OK;
 
+  if(!GOOD_SHARE_HANDLE(share))
+    return CURLSHE_INVALID;
+
   if(share->dirty)
     /* don't allow setting options while one or more handles are already
        using this share */
@@ -92,7 +96,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
       if(!share->sslsession) {
         share->max_ssl_sessions = 8;
         share->sslsession = calloc(share->max_ssl_sessions,
-                                   sizeof(struct curl_ssl_session));
+                                   sizeof(struct Curl_ssl_session));
         share->sessionage = 0;
         if(!share->sslsession)
           res = CURLSHE_NOMEM;
@@ -184,7 +188,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
 CURLSHcode
 curl_share_cleanup(struct Curl_share *share)
 {
-  if(share == NULL)
+  if(!GOOD_SHARE_HANDLE(share))
     return CURLSHE_INVALID;
 
   if(share->lockfunc)
@@ -218,6 +222,7 @@ curl_share_cleanup(struct Curl_share *share)
 
   if(share->unlockfunc)
     share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+  share->magic = 0;
   free(share);
 
   return CURLSHE_OK;
index a7dea41..222e34b 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #define CURL_VOLATILE volatile
 #endif
 
+#define CURL_GOOD_SHARE 0x7e117a1e
+#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE)
+
 /* this struct is libcurl-private, don't export details */
 struct Curl_share {
+  unsigned int magic; /* CURL_GOOD_SHARE */
   unsigned int specifier;
   CURL_VOLATILE unsigned int dirty;
 
@@ -46,7 +50,7 @@ struct Curl_share {
   curl_unlock_function unlockfunc;
   void *clientdata;
   struct conncache conn_cache;
-  struct curl_hash hostcache;
+  struct Curl_hash hostcache;
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
   struct CookieInfo *cookies;
 #endif
@@ -54,7 +58,7 @@ struct Curl_share {
   struct PslCache psl;
 #endif
 
-  struct curl_ssl_session *sslsession;
+  struct Curl_ssl_session *sslsession;
   size_t max_ssl_sessions;
   long sessionage;
 };
index 3960a13..430cfc6 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index d27fbe1..907c203 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 799b3c0..3114259 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index d493adc..dd4e4fd 100644 (file)
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2016 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
- * Copyright (C) 2016-2020, 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.haxx.se/docs/copyright.html.
+ * 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
 
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) &&  \
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) &&  \
   (CURL_SIZEOF_CURL_OFF_T > 4)
 
-#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
-
 #define BUILDING_CURL_SMB_C
 
 #ifdef HAVE_PROCESS_H
 #include "memdebug.h"
 
 /* Local API functions */
-static CURLcode smb_setup_connection(struct connectdata *conn);
-static CURLcode smb_connect(struct connectdata *conn, bool *done);
-static CURLcode smb_connection_state(struct connectdata *conn, bool *done);
-static CURLcode smb_do(struct connectdata *conn, bool *done);
-static CURLcode smb_request_state(struct connectdata *conn, bool *done);
-static CURLcode smb_done(struct connectdata *conn, CURLcode status,
+static CURLcode smb_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn);
+static CURLcode smb_connect(struct Curl_easy *data, bool *done);
+static CURLcode smb_connection_state(struct Curl_easy *data, bool *done);
+static CURLcode smb_do(struct Curl_easy *data, bool *done);
+static CURLcode smb_request_state(struct Curl_easy *data, bool *done);
+static CURLcode smb_done(struct Curl_easy *data, CURLcode status,
                          bool premature);
-static CURLcode smb_disconnect(struct connectdata *conn, bool dead);
-static int smb_getsock(struct connectdata *conn, curl_socket_t *socks);
-static CURLcode smb_parse_url_path(struct connectdata *conn);
+static CURLcode smb_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead);
+static int smb_getsock(struct Curl_easy *data, struct connectdata *conn,
+                       curl_socket_t *socks);
+static CURLcode smb_parse_url_path(struct Curl_easy *data,
+                                   struct connectdata *conn);
 
 /*
  * SMB handler interface
@@ -88,6 +90,7 @@ const struct Curl_handler Curl_handler_smb = {
   ZERO_NULL,                            /* connection_check */
   PORT_SMB,                             /* defport */
   CURLPROTO_SMB,                        /* protocol */
+  CURLPROTO_SMB,                        /* family */
   PROTOPT_NONE                          /* flags */
 };
 
@@ -113,6 +116,7 @@ const struct Curl_handler Curl_handler_smbs = {
   ZERO_NULL,                            /* connection_check */
   PORT_SMBS,                            /* defport */
   CURLPROTO_SMBS,                       /* protocol */
+  CURLPROTO_SMB,                        /* family */
   PROTOPT_SSL                           /* flags */
 };
 #endif
@@ -124,13 +128,17 @@ const struct Curl_handler Curl_handler_smbs = {
 
 /* Append a string to an SMB message */
 #define MSGCAT(str)                             \
-  strcpy(p, (str));                             \
-  p += strlen(str);
+  do {                                          \
+    strcpy(p, (str));                           \
+    p += strlen(str);                           \
+  } while(0)
 
 /* Append a null-terminated string to an SMB message */
 #define MSGCATNULL(str)                         \
-  strcpy(p, (str));                             \
-  p += strlen(str) + 1;
+  do {                                          \
+    strcpy(p, (str));                           \
+    p += strlen(str) + 1;                       \
+  } while(0)
 
 /* SMB is mostly little endian */
 #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
@@ -179,9 +187,9 @@ struct smb_request {
   CURLcode result;
 };
 
-static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
+static void conn_state(struct Curl_easy *data, enum smb_conn_state newstate)
 {
-  struct smb_conn *smbc = &conn->proto.smbc;
+  struct smb_conn *smbc = &data->conn->proto.smbc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* For debug purposes */
   static const char * const names[] = {
@@ -194,17 +202,17 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
   };
 
   if(smbc->state != newstate)
-    infof(conn->data, "SMB conn %p state change from %s to %s\n",
+    infof(data, "SMB conn %p state change from %s to %s\n",
           (void *)smbc, names[smbc->state], names[newstate]);
 #endif
 
   smbc->state = newstate;
 }
 
-static void request_state(struct connectdata *conn,
+static void request_state(struct Curl_easy *data,
                           enum smb_req_state newstate)
 {
-  struct smb_request *req = conn->data->req.protop;
+  struct smb_request *req = data->req.p.smb;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* For debug purposes */
   static const char * const names[] = {
@@ -220,7 +228,7 @@ static void request_state(struct connectdata *conn,
   };
 
   if(req->state != newstate)
-    infof(conn->data, "SMB request %p state change from %s to %s\n",
+    infof(data, "SMB request %p state change from %s to %s\n",
           (void *)req, names[req->state], names[newstate]);
 #endif
 
@@ -229,21 +237,23 @@ static void request_state(struct connectdata *conn,
 
 /* this should setup things in the connection, not in the easy
    handle */
-static CURLcode smb_setup_connection(struct connectdata *conn)
+static CURLcode smb_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn)
 {
   struct smb_request *req;
 
   /* Initialize the request state */
-  conn->data->req.protop = req = calloc(1, sizeof(struct smb_request));
+  data->req.p.smb = req = calloc(1, sizeof(struct smb_request));
   if(!req)
     return CURLE_OUT_OF_MEMORY;
 
   /* Parse the URL path */
-  return smb_parse_url_path(conn);
+  return smb_parse_url_path(data, conn);
 }
 
-static CURLcode smb_connect(struct connectdata *conn, bool *done)
+static CURLcode smb_connect(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *slash;
 
@@ -284,8 +294,9 @@ static CURLcode smb_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode smb_recv_message(struct connectdata *conn, void **msg)
+static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *buf = smbc->recv_buf;
   ssize_t bytes_read;
@@ -294,7 +305,7 @@ static CURLcode smb_recv_message(struct connectdata *conn, void **msg)
   size_t len = MAX_MESSAGE_SIZE - smbc->got;
   CURLcode result;
 
-  result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
+  result = Curl_read(data, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
   if(result)
     return result;
 
@@ -338,11 +349,12 @@ static void smb_pop_message(struct connectdata *conn)
   smbc->got = 0;
 }
 
-static void smb_format_message(struct connectdata *conn, struct smb_header *h,
+static void smb_format_message(struct Curl_easy *data, struct smb_header *h,
                                unsigned char cmd, size_t len)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
-  struct smb_request *req = conn->data->req.protop;
+  struct smb_request *req = data->req.p.smb;
   unsigned int pid;
 
   memset(h, 0, sizeof(*h));
@@ -359,14 +371,15 @@ static void smb_format_message(struct connectdata *conn, struct smb_header *h,
   h->pid = smb_swap16((unsigned short) pid);
 }
 
-static CURLcode smb_send(struct connectdata *conn, ssize_t len,
+static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
                          size_t upload_size)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   CURLcode result;
 
-  result = Curl_write(conn, FIRSTSOCKET, conn->data->state.ulbuf,
+  result = Curl_write(data, FIRSTSOCKET, data->state.ulbuf,
                       len, &bytes_written);
   if(result)
     return result;
@@ -381,8 +394,9 @@ static CURLcode smb_send(struct connectdata *conn, ssize_t len,
   return CURLE_OK;
 }
 
-static CURLcode smb_flush(struct connectdata *conn)
+static CURLcode smb_flush(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   ssize_t len = smbc->send_size - smbc->sent;
@@ -391,8 +405,8 @@ static CURLcode smb_flush(struct connectdata *conn)
   if(!smbc->send_size)
     return CURLE_OK;
 
-  result = Curl_write(conn, FIRSTSOCKET,
-                      conn->data->state.ulbuf + smbc->sent,
+  result = Curl_write(data, FIRSTSOCKET,
+                      data->state.ulbuf + smbc->sent,
                       len, &bytes_written);
   if(result)
     return result;
@@ -405,29 +419,30 @@ static CURLcode smb_flush(struct connectdata *conn)
   return CURLE_OK;
 }
 
-static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd,
+static CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd,
                                  const void *msg, size_t msg_len)
 {
-  CURLcode result = Curl_get_upload_buffer(conn->data);
+  CURLcode result = Curl_get_upload_buffer(data);
   if(result)
     return result;
-  smb_format_message(conn, (struct smb_header *)conn->data->state.ulbuf,
+  smb_format_message(data, (struct smb_header *)data->state.ulbuf,
                      cmd, msg_len);
-  memcpy(conn->data->state.ulbuf + sizeof(struct smb_header),
+  memcpy(data->state.ulbuf + sizeof(struct smb_header),
          msg, msg_len);
 
-  return smb_send(conn, sizeof(struct smb_header) + msg_len, 0);
+  return smb_send(data, sizeof(struct smb_header) + msg_len, 0);
 }
 
-static CURLcode smb_send_negotiate(struct connectdata *conn)
+static CURLcode smb_send_negotiate(struct Curl_easy *data)
 {
   const char *msg = "\x00\x0c\x00\x02NT LM 0.12";
 
-  return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15);
+  return smb_send_message(data, SMB_COM_NEGOTIATE, msg, 15);
 }
 
-static CURLcode smb_send_setup(struct connectdata *conn)
+static CURLcode smb_send_setup(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   struct smb_setup msg;
   char *p = msg.bytes;
@@ -442,10 +457,10 @@ static CURLcode smb_send_setup(struct connectdata *conn)
   if(byte_count > sizeof(msg.bytes))
     return CURLE_FILESIZE_EXCEEDED;
 
-  Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash);
+  Curl_ntlm_core_mk_lm_hash(data, conn->passwd, lm_hash);
   Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm);
 #ifdef USE_NTRESPONSES
-  Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash);
+  Curl_ntlm_core_mk_nt_hash(data, conn->passwd, nt_hash);
   Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);
 #else
   memset(nt, 0, sizeof(nt));
@@ -472,13 +487,14 @@ static CURLcode smb_send_setup(struct connectdata *conn)
   byte_count = p - msg.bytes;
   msg.byte_count = smb_swap16((unsigned short)byte_count);
 
-  return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg,
+  return smb_send_message(data, SMB_COM_SETUP_ANDX, &msg,
                           sizeof(msg) - sizeof(msg.bytes) + byte_count);
 }
 
-static CURLcode smb_send_tree_connect(struct connectdata *conn)
+static CURLcode smb_send_tree_connect(struct Curl_easy *data)
 {
   struct smb_tree_connect msg;
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *p = msg.bytes;
 
@@ -499,13 +515,13 @@ static CURLcode smb_send_tree_connect(struct connectdata *conn)
   byte_count = p - msg.bytes;
   msg.byte_count = smb_swap16((unsigned short)byte_count);
 
-  return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg,
+  return smb_send_message(data, SMB_COM_TREE_CONNECT_ANDX, &msg,
                           sizeof(msg) - sizeof(msg.bytes) + byte_count);
 }
 
-static CURLcode smb_send_open(struct connectdata *conn)
+static CURLcode smb_send_open(struct Curl_easy *data)
 {
-  struct smb_request *req = conn->data->req.protop;
+  struct smb_request *req = data->req.p.smb;
   struct smb_nt_create msg;
   size_t byte_count;
 
@@ -518,7 +534,7 @@ static CURLcode smb_send_open(struct connectdata *conn)
   byte_count = strlen(req->path);
   msg.name_length = smb_swap16((unsigned short)byte_count);
   msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL);
-  if(conn->data->set.upload) {
+  if(data->set.upload) {
     msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE);
     msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF);
   }
@@ -529,35 +545,35 @@ static CURLcode smb_send_open(struct connectdata *conn)
   msg.byte_count = smb_swap16((unsigned short) ++byte_count);
   strcpy(msg.bytes, req->path);
 
-  return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg,
+  return smb_send_message(data, SMB_COM_NT_CREATE_ANDX, &msg,
                           sizeof(msg) - sizeof(msg.bytes) + byte_count);
 }
 
-static CURLcode smb_send_close(struct connectdata *conn)
+static CURLcode smb_send_close(struct Curl_easy *data)
 {
-  struct smb_request *req = conn->data->req.protop;
+  struct smb_request *req = data->req.p.smb;
   struct smb_close msg;
 
   memset(&msg, 0, sizeof(msg));
   msg.word_count = SMB_WC_CLOSE;
   msg.fid = smb_swap16(req->fid);
 
-  return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg));
+  return smb_send_message(data, SMB_COM_CLOSE, &msg, sizeof(msg));
 }
 
-static CURLcode smb_send_tree_disconnect(struct connectdata *conn)
+static CURLcode smb_send_tree_disconnect(struct Curl_easy *data)
 {
   struct smb_tree_disconnect msg;
 
   memset(&msg, 0, sizeof(msg));
 
-  return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg));
+  return smb_send_message(data, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg));
 }
 
-static CURLcode smb_send_read(struct connectdata *conn)
+static CURLcode smb_send_read(struct Curl_easy *data)
 {
-  struct smb_request *req = conn->data->req.protop;
-  curl_off_t offset = conn->data->req.offset;
+  struct smb_request *req = data->req.p.smb;
+  curl_off_t offset = data->req.offset;
   struct smb_read msg;
 
   memset(&msg, 0, sizeof(msg));
@@ -569,19 +585,19 @@ static CURLcode smb_send_read(struct connectdata *conn)
   msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
   msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
 
-  return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg));
+  return smb_send_message(data, SMB_COM_READ_ANDX, &msg, sizeof(msg));
 }
 
-static CURLcode smb_send_write(struct connectdata *conn)
+static CURLcode smb_send_write(struct Curl_easy *data)
 {
   struct smb_write *msg;
-  struct smb_request *req = conn->data->req.protop;
-  curl_off_t offset = conn->data->req.offset;
-  curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
-  CURLcode result = Curl_get_upload_buffer(conn->data);
+  struct smb_request *req = data->req.p.smb;
+  curl_off_t offset = data->req.offset;
+  curl_off_t upload_size = data->req.size - data->req.bytecount;
+  CURLcode result = Curl_get_upload_buffer(data);
   if(result)
     return result;
-  msg = (struct smb_write *)conn->data->state.ulbuf;
+  msg = (struct smb_write *)data->state.ulbuf;
 
   if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
     upload_size = MAX_PAYLOAD_SIZE - 1;
@@ -596,25 +612,26 @@ static CURLcode smb_send_write(struct connectdata *conn)
   msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int));
   msg->byte_count = smb_swap16((unsigned short) (upload_size + 1));
 
-  smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX,
+  smb_format_message(data, &msg->h, SMB_COM_WRITE_ANDX,
                      sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size);
 
-  return smb_send(conn, sizeof(*msg), (size_t) upload_size);
+  return smb_send(data, sizeof(*msg), (size_t) upload_size);
 }
 
-static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
+static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   CURLcode result;
   *msg = NULL; /* if it returns early */
 
   /* Check if there is data in the transfer buffer */
   if(!smbc->send_size && smbc->upload_size) {
-    size_t nread = smbc->upload_size > conn->data->set.upload_buffer_size ?
-      conn->data->set.upload_buffer_size :
+    size_t nread = smbc->upload_size > data->set.upload_buffer_size ?
+      data->set.upload_buffer_size :
       smbc->upload_size;
-    conn->data->req.upload_fromhere = conn->data->state.ulbuf;
-    result = Curl_fillreadbuffer(conn, nread, &nread);
+    data->req.upload_fromhere = data->state.ulbuf;
+    result = Curl_fillreadbuffer(data, nread, &nread);
     if(result && result != CURLE_AGAIN)
       return result;
     if(!nread)
@@ -627,7 +644,7 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
 
   /* Check if there is data to send */
   if(smbc->send_size) {
-    result = smb_flush(conn);
+    result = smb_flush(data);
     if(result)
       return result;
   }
@@ -636,11 +653,12 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
   if(smbc->send_size || smbc->upload_size)
     return CURLE_AGAIN;
 
-  return smb_recv_message(conn, msg);
+  return smb_recv_message(data, msg);
 }
 
-static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
+static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   struct smb_negotiate_response *nrsp;
   struct smb_header *h;
@@ -651,7 +669,8 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
 #ifdef USE_SSL
     if((conn->handler->flags & PROTOPT_SSL)) {
       bool ssl_done = FALSE;
-      result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done);
+      result = Curl_ssl_connect_nonblocking(data, conn,
+                                            FIRSTSOCKET, &ssl_done);
       if(result && result != CURLE_AGAIN)
         return result;
       if(!ssl_done)
@@ -659,17 +678,17 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
     }
 #endif
 
-    result = smb_send_negotiate(conn);
+    result = smb_send_negotiate(data);
     if(result) {
       connclose(conn, "SMB: failed to send negotiate message");
       return result;
     }
 
-    conn_state(conn, SMB_NEGOTIATE);
+    conn_state(data, SMB_NEGOTIATE);
   }
 
   /* Send the previous message and check for a response */
-  result = smb_send_and_recv(conn, &msg);
+  result = smb_send_and_recv(data, &msg);
   if(result && result != CURLE_AGAIN) {
     connclose(conn, "SMB: failed to communicate");
     return result;
@@ -690,12 +709,12 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
     nrsp = msg;
     memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge));
     smbc->session_key = smb_swap32(nrsp->session_key);
-    result = smb_send_setup(conn);
+    result = smb_send_setup(data);
     if(result) {
       connclose(conn, "SMB: failed to send setup message");
       return result;
     }
-    conn_state(conn, SMB_SETUP);
+    conn_state(data, SMB_SETUP);
     break;
 
   case SMB_SETUP:
@@ -704,7 +723,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
       return CURLE_LOGIN_DENIED;
     }
     smbc->uid = smb_swap16(h->uid);
-    conn_state(conn, SMB_CONNECTED);
+    conn_state(data, SMB_CONNECTED);
     *done = true;
     break;
 
@@ -736,9 +755,10 @@ static void get_posix_time(time_t *out, curl_off_t timestamp)
     *out = (time_t) timestamp;
 }
 
-static CURLcode smb_request_state(struct connectdata *conn, bool *done)
+static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
 {
-  struct smb_request *req = conn->data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct smb_request *req = data->req.p.smb;
   struct smb_header *h;
   struct smb_conn *smbc = &conn->proto.smbc;
   enum smb_req_state next_state = SMB_DONE;
@@ -750,17 +770,17 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
 
   /* Start the request */
   if(req->state == SMB_REQUESTING) {
-    result = smb_send_tree_connect(conn);
+    result = smb_send_tree_connect(data);
     if(result) {
       connclose(conn, "SMB: failed to send tree connect message");
       return result;
     }
 
-    request_state(conn, SMB_TREE_CONNECT);
+    request_state(data, SMB_TREE_CONNECT);
   }
 
   /* Send the previous message and check for a response */
-  result = smb_send_and_recv(conn, &msg);
+  result = smb_send_and_recv(data, &msg);
   if(result && result != CURLE_AGAIN) {
     connclose(conn, "SMB: failed to communicate");
     return result;
@@ -793,23 +813,23 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
     }
     smb_m = (const struct smb_nt_create_response*) msg;
     req->fid = smb_swap16(smb_m->fid);
-    conn->data->req.offset = 0;
-    if(conn->data->set.upload) {
-      conn->data->req.size = conn->data->state.infilesize;
-      Curl_pgrsSetUploadSize(conn->data, conn->data->req.size);
+    data->req.offset = 0;
+    if(data->set.upload) {
+      data->req.size = data->state.infilesize;
+      Curl_pgrsSetUploadSize(data, data->req.size);
       next_state = SMB_UPLOAD;
     }
     else {
       smb_m = (const struct smb_nt_create_response*) msg;
-      conn->data->req.size = smb_swap64(smb_m->end_of_file);
-      if(conn->data->req.size < 0) {
+      data->req.size = smb_swap64(smb_m->end_of_file);
+      if(data->req.size < 0) {
         req->result = CURLE_WEIRD_SERVER_REPLY;
         next_state = SMB_CLOSE;
       }
       else {
-        Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
-        if(conn->data->set.get_filetime)
-          get_posix_time(&conn->data->info.filetime, smb_m->last_change_time);
+        Curl_pgrsSetDownloadSize(data, data->req.size);
+        if(data->set.get_filetime)
+          get_posix_time(&data->info.filetime, smb_m->last_change_time);
         next_state = SMB_DOWNLOAD;
       }
     }
@@ -827,11 +847,11 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
                          sizeof(struct smb_header) + 13);
     if(len > 0) {
       if(off + sizeof(unsigned int) + len > smbc->got) {
-        failf(conn->data, "Invalid input packet");
+        failf(data, "Invalid input packet");
         result = CURLE_RECV_ERROR;
       }
       else
-        result = Curl_client_write(conn, CLIENTWRITE_BODY,
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
                                    (char *)msg + off + sizeof(unsigned int),
                                    len);
       if(result) {
@@ -840,9 +860,9 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
         break;
       }
     }
-    conn->data->req.bytecount += len;
-    conn->data->req.offset += len;
-    Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount);
+    data->req.bytecount += len;
+    data->req.offset += len;
+    Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
     next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD;
     break;
 
@@ -854,10 +874,10 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
     }
     len = Curl_read16_le(((const unsigned char *) msg) +
                          sizeof(struct smb_header) + 5);
-    conn->data->req.bytecount += len;
-    conn->data->req.offset += len;
-    Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount);
-    if(conn->data->req.bytecount >= conn->data->req.size)
+    data->req.bytecount += len;
+    data->req.offset += len;
+    Curl_pgrsSetUploadCounter(data, data->req.bytecount);
+    if(data->req.bytecount >= data->req.size)
       next_state = SMB_CLOSE;
     else
       next_state = SMB_UPLOAD;
@@ -881,23 +901,23 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
 
   switch(next_state) {
   case SMB_OPEN:
-    result = smb_send_open(conn);
+    result = smb_send_open(data);
     break;
 
   case SMB_DOWNLOAD:
-    result = smb_send_read(conn);
+    result = smb_send_read(data);
     break;
 
   case SMB_UPLOAD:
-    result = smb_send_write(conn);
+    result = smb_send_write(data);
     break;
 
   case SMB_CLOSE:
-    result = smb_send_close(conn);
+    result = smb_send_close(data);
     break;
 
   case SMB_TREE_DISCONNECT:
-    result = smb_send_tree_disconnect(conn);
+    result = smb_send_tree_disconnect(data);
     break;
 
   case SMB_DONE:
@@ -914,37 +934,42 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
     return result;
   }
 
-  request_state(conn, next_state);
+  request_state(data, next_state);
 
   return CURLE_OK;
 }
 
-static CURLcode smb_done(struct connectdata *conn, CURLcode status,
+static CURLcode smb_done(struct Curl_easy *data, CURLcode status,
                          bool premature)
 {
   (void) premature;
-  Curl_safefree(conn->data->req.protop);
+  Curl_safefree(data->req.p.smb);
   return status;
 }
 
-static CURLcode smb_disconnect(struct connectdata *conn, bool dead)
+static CURLcode smb_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead)
 {
   struct smb_conn *smbc = &conn->proto.smbc;
   (void) dead;
+  (void) data;
   Curl_safefree(smbc->share);
   Curl_safefree(smbc->domain);
   Curl_safefree(smbc->recv_buf);
   return CURLE_OK;
 }
 
-static int smb_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int smb_getsock(struct Curl_easy *data,
+                       struct connectdata *conn, curl_socket_t *socks)
 {
+  (void)data;
   socks[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
 }
 
-static CURLcode smb_do(struct connectdata *conn, bool *done)
+static CURLcode smb_do(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
 
   *done = FALSE;
@@ -954,10 +979,10 @@ static CURLcode smb_do(struct connectdata *conn, bool *done)
   return CURLE_URL_MALFORMAT;
 }
 
-static CURLcode smb_parse_url_path(struct connectdata *conn)
+static CURLcode smb_parse_url_path(struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
-  struct Curl_easy *data = conn->data;
-  struct smb_request *req = data->req.protop;
+  struct smb_request *req = data->req.p.smb;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *path;
   char *slash;
@@ -996,6 +1021,5 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
   return CURLE_OK;
 }
 
-#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
-
-#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */
+#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
+          CURL_SIZEOF_CURL_OFF_T > 4 */
index 136a89c..907cf0c 100644 (file)
@@ -12,7 +12,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -243,16 +243,13 @@ struct smb_tree_disconnect {
 
 #endif /* BUILDING_CURL_SMB_C */
 
-#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
     (CURL_SIZEOF_CURL_OFF_T > 4)
 
-#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
-
 extern const struct Curl_handler Curl_handler_smb;
 extern const struct Curl_handler Curl_handler_smbs;
 
-#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
-
-#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */
+#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
+          CURL_SIZEOF_CURL_OFF_T > 4 */
 
 #endif /* HEADER_CURL_SMB_H */
index aea41bb..1fc8800 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "memdebug.h"
 
 /* Local API functions */
-static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
-static CURLcode smtp_do(struct connectdata *conn, bool *done);
-static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+static CURLcode smtp_regular_transfer(struct Curl_easy *data, bool *done);
+static CURLcode smtp_do(struct Curl_easy *data, bool *done);
+static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
                           bool premature);
-static CURLcode smtp_connect(struct connectdata *conn, bool *done);
-static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
-static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
-static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks);
-static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
-static CURLcode smtp_setup_connection(struct connectdata *conn);
+static CURLcode smtp_connect(struct Curl_easy *data, bool *done);
+static CURLcode smtp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done);
+static int smtp_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
+static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode smtp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
 static CURLcode smtp_parse_url_options(struct connectdata *conn);
-static CURLcode smtp_parse_url_path(struct connectdata *conn);
-static CURLcode smtp_parse_custom_request(struct connectdata *conn);
-static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
+static CURLcode smtp_parse_url_path(struct Curl_easy *data);
+static CURLcode smtp_parse_custom_request(struct Curl_easy *data);
+static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
                                    char **address, struct hostname *host);
-static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
+static CURLcode smtp_perform_auth(struct Curl_easy *data,
+                                  struct connectdata *conn, const char *mech,
                                   const char *initresp);
-static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
+static CURLcode smtp_continue_auth(struct Curl_easy *data,
+                                   struct connectdata *conn, const char *resp);
 static void smtp_get_message(char *buffer, char **outptr);
 
 /*
@@ -133,6 +138,7 @@ const struct Curl_handler Curl_handler_smtp = {
   ZERO_NULL,                        /* connection_check */
   PORT_SMTP,                        /* defport */
   CURLPROTO_SMTP,                   /* protocol */
+  CURLPROTO_SMTP,                   /* family */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
   PROTOPT_URLOPTIONS
 };
@@ -160,6 +166,7 @@ const struct Curl_handler Curl_handler_smtps = {
   ZERO_NULL,                        /* connection_check */
   PORT_SMTPS,                       /* defport */
   CURLPROTO_SMTPS,                  /* protocol */
+  CURLPROTO_SMTP,                   /* family */
   PROTOPT_CLOSEACTION | PROTOPT_SSL
   | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
 };
@@ -197,11 +204,12 @@ static void smtp_to_smtps(struct connectdata *conn)
  * also detects various capabilities from the EHLO response including the
  * supported authentication mechanisms.
  */
-static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
-                           int *resp)
+static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
+                           char *line, size_t len, int *resp)
 {
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   bool result = FALSE;
+  (void)data;
 
   /* Nothing for us */
   if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
@@ -275,9 +283,9 @@ static void smtp_get_message(char *buffer, char **outptr)
  *
  * This is the ONLY way to change SMTP state!
  */
-static void state(struct connectdata *conn, smtpstate newstate)
+static void state(struct Curl_easy *data, smtpstate newstate)
 {
-  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  struct smtp_conn *smtpc = &data->conn->proto.smtpc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
   static const char * const names[] = {
@@ -298,7 +306,7 @@ static void state(struct connectdata *conn, smtpstate newstate)
   };
 
   if(smtpc->state != newstate)
-    infof(conn->data, "SMTP %p state change from %s to %s\n",
+    infof(data, "SMTP %p state change from %s to %s\n",
           (void *)smtpc, names[smtpc->state], names[newstate]);
 #endif
 
@@ -312,9 +320,10 @@ static void state(struct connectdata *conn, smtpstate newstate)
  * Sends the EHLO command to not only initialise communication with the ESMTP
  * server but to also obtain a list of server side supported capabilities.
  */
-static CURLcode smtp_perform_ehlo(struct connectdata *conn)
+static CURLcode smtp_perform_ehlo(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
 
   smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
@@ -324,10 +333,10 @@ static CURLcode smtp_perform_ehlo(struct connectdata *conn)
   smtpc->auth_supported = FALSE;          /* Clear the AUTH capability */
 
   /* Send the EHLO command */
-  result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
+  result = Curl_pp_sendf(data, &smtpc->pp, "EHLO %s", smtpc->domain);
 
   if(!result)
-    state(conn, SMTP_EHLO);
+    state(data, SMTP_EHLO);
 
   return result;
 }
@@ -338,7 +347,8 @@ static CURLcode smtp_perform_ehlo(struct connectdata *conn)
  *
  * Sends the HELO command to initialise communication with the SMTP server.
  */
-static CURLcode smtp_perform_helo(struct connectdata *conn)
+static CURLcode smtp_perform_helo(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
@@ -347,10 +357,10 @@ static CURLcode smtp_perform_helo(struct connectdata *conn)
                                             in smtp connections */
 
   /* Send the HELO command */
-  result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
+  result = Curl_pp_sendf(data, &smtpc->pp, "HELO %s", smtpc->domain);
 
   if(!result)
-    state(conn, SMTP_HELO);
+    state(data, SMTP_HELO);
 
   return result;
 }
@@ -361,13 +371,15 @@ static CURLcode smtp_perform_helo(struct connectdata *conn)
  *
  * Sends the STLS command to start the upgrade to TLS.
  */
-static CURLcode smtp_perform_starttls(struct connectdata *conn)
+static CURLcode smtp_perform_starttls(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   /* Send the STARTTLS command */
-  CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
+                                  "%s", "STARTTLS");
 
   if(!result)
-    state(conn, SMTP_STARTTLS);
+    state(data, SMTP_STARTTLS);
 
   return result;
 }
@@ -378,20 +390,21 @@ static CURLcode smtp_perform_starttls(struct connectdata *conn)
  *
  * Performs the upgrade to TLS.
  */
-static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
+static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
 {
   /* Start the SSL connection */
+  struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
-  CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
+  CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
                                                  &smtpc->ssldone);
 
   if(!result) {
     if(smtpc->state != SMTP_UPGRADETLS)
-      state(conn, SMTP_UPGRADETLS);
+      state(data, SMTP_UPGRADETLS);
 
     if(smtpc->ssldone) {
       smtp_to_smtps(conn);
-      result = smtp_perform_ehlo(conn);
+      result = smtp_perform_ehlo(data);
     }
   }
 
@@ -405,7 +418,8 @@ static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
  * Sends an AUTH command allowing the client to login with the given SASL
  * authentication mechanism.
  */
-static CURLcode smtp_perform_auth(struct connectdata *conn,
+static CURLcode smtp_perform_auth(struct Curl_easy *data,
+                                  struct connectdata *conn,
                                   const char *mech,
                                   const char *initresp)
 {
@@ -414,11 +428,11 @@ static CURLcode smtp_perform_auth(struct connectdata *conn,
 
   if(initresp) {                                  /* AUTH <mech> ...<crlf> */
     /* Send the AUTH command with the initial response */
-    result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
+    result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, initresp);
   }
   else {
     /* Send the AUTH command */
-    result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
+    result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s", mech);
   }
 
   return result;
@@ -430,11 +444,12 @@ static CURLcode smtp_perform_auth(struct connectdata *conn,
  *
  * Sends SASL continuation data or cancellation.
  */
-static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
+static CURLcode smtp_continue_auth(struct Curl_easy *data,
+                                   struct connectdata *conn, const char *resp)
 {
   struct smtp_conn *smtpc = &conn->proto.smtpc;
 
-  return Curl_pp_sendf(&smtpc->pp, "%s", resp);
+  return Curl_pp_sendf(data, &smtpc->pp, "%s", resp);
 }
 
 /***********************************************************************
@@ -444,9 +459,10 @@ static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
  * Initiates the authentication sequence, with the appropriate SASL
  * authentication mechanism.
  */
-static CURLcode smtp_perform_authentication(struct connectdata *conn)
+static CURLcode smtp_perform_authentication(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   saslprogress progress;
 
@@ -454,19 +470,19 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)
      server supports authentiation, and end the connect phase if not */
   if(!smtpc->auth_supported ||
      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
-    state(conn, SMTP_STOP);
+    state(data, SMTP_STOP);
     return result;
   }
 
   /* Calculate the SASL login details */
-  result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
+  result = Curl_sasl_start(&smtpc->sasl, data, conn, FALSE, &progress);
 
   if(!result) {
     if(progress == SASL_INPROGRESS)
-      state(conn, SMTP_AUTH);
+      state(data, SMTP_AUTH);
     else {
       /* Other mechanisms not supported */
-      infof(conn->data, "No known authentication mechanisms supported!\n");
+      infof(data, "No known authentication mechanisms supported!\n");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -480,11 +496,11 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)
  *
  * Sends a SMTP based command.
  */
-static CURLcode smtp_perform_command(struct connectdata *conn)
+static CURLcode smtp_perform_command(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct SMTP *smtp = data->req.p.smtp;
 
   if(smtp->rcpt) {
     /* We notify the server we are sending UTF-8 data if a) it supports the
@@ -499,7 +515,7 @@ static CURLcode smtp_perform_command(struct connectdata *conn)
 
       /* Parse the mailbox to verify into the local address and host name
          parts, converting the host name to an IDN A-label if necessary */
-      result = smtp_parse_address(conn, smtp->rcpt->data,
+      result = smtp_parse_address(data, smtp->rcpt->data,
                                   &address, &host);
       if(result)
         return result;
@@ -512,7 +528,7 @@ static CURLcode smtp_perform_command(struct connectdata *conn)
 
       /* Send the VRFY command (Note: The host name part may be absent when the
          host is a local system) */
-      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "VRFY %s%s%s%s",
+      result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "VRFY %s%s%s%s",
                              address,
                              host.name ? "@" : "",
                              host.name ? host.name : "",
@@ -528,19 +544,20 @@ static CURLcode smtp_perform_command(struct connectdata *conn)
              (!strcmp(smtp->custom, "EXPN"));
 
       /* Send the custom recipient based command such as the EXPN command */
-      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s%s", smtp->custom,
+      result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
+                             "%s %s%s", smtp->custom,
                              smtp->rcpt->data,
                              utf8 ? " SMTPUTF8" : "");
     }
   }
   else
     /* Send the non-recipient based command such as HELP */
-    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
+    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s",
                            smtp->custom && smtp->custom[0] != '\0' ?
                            smtp->custom : "HELP");
 
   if(!result)
-    state(conn, SMTP_COMMAND);
+    state(data, SMTP_COMMAND);
 
   return result;
 }
@@ -551,13 +568,13 @@ static CURLcode smtp_perform_command(struct connectdata *conn)
  *
  * Sends an MAIL command to initiate the upload of a message.
  */
-static CURLcode smtp_perform_mail(struct connectdata *conn)
+static CURLcode smtp_perform_mail(struct Curl_easy *data)
 {
   char *from = NULL;
   char *auth = NULL;
   char *size = NULL;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   /* We notify the server we are sending UTF-8 data if a) it supports the
      SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
@@ -572,7 +589,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
 
     /* Parse the FROM mailbox into the local address and host name parts,
        converting the host name to an IDN A-label if necessary */
-    result = smtp_parse_address(conn, data->set.str[STRING_MAIL_FROM],
+    result = smtp_parse_address(data, data->set.str[STRING_MAIL_FROM],
                                 &address, &host);
     if(result)
       return result;
@@ -610,7 +627,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
 
       /* Parse the AUTH mailbox into the local address and host name parts,
          converting the host name to an IDN A-label if necessary */
-      result = smtp_parse_address(conn, data->set.str[STRING_MAIL_AUTH],
+      result = smtp_parse_address(data, data->set.str[STRING_MAIL_AUTH],
                                   &address, &host);
       if(result) {
         free(from);
@@ -658,7 +675,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
                                        NULL, MIMESTRATEGY_MAIL);
 
     if(!result)
-      if(!Curl_checkheaders(conn, "Mime-Version"))
+      if(!Curl_checkheaders(data, "Mime-Version"))
         result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
                                       "Mime-Version: 1.0");
 
@@ -697,7 +714,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
      any there do, as we need to correctly identify our support for SMTPUTF8
      in the envelope, as per RFC-6531 sect. 3.4 */
   if(conn->proto.smtpc.utf8_supported && !utf8) {
-    struct SMTP *smtp = data->req.protop;
+    struct SMTP *smtp = data->req.p.smtp;
     struct curl_slist *rcpt = smtp->rcpt;
 
     while(rcpt && !utf8) {
@@ -710,7 +727,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
   }
 
   /* Send the MAIL command */
-  result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+  result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
                          "MAIL FROM:%s%s%s%s%s%s",
                          from,                 /* Mandatory                 */
                          auth ? " AUTH=" : "", /* Optional on AUTH support  */
@@ -725,7 +742,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
   free(size);
 
   if(!result)
-    state(conn, SMTP_MAIL);
+    state(data, SMTP_MAIL);
 
   return result;
 }
@@ -737,35 +754,36 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
  * Sends a RCPT TO command for a given recipient as part of the message upload
  * process.
  */
-static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
+static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct SMTP *smtp = data->req.p.smtp;
   char *address = NULL;
   struct hostname host = { NULL, NULL, NULL, NULL };
 
   /* Parse the recipient mailbox into the local address and host name parts,
      converting the host name to an IDN A-label if necessary */
-  result = smtp_parse_address(conn, smtp->rcpt->data,
+  result = smtp_parse_address(data, smtp->rcpt->data,
                               &address, &host);
   if(result)
     return result;
 
   /* Send the RCPT TO command */
   if(host.name)
-    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s@%s>", address,
-                           host.name);
+    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s@%s>",
+                           address, host.name);
   else
     /* An invalid mailbox was provided but we'll simply let the server worry
        about that and reply with a 501 error */
-    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", address);
+    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s>",
+                           address);
 
   Curl_free_idnconverted_hostname(&host);
   free(address);
 
   if(!result)
-    state(conn, SMTP_RCPT);
+    state(data, SMTP_RCPT);
 
   return result;
 }
@@ -776,25 +794,24 @@ static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
  *
  * Performs the quit action prior to sclose() being called.
  */
-static CURLcode smtp_perform_quit(struct connectdata *conn)
+static CURLcode smtp_perform_quit(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   /* Send the QUIT command */
-  CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
+  CURLcode result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "QUIT");
 
   if(!result)
-    state(conn, SMTP_QUIT);
+    state(data, SMTP_QUIT);
 
   return result;
 }
 
 /* For the initial server greeting */
-static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
+static CURLcode smtp_state_servergreet_resp(struct Curl_easy *data,
                                             int smtpcode,
                                             smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(smtpcode/100 != 2) {
@@ -802,19 +819,17 @@ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
     result = CURLE_WEIRD_SERVER_REPLY;
   }
   else
-    result = smtp_perform_ehlo(conn);
+    result = smtp_perform_ehlo(data);
 
   return result;
 }
 
 /* For STARTTLS responses */
-static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
+static CURLcode smtp_state_starttls_resp(struct Curl_easy *data,
                                          int smtpcode,
                                          smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(smtpcode != 220) {
@@ -823,20 +838,20 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
       result = CURLE_USE_SSL_FAILED;
     }
     else
-      result = smtp_perform_authentication(conn);
+      result = smtp_perform_authentication(data);
   }
   else
-    result = smtp_perform_upgrade_tls(conn);
+    result = smtp_perform_upgrade_tls(data);
 
   return result;
 }
 
 /* For EHLO responses */
-static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
+static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
+                                     struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   const char *line = data->state.buffer;
   size_t len = strlen(line);
@@ -845,7 +860,7 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
 
   if(smtpcode/100 != 2 && smtpcode != 1) {
     if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
-      result = smtp_perform_helo(conn);
+      result = smtp_perform_helo(data, conn);
     else {
       failf(data, "Remote access denied: %d", smtpcode);
       result = CURLE_REMOTE_ACCESS_DENIED;
@@ -913,17 +928,17 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
         /* We don't have a SSL/TLS connection yet, but SSL is requested */
         if(smtpc->tls_supported)
           /* Switch to TLS connection now */
-          result = smtp_perform_starttls(conn);
+          result = smtp_perform_starttls(data, conn);
         else if(data->set.use_ssl == CURLUSESSL_TRY)
           /* Fallback and carry on with authentication */
-          result = smtp_perform_authentication(conn);
+          result = smtp_perform_authentication(data);
         else {
           failf(data, "STARTTLS not supported.");
           result = CURLE_USE_SSL_FAILED;
         }
       }
       else
-        result = smtp_perform_authentication(conn);
+        result = smtp_perform_authentication(data);
     }
   }
   else {
@@ -935,12 +950,10 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
 }
 
 /* For HELO responses */
-static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
+static CURLcode smtp_state_helo_resp(struct Curl_easy *data, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(smtpcode/100 != 2) {
@@ -949,28 +962,28 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
   }
   else
     /* End of connect phase */
-    state(conn, SMTP_STOP);
+    state(data, SMTP_STOP);
 
   return result;
 }
 
 /* For SASL authentication responses */
-static CURLcode smtp_state_auth_resp(struct connectdata *conn,
+static CURLcode smtp_state_auth_resp(struct Curl_easy *data,
                                      int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   saslprogress progress;
 
   (void)instate; /* no use for this yet */
 
-  result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
+  result = Curl_sasl_continue(&smtpc->sasl, data, conn, smtpcode, &progress);
   if(!result)
     switch(progress) {
     case SASL_DONE:
-      state(conn, SMTP_STOP);  /* Authenticated */
+      state(data, SMTP_STOP);  /* Authenticated */
       break;
     case SASL_IDLE:            /* No mechanism left after cancellation */
       failf(data, "Authentication cancelled");
@@ -984,12 +997,11 @@ static CURLcode smtp_state_auth_resp(struct connectdata *conn,
 }
 
 /* For command responses */
-static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
+static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
                                         smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct SMTP *smtp = data->req.p.smtp;
   char *line = data->state.buffer;
   size_t len = strlen(line);
 
@@ -1004,7 +1016,7 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
     /* Temporarily add the LF character back and send as body to the client */
     if(!data->set.opt_no_body) {
       line[len] = '\n';
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
       line[len] = '\0';
     }
 
@@ -1014,15 +1026,15 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
 
         if(smtp->rcpt) {
           /* Send the next command */
-          result = smtp_perform_command(conn);
+          result = smtp_perform_command(data);
         }
         else
           /* End of DO phase */
-          state(conn, SMTP_STOP);
+          state(data, SMTP_STOP);
       }
       else
         /* End of DO phase */
-        state(conn, SMTP_STOP);
+        state(data, SMTP_STOP);
     }
   }
 
@@ -1030,12 +1042,10 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
 }
 
 /* For MAIL responses */
-static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
+static CURLcode smtp_state_mail_resp(struct Curl_easy *data, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(smtpcode/100 != 2) {
@@ -1044,18 +1054,18 @@ static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
   }
   else
     /* Start the RCPT TO command */
-    result = smtp_perform_rcpt_to(conn);
+    result = smtp_perform_rcpt_to(data);
 
   return result;
 }
 
 /* For RCPT responses */
-static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
+static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data,
+                                     struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct SMTP *smtp = data->req.p.smtp;
   bool is_smtp_err = FALSE;
   bool is_smtp_blocking_err = FALSE;
 
@@ -1088,7 +1098,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
 
     if(smtp->rcpt)
       /* Send the next RCPT TO command */
-      result = smtp_perform_rcpt_to(conn);
+      result = smtp_perform_rcpt_to(data);
     else {
       /* We weren't able to issue a successful RCPT TO command while going
          over recipients (potentially multiple). Sending back last error. */
@@ -1098,10 +1108,10 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
       }
       else {
         /* Send the DATA command */
-        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
+        result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "%s", "DATA");
 
         if(!result)
-          state(conn, SMTP_DATA);
+          state(data, SMTP_DATA);
       }
     }
   }
@@ -1110,12 +1120,10 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
 }
 
 /* For DATA response */
-static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
+static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
 
   if(smtpcode != 354) {
@@ -1130,7 +1138,7 @@ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
     Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
 
     /* End of DO phase */
-    state(conn, SMTP_STOP);
+    state(data, SMTP_STOP);
   }
 
   return result;
@@ -1138,7 +1146,7 @@ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
 
 /* For POSTDATA responses, which are received after the entire DATA
    part has been sent to the server */
-static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
+static CURLcode smtp_state_postdata_resp(struct Curl_easy *data,
                                          int smtpcode,
                                          smtpstate instate)
 {
@@ -1150,16 +1158,16 @@ static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
     result = CURLE_RECV_ERROR;
 
   /* End of DONE phase */
-  state(conn, SMTP_STOP);
+  state(data, SMTP_STOP);
 
   return result;
 }
 
-static CURLcode smtp_statemach_act(struct connectdata *conn)
+static CURLcode smtp_statemachine(struct Curl_easy *data,
+                                  struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data = conn->data;
   int smtpcode;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   struct pingpong *pp = &smtpc->pp;
@@ -1167,15 +1175,15 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
 
   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
   if(smtpc->state == SMTP_UPGRADETLS)
-    return smtp_perform_upgrade_tls(conn);
+    return smtp_perform_upgrade_tls(data);
 
   /* Flush any data that needs to be sent */
   if(pp->sendleft)
-    return Curl_pp_flushsend(pp);
+    return Curl_pp_flushsend(data, pp);
 
   do {
     /* Read the response from the server */
-    result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
+    result = Curl_pp_readresp(data, sock, pp, &smtpcode, &nread);
     if(result)
       return result;
 
@@ -1189,50 +1197,50 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
     /* We have now received a full SMTP server response */
     switch(smtpc->state) {
     case SMTP_SERVERGREET:
-      result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_servergreet_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_EHLO:
-      result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_ehlo_resp(data, conn, smtpcode, smtpc->state);
       break;
 
     case SMTP_HELO:
-      result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_helo_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_STARTTLS:
-      result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_starttls_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_AUTH:
-      result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_auth_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_COMMAND:
-      result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_command_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_MAIL:
-      result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_mail_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_RCPT:
-      result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_rcpt_resp(data, conn, smtpcode, smtpc->state);
       break;
 
     case SMTP_DATA:
-      result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_data_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_POSTDATA:
-      result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
+      result = smtp_state_postdata_resp(data, smtpcode, smtpc->state);
       break;
 
     case SMTP_QUIT:
       /* fallthrough, just stop! */
     default:
       /* internal error */
-      state(conn, SMTP_STOP);
+      state(data, SMTP_STOP);
       break;
     }
   } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
@@ -1241,44 +1249,46 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
 }
 
 /* Called repeatedly until done from multi.c */
-static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
+static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
 
   if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
-    result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
+    result = Curl_ssl_connect_nonblocking(data, conn,
+                                          FIRSTSOCKET, &smtpc->ssldone);
     if(result || !smtpc->ssldone)
       return result;
   }
 
-  result = Curl_pp_statemach(&smtpc->pp, FALSE, FALSE);
+  result = Curl_pp_statemach(data, &smtpc->pp, FALSE, FALSE);
   *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
 
   return result;
 }
 
-static CURLcode smtp_block_statemach(struct connectdata *conn,
+static CURLcode smtp_block_statemach(struct Curl_easy *data,
+                                     struct connectdata *conn,
                                      bool disconnecting)
 {
   CURLcode result = CURLE_OK;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
 
   while(smtpc->state != SMTP_STOP && !result)
-    result = Curl_pp_statemach(&smtpc->pp, TRUE, disconnecting);
+    result = Curl_pp_statemach(data, &smtpc->pp, TRUE, disconnecting);
 
   return result;
 }
 
 /* Allocate and initialize the SMTP struct for the current Curl_easy if
    required */
-static CURLcode smtp_init(struct connectdata *conn)
+static CURLcode smtp_init(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct SMTP *smtp;
 
-  smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
+  smtp = data->req.p.smtp = calloc(sizeof(struct SMTP), 1);
   if(!smtp)
     result = CURLE_OUT_OF_MEMORY;
 
@@ -1286,9 +1296,10 @@ static CURLcode smtp_init(struct connectdata *conn)
 }
 
 /* For the SMTP "protocol connect" and "doing" phases only */
-static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int smtp_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks)
 {
-  return Curl_pp_getsock(&conn->proto.smtpc.pp, socks);
+  return Curl_pp_getsock(data, &conn->proto.smtpc.pp, socks);
 }
 
 /***********************************************************************
@@ -1301,9 +1312,10 @@ static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks)
  * The variable pointed to by 'done' will be TRUE if the protocol-layer
  * connect phase is done when this function returns, or FALSE if not.
  */
-static CURLcode smtp_connect(struct connectdata *conn, bool *done)
+static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   struct pingpong *pp = &smtpc->pp;
 
@@ -1312,17 +1324,14 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
   /* We always support persistent connections in SMTP */
   connkeep(conn, "SMTP default");
 
-  /* Set the default response time-out */
-  pp->response_time = RESP_TIMEOUT;
-  pp->statemach_act = smtp_statemach_act;
-  pp->endofresp = smtp_endofresp;
-  pp->conn = conn;
+  PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp);
 
   /* Initialize the SASL storage */
   Curl_sasl_init(&smtpc->sasl, &saslsmtp);
 
   /* Initialise the pingpong layer */
-  Curl_pp_init(pp);
+  Curl_pp_setup(pp);
+  Curl_pp_init(data, pp);
 
   /* Parse the URL options */
   result = smtp_parse_url_options(conn);
@@ -1330,14 +1339,14 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
     return result;
 
   /* Parse the URL path */
-  result = smtp_parse_url_path(conn);
+  result = smtp_parse_url_path(data);
   if(result)
     return result;
 
   /* Start off waiting for the server greeting response */
-  state(conn, SMTP_SERVERGREET);
+  state(data, SMTP_SERVERGREET);
 
-  result = smtp_multi_statemach(conn, done);
+  result = smtp_multi_statemach(data, done);
 
   return result;
 }
@@ -1351,12 +1360,12 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
  *
  * Input argument is already checked for validity.
  */
-static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
                           bool premature)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct SMTP *smtp = data->req.p.smtp;
   struct pingpong *pp = &conn->proto.smtpc.pp;
   char *eob;
   ssize_t len;
@@ -1364,7 +1373,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
 
   (void)premature;
 
-  if(!smtp || !pp->conn)
+  if(!smtp)
     return CURLE_OK;
 
   /* Cleanup our per-request based variables */
@@ -1384,7 +1393,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
        fail when using a different pointer following a previous write, that
        returned CURLE_AGAIN, we duplicate the EOB now rather than when the
        bytes written doesn't equal len. */
-    if(smtp->trailing_crlf || !conn->data->state.infilesize) {
+    if(smtp->trailing_crlf || !data->state.infilesize) {
       eob = strdup(&SMTP_EOB[2]);
       len = SMTP_EOB_LEN - 2;
     }
@@ -1397,7 +1406,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
       return CURLE_OUT_OF_MEMORY;
 
     /* Send the end of block data */
-    result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
+    result = Curl_write(data, conn->writesockfd, eob, len, &bytes_written);
     if(result) {
       free(eob);
       return result;
@@ -1417,10 +1426,10 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
       free(eob);
     }
 
-    state(conn, SMTP_POSTDATA);
+    state(data, SMTP_POSTDATA);
 
     /* Run the state-machine */
-    result = smtp_block_statemach(conn, FALSE);
+    result = smtp_block_statemach(data, conn, FALSE);
   }
 
   /* Clear the transfer mode for the next request */
@@ -1436,15 +1445,15 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
  * This is the actual DO function for SMTP. Transfer a mail, send a command
  * or get some data according to the options previously setup.
  */
-static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
+static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
                              bool *dophase_done)
 {
   /* This is SMTP and no proxy */
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct SMTP *smtp = data->req.p.smtp;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
   if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
@@ -1470,21 +1479,21 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
   /* Start the first command in the DO phase */
   if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
     /* MAIL transfer */
-    result = smtp_perform_mail(conn);
+    result = smtp_perform_mail(data);
   else
     /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */
-    result = smtp_perform_command(conn);
+    result = smtp_perform_command(data);
 
   if(result)
     return result;
 
   /* Run the state-machine */
-  result = smtp_multi_statemach(conn, dophase_done);
+  result = smtp_multi_statemach(data, dophase_done);
 
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
 
   return result;
 }
@@ -1498,18 +1507,17 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
  *
  * The input argument is already checked for validity.
  */
-static CURLcode smtp_do(struct connectdata *conn, bool *done)
+static CURLcode smtp_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-
   *done = FALSE; /* default to false */
 
   /* Parse the custom request */
-  result = smtp_parse_custom_request(conn);
+  result = smtp_parse_custom_request(data);
   if(result)
     return result;
 
-  result = smtp_regular_transfer(conn, done);
+  result = smtp_regular_transfer(data, done);
 
   return result;
 }
@@ -1521,19 +1529,21 @@ static CURLcode smtp_do(struct connectdata *conn, bool *done)
  * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
  * resources. BLOCKING.
  */
-static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode smtp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection)
 {
   struct smtp_conn *smtpc = &conn->proto.smtpc;
+  (void)data;
 
   /* We cannot send quit unconditionally. If this connection is stale or
      bad in any way, sending quit and waiting around here will make the
      disconnect wait in vain and cause more problems than we need to. */
 
-  /* The SMTP session may or may not have been allocated/setup at this
-     point! */
-  if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
-    if(!smtp_perform_quit(conn))
-      (void)smtp_block_statemach(conn, TRUE); /* ignore errors on QUIT */
+  if(!dead_connection && conn->bits.protoconnstart) {
+    if(!smtp_perform_quit(data, conn))
+      (void)smtp_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */
+  }
 
   /* Disconnect from the server */
   Curl_pp_disconnect(&smtpc->pp);
@@ -1548,30 +1558,30 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
 }
 
 /* Call this when the DO phase has completed */
-static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
+static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected)
 {
-  struct SMTP *smtp = conn->data->req.protop;
+  struct SMTP *smtp = data->req.p.smtp;
 
   (void)connected;
 
   if(smtp->transfer != FTPTRANSFER_BODY)
     /* no data to transfer */
-    Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
+    Curl_setup_transfer(data, -1, -1, FALSE, -1);
 
   return CURLE_OK;
 }
 
 /* Called from multi.c while DOing */
-static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
+static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
 {
-  CURLcode result = smtp_multi_statemach(conn, dophase_done);
+  CURLcode result = smtp_multi_statemach(data, dophase_done);
 
   if(result)
-    DEBUGF(infof(conn->data, "DO phase failed\n"));
+    DEBUGF(infof(data, "DO phase failed\n"));
   else if(*dophase_done) {
-    result = smtp_dophase_done(conn, FALSE /* not connected */);
+    result = smtp_dophase_done(data, FALSE /* not connected */);
 
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
@@ -1586,12 +1596,11 @@ static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
  * Performs all commands done before a regular transfer between a local and a
  * remote host.
  */
-static CURLcode smtp_regular_transfer(struct connectdata *conn,
+static CURLcode smtp_regular_transfer(struct Curl_easy *data,
                                       bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
-  struct Curl_easy *data = conn->data;
 
   /* Make sure size is unknown at this point */
   data->req.size = -1;
@@ -1603,16 +1612,17 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn,
   Curl_pgrsSetDownloadSize(data, -1);
 
   /* Carry out the perform */
-  result = smtp_perform(conn, &connected, dophase_done);
+  result = smtp_perform(data, &connected, dophase_done);
 
   /* Perform post DO phase operations if necessary */
   if(!result && *dophase_done)
-    result = smtp_dophase_done(conn, connected);
+    result = smtp_dophase_done(data, connected);
 
   return result;
 }
 
-static CURLcode smtp_setup_connection(struct connectdata *conn)
+static CURLcode smtp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   CURLcode result;
 
@@ -1620,7 +1630,7 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
   conn->bits.tls_upgraded = FALSE;
 
   /* Initialise the SMTP layer */
-  result = smtp_init(conn);
+  result = smtp_init(data);
   if(result)
     return result;
 
@@ -1672,10 +1682,10 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
  *
  * Parse the URL path into separate path components.
  */
-static CURLcode smtp_parse_url_path(struct connectdata *conn)
+static CURLcode smtp_parse_url_path(struct Curl_easy *data)
 {
   /* The SMTP struct is already initialised in smtp_connect() */
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   const char *path = &data->state.up.path[1]; /* skip leading path */
   char localhost[HOSTNAME_MAX + 1];
@@ -1689,7 +1699,7 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
   }
 
   /* URL decode the path and use it as the domain in our EHLO */
-  return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL,
+  return Curl_urldecode(data, path, 0, &smtpc->domain, NULL,
                         REJECT_CTRL);
 }
 
@@ -1699,11 +1709,10 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
  *
  * Parse the custom request.
  */
-static CURLcode smtp_parse_custom_request(struct connectdata *conn)
+static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct SMTP *smtp = data->req.p.smtp;
   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
 
   /* URL decode the custom request */
@@ -1747,7 +1756,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn)
  * calling function deems it to be) then the input will simply be returned in
  * the address part with the host name being NULL.
  */
-static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
+static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
                                    char **address, struct hostname *host)
 {
   CURLcode result = CURLE_OK;
@@ -1772,7 +1781,7 @@ static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
     host->name = host->name + 1;
 
     /* Attempt to convert the host name to IDN ACE */
-    (void) Curl_idnconvert_hostname(conn, host);
+    (void) Curl_idnconvert_hostname(data, host);
 
     /* If Curl_idnconvert_hostname() fails then we shall attempt to continue
        and send the host name using UTF-8 rather than as 7-bit ACE (which is
@@ -1785,7 +1794,7 @@ static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
   return result;
 }
 
-CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
+CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread)
 {
   /* When sending a SMTP payload we must detect CRLF. sequences making sure
      they are sent as CRLF.. instead, as a . on the beginning of a line will
@@ -1795,8 +1804,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
   */
   ssize_t i;
   ssize_t si;
-  struct Curl_easy *data = conn->data;
-  struct SMTP *smtp = data->req.protop;
+  struct SMTP *smtp = data->req.p.smtp;
   char *scratch = data->state.scratch;
   char *newscratch = NULL;
   char *oldscratch = NULL;
index 164a175..1fe4534 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -57,10 +57,10 @@ struct SMTP {
   struct curl_slist *rcpt; /* Recipient list */
   bool rcpt_had_ok;        /* Whether any of RCPT TO commands (depends on
                               total number of recipients) succeeded so far */
+  bool trailing_crlf;      /* Specifies if the trailing CRLF is present */
   int rcpt_last_error;     /* The last error received for RCPT TO command */
   size_t eob;              /* Number of bytes of the EOB (End Of Body) that
                               have been received so far */
-  bool trailing_crlf;      /* Specifies if the tailing CRLF is present */
 };
 
 /* smtp_conn is used for struct connection-oriented data in the connectdata
@@ -91,6 +91,6 @@ extern const struct Curl_handler Curl_handler_smtps;
 #define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
 #define SMTP_EOB_REPL_LEN 4
 
-CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread);
+CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread);
 
 #endif /* HEADER_CURL_SMTP_H */
index b037ee0..84c08d9 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 1ec0d75..2c580ad 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -23,7 +23,7 @@
 #include "curl_setup.h"
 #include "socketpair.h"
 
-#ifndef HAVE_SOCKETPAIR
+#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR)
 #ifdef WIN32
 /*
  * This is a socketpair() implementation for Windows.
index be9fb24..033a235 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 44783d0..d1c2a2e 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -51,7 +51,7 @@
  *
  * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions.
  */
-int Curl_blockread_all(struct connectdata *conn, /* connection data */
+int Curl_blockread_all(struct Curl_easy *data,   /* transfer */
                        curl_socket_t sockfd,     /* read from this socket */
                        char *buf,                /* store read data here */
                        ssize_t buffersize,       /* max amount to read */
@@ -62,7 +62,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
   int result;
   *n = 0;
   for(;;) {
-    timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, TRUE);
+    timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
     if(timeout_ms < 0) {
       /* we already got the timeout */
       result = CURLE_OPERATION_TIMEDOUT;
@@ -107,13 +107,14 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
 
 
 /* always use this function to change state, to make debugging easier */
-static void socksstate(struct connectdata *conn,
+static void socksstate(struct Curl_easy *data,
                        enum connect_t state
 #ifdef DEBUGBUILD
                        , int lineno
 #endif
 )
 {
+  struct connectdata *conn = data->conn;
   enum connect_t oldstate = conn->cnnct.state;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* synced with the state list in urldata.h */
@@ -146,7 +147,7 @@ static void socksstate(struct connectdata *conn,
   conn->cnnct.state = state;
 
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  infof(conn->data,
+  infof(data,
         "SXSTATE: %s => %s conn %p; line %d\n",
         statename[oldstate], statename[conn->cnnct.state], conn,
         lineno);
@@ -184,33 +185,36 @@ int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock,
 *   Set protocol4a=true for  "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
 *   Nonsupport "Identification Protocol (RFC1413)"
 */
-CURLcode Curl_SOCKS4(const char *proxy_user,
-                     const char *hostname,
-                     int remote_port,
-                     int sockindex,
-                     struct connectdata *conn,
-                     bool *done)
+CURLproxycode Curl_SOCKS4(const char *proxy_user,
+                          const char *hostname,
+                          int remote_port,
+                          int sockindex,
+                          struct Curl_easy *data,
+                          bool *done)
 {
+  struct connectdata *conn = data->conn;
   const bool protocol4a =
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
-  unsigned char *socksreq = &conn->cnnct.socksreq[0];
+  unsigned char *socksreq = (unsigned char *)data->state.buffer;
   CURLcode result;
   curl_socket_t sockfd = conn->sock[sockindex];
-  struct Curl_easy *data = conn->data;
   struct connstate *sx = &conn->cnnct;
   struct Curl_dns_entry *dns = NULL;
   ssize_t actualread;
   ssize_t written;
 
+  /* make sure that the buffer is at least 600 bytes */
+  DEBUGASSERT(READBUFFER_MIN >= 600);
+
   if(!SOCKS_STATE(sx->state) && !*done)
-    sxstate(conn, CONNECT_SOCKS_INIT);
+    sxstate(data, CONNECT_SOCKS_INIT);
 
   switch(sx->state) {
   case CONNECT_SOCKS_INIT:
     /* SOCKS4 can only do IPv4, insist! */
     conn->ip_version = CURL_IPRESOLVE_V4;
     if(conn->bits.httpproxy)
-      infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
+      infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
             protocol4a ? "a" : "", hostname, remote_port);
 
     infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
@@ -234,39 +238,42 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
     /* DNS resolve only for SOCKS4, not SOCKS4a */
     if(!protocol4a) {
       enum resolve_t rc =
-        Curl_resolv(conn, hostname, remote_port, FALSE, &dns);
+        Curl_resolv(data, hostname, remote_port, FALSE, &dns);
 
       if(rc == CURLRESOLV_ERROR)
-        return CURLE_COULDNT_RESOLVE_PROXY;
+        return CURLPX_RESOLVE_HOST;
       else if(rc == CURLRESOLV_PENDING) {
-        sxstate(conn, CONNECT_RESOLVING);
+        sxstate(data, CONNECT_RESOLVING);
         infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname);
-        return CURLE_OK;
+        return CURLPX_OK;
       }
-      sxstate(conn, CONNECT_RESOLVED);
+      sxstate(data, CONNECT_RESOLVED);
       goto CONNECT_RESOLVED;
     }
 
     /* socks4a doesn't resolve anything locally */
-    sxstate(conn, CONNECT_REQ_INIT);
+    sxstate(data, CONNECT_REQ_INIT);
     goto CONNECT_REQ_INIT;
 
   case CONNECT_RESOLVING:
     /* check if we have the name resolved by now */
-    dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+    dns = Curl_fetch_addr(data, hostname, (int)conn->port);
 
     if(dns) {
 #ifdef CURLRES_ASYNCH
-      conn->async.dns = dns;
-      conn->async.done = TRUE;
+      data->state.async.dns = dns;
+      data->state.async.done = TRUE;
 #endif
       infof(data, "Hostname '%s' was found\n", hostname);
-      sxstate(conn, CONNECT_RESOLVED);
+      sxstate(data, CONNECT_RESOLVED);
     }
     else {
-      result = Curl_resolv_check(data->conn, &dns);
-      if(!dns)
-        return result;
+      result = Curl_resolv_check(data, &dns);
+      if(!dns) {
+        if(result)
+          return CURLPX_RESOLVE_HOST;
+        return CURLPX_OK;
+      }
     }
     /* FALLTHROUGH */
   CONNECT_RESOLVED:
@@ -295,7 +302,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
       }
       else {
         hp = NULL; /* fail! */
-        failf(data, "SOCKS4 connection to %s not supported\n", buf);
+        failf(data, "SOCKS4 connection to %s not supported", buf);
       }
 
       Curl_resolv_unlock(data, dns); /* not used anymore from now on */
@@ -303,7 +310,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
     if(!hp) {
       failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
             hostname);
-      return CURLE_COULDNT_RESOLVE_HOST;
+      return CURLPX_RESOLVE_HOST;
     }
   }
     /* FALLTHROUGH */
@@ -315,9 +322,9 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
     socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
     if(proxy_user) {
       size_t plen = strlen(proxy_user);
-      if(plen >= sizeof(sx->socksreq) - 8) {
-        failf(data, "Too long SOCKS proxy name, can't use!\n");
-        return CURLE_COULDNT_CONNECT;
+      if(plen >= (size_t)data->set.buffer_size - 8) {
+        failf(data, "Too long SOCKS proxy user name, can't use!");
+        return CURLPX_LONG_USER;
       }
       /* copy the proxy name WITH trailing zero */
       memcpy(socksreq + 8, proxy_user, plen + 1);
@@ -343,34 +350,34 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
           strcpy((char *)socksreq + packetsize, hostname);
         else {
           failf(data, "SOCKS4: too long host name");
-          return CURLE_COULDNT_CONNECT;
+          return CURLPX_LONG_HOSTNAME;
         }
         packetsize += hostnamelen;
       }
       sx->outp = socksreq;
       sx->outstanding = packetsize;
-      sxstate(conn, CONNECT_REQ_SENDING);
+      sxstate(data, CONNECT_REQ_SENDING);
     }
     /* FALLTHROUGH */
   case CONNECT_REQ_SENDING:
     /* Send request */
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to send SOCKS4 connect request.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_SEND_CONNECT;
     }
     if(written != sx->outstanding) {
       /* not done, remain in state */
       sx->outstanding -= written;
       sx->outp += written;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
 
     /* done sending! */
     sx->outstanding = 8; /* receive data size */
     sx->outp = socksreq;
-    sxstate(conn, CONNECT_SOCKS_READ);
+    sxstate(data, CONNECT_SOCKS_READ);
 
     /* FALLTHROUGH */
   case CONNECT_SOCKS_READ:
@@ -380,20 +387,20 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "SOCKS4: Failed receiving connect request ack: %s",
             curl_easy_strerror(result));
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_RECV_CONNECT;
     }
     else if(!result && !actualread) {
       /* connection closed */
       failf(data, "connection to proxy closed");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_CLOSED;
     }
     else if(actualread != sx->outstanding) {
       /* remain in reading state */
       sx->outstanding -= actualread;
       sx->outp += actualread;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
-    sxstate(conn, CONNECT_DONE);
+    sxstate(data, CONNECT_DONE);
     break;
   default: /* lots of unused states in SOCKS4 */
     break;
@@ -422,7 +429,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
   if(socksreq[0] != 0) {
     failf(data,
           "SOCKS4 reply has wrong version, version should be 0.");
-    return CURLE_COULDNT_CONNECT;
+    return CURLPX_BAD_VERSION;
   }
 
   /* Result */
@@ -434,57 +441,53 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
     failf(data,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", request rejected or failed.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
-    return CURLE_COULDNT_CONNECT;
+    return CURLPX_REQUEST_FAILED;
   case 92:
     failf(data,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", request rejected because SOCKS server cannot connect to "
           "identd on the client.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
-    return CURLE_COULDNT_CONNECT;
+    return CURLPX_IDENTD;
   case 93:
     failf(data,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", request rejected because the client program and identd "
           "report different user-ids.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
-    return CURLE_COULDNT_CONNECT;
+    return CURLPX_IDENTD_DIFFER;
   default:
     failf(data,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", Unknown.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
-    return CURLE_COULDNT_CONNECT;
+    return CURLPX_UNKNOWN_FAIL;
   }
 
   *done = TRUE;
-  return CURLE_OK; /* Proxy was successful! */
+  return CURLPX_OK; /* Proxy was successful! */
 }
 
 /*
  * This function logs in to a SOCKS5 proxy and sends the specifics to the final
  * destination server.
  */
-CURLcode Curl_SOCKS5(const char *proxy_user,
-                     const char *proxy_password,
-                     const char *hostname,
-                     int remote_port,
-                     int sockindex,
-                     struct connectdata *conn,
-                     bool *done)
+CURLproxycode Curl_SOCKS5(const char *proxy_user,
+                          const char *proxy_password,
+                          const char *hostname,
+                          int remote_port,
+                          int sockindex,
+                          struct Curl_easy *data,
+                          bool *done)
 {
   /*
     According to the RFC1928, section "6.  Replies". This is what a SOCK5
@@ -502,14 +505,14 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
     o  REP    Reply field:
     o  X'00' succeeded
   */
-  unsigned char *socksreq = &conn->cnnct.socksreq[0];
+  struct connectdata *conn = data->conn;
+  unsigned char *socksreq = (unsigned char *)data->state.buffer;
   char dest[256] = "unknown";  /* printable hostname:port */
   int idx;
   ssize_t actualread;
   ssize_t written;
   CURLcode result;
   curl_socket_t sockfd = conn->sock[sockindex];
-  struct Curl_easy *data = conn->data;
   bool socks5_resolve_local =
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
   const size_t hostname_len = strlen(hostname);
@@ -520,23 +523,23 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
   struct Curl_dns_entry *dns = NULL;
 
   if(!SOCKS_STATE(sx->state) && !*done)
-    sxstate(conn, CONNECT_SOCKS_INIT);
+    sxstate(data, CONNECT_SOCKS_INIT);
 
   switch(sx->state) {
   case CONNECT_SOCKS_INIT:
     if(conn->bits.httpproxy)
-      infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
+      infof(data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
             hostname, remote_port);
 
     /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
     if(!socks5_resolve_local && hostname_len > 255) {
-      infof(conn->data, "SOCKS5: server resolving disabled for hostnames of "
+      infof(data, "SOCKS5: server resolving disabled for hostnames of "
             "length > 255 [actual len=%zu]\n", hostname_len);
       socks5_resolve_local = TRUE;
     }
 
     if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
-      infof(conn->data,
+      infof(data,
             "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
             auth);
     if(!(auth & CURLAUTH_BASIC))
@@ -558,31 +561,31 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
     /* write the number of authentication methods */
     socksreq[1] = (unsigned char) (idx - 2);
 
-    result = Curl_write_plain(conn, sockfd, (char *)socksreq, idx, &written);
+    result = Curl_write_plain(data, sockfd, (char *)socksreq, idx, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Unable to send initial SOCKS5 request.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_SEND_CONNECT;
     }
     if(written != idx) {
-      sxstate(conn, CONNECT_SOCKS_SEND);
+      sxstate(data, CONNECT_SOCKS_SEND);
       sx->outstanding = idx - written;
       sx->outp = &socksreq[written];
-      return CURLE_OK;
+      return CURLPX_OK;
     }
-    sxstate(conn, CONNECT_SOCKS_READ);
+    sxstate(data, CONNECT_SOCKS_READ);
     goto CONNECT_SOCKS_READ_INIT;
   case CONNECT_SOCKS_SEND:
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Unable to send initial SOCKS5 request.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_SEND_CONNECT;
     }
     if(written != sx->outstanding) {
       /* not done, remain in state */
       sx->outstanding -= written;
       sx->outp += written;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
     /* FALLTHROUGH */
   CONNECT_SOCKS_READ_INIT:
@@ -595,40 +598,40 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
                              sx->outstanding, &actualread);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Unable to receive initial SOCKS5 response.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_RECV_CONNECT;
     }
     else if(!result && !actualread) {
       /* connection closed */
       failf(data, "Connection to proxy closed");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_CLOSED;
     }
     else if(actualread != sx->outstanding) {
       /* remain in reading state */
       sx->outstanding -= actualread;
       sx->outp += actualread;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
     else if(socksreq[0] != 5) {
       failf(data, "Received invalid version in initial SOCKS5 response.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_BAD_VERSION;
     }
     else if(socksreq[1] == 0) {
       /* DONE! No authentication needed. Send request. */
-      sxstate(conn, CONNECT_REQ_INIT);
+      sxstate(data, CONNECT_REQ_INIT);
       goto CONNECT_REQ_INIT;
     }
     else if(socksreq[1] == 2) {
       /* regular name + password authentication */
-      sxstate(conn, CONNECT_AUTH_INIT);
+      sxstate(data, CONNECT_AUTH_INIT);
       goto CONNECT_AUTH_INIT;
     }
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
     else if(allow_gssapi && (socksreq[1] == 1)) {
-      sxstate(conn, CONNECT_GSSAPI_INIT);
-      result = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
+      sxstate(data, CONNECT_GSSAPI_INIT);
+      result = Curl_SOCKS5_gssapi_negotiate(sockindex, data);
       if(result) {
         failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
-        return CURLE_COULDNT_CONNECT;
+        return CURLPX_GSSAPI;
       }
     }
 #endif
@@ -637,16 +640,16 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
       if(!allow_gssapi && (socksreq[1] == 1)) {
         failf(data,
               "SOCKS5 GSSAPI per-message authentication is not supported.");
-        return CURLE_COULDNT_CONNECT;
+        return CURLPX_GSSAPI_PERMSG;
       }
       else if(socksreq[1] == 255) {
         failf(data, "No authentication method was acceptable.");
-        return CURLE_COULDNT_CONNECT;
+        return CURLPX_NO_AUTH;
       }
     }
     failf(data,
           "Undocumented SOCKS5 mode attempted to be used by server.");
-    return CURLE_COULDNT_CONNECT;
+    return CURLPX_UNKNOWN_MODE;
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   case CONNECT_GSSAPI_INIT:
     /* GSSAPI stuff done non-blocking */
@@ -683,7 +686,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
       /* the length must fit in a single byte */
       if(proxy_user_len >= 255) {
         failf(data, "Excessive user name length for proxy auth");
-        return CURLE_BAD_FUNCTION_ARGUMENT;
+        return CURLPX_LONG_USER;
       }
       memcpy(socksreq + len, proxy_user, proxy_user_len);
     }
@@ -693,95 +696,98 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
       /* the length must fit in a single byte */
       if(proxy_password_len > 255) {
         failf(data, "Excessive password length for proxy auth");
-        return CURLE_BAD_FUNCTION_ARGUMENT;
+        return CURLPX_LONG_PASSWD;
       }
       memcpy(socksreq + len, proxy_password, proxy_password_len);
     }
     len += proxy_password_len;
-    sxstate(conn, CONNECT_AUTH_SEND);
+    sxstate(data, CONNECT_AUTH_SEND);
     sx->outstanding = len;
     sx->outp = socksreq;
   }
     /* FALLTHROUGH */
   case CONNECT_AUTH_SEND:
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to send SOCKS5 sub-negotiation request.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_SEND_AUTH;
     }
     if(sx->outstanding != written) {
       /* remain in state */
       sx->outstanding -= written;
       sx->outp += written;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
     sx->outp = socksreq;
     sx->outstanding = 2;
-    sxstate(conn, CONNECT_AUTH_READ);
+    sxstate(data, CONNECT_AUTH_READ);
     /* FALLTHROUGH */
   case CONNECT_AUTH_READ:
     result = Curl_read_plain(sockfd, (char *)sx->outp,
                              sx->outstanding, &actualread);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_RECV_AUTH;
     }
     else if(!result && !actualread) {
       /* connection closed */
       failf(data, "connection to proxy closed");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_CLOSED;
     }
     else if(actualread != sx->outstanding) {
       /* remain in state */
       sx->outstanding -= actualread;
       sx->outp += actualread;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
     /* ignore the first (VER) byte */
     else if(socksreq[1] != 0) { /* status */
       failf(data, "User was rejected by the SOCKS5 server (%d %d).",
             socksreq[0], socksreq[1]);
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_USER_REJECTED;
     }
 
     /* Everything is good so far, user was authenticated! */
-    sxstate(conn, CONNECT_REQ_INIT);
+    sxstate(data, CONNECT_REQ_INIT);
     /* FALLTHROUGH */
   CONNECT_REQ_INIT:
   case CONNECT_REQ_INIT:
     if(socks5_resolve_local) {
-      enum resolve_t rc = Curl_resolv(conn, hostname, remote_port,
+      enum resolve_t rc = Curl_resolv(data, hostname, remote_port,
                                       FALSE, &dns);
 
       if(rc == CURLRESOLV_ERROR)
-        return CURLE_COULDNT_RESOLVE_HOST;
+        return CURLPX_RESOLVE_HOST;
 
       if(rc == CURLRESOLV_PENDING) {
-        sxstate(conn, CONNECT_RESOLVING);
-        return CURLE_OK;
+        sxstate(data, CONNECT_RESOLVING);
+        return CURLPX_OK;
       }
-      sxstate(conn, CONNECT_RESOLVED);
+      sxstate(data, CONNECT_RESOLVED);
       goto CONNECT_RESOLVED;
     }
     goto CONNECT_RESOLVE_REMOTE;
 
   case CONNECT_RESOLVING:
     /* check if we have the name resolved by now */
-    dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+    dns = Curl_fetch_addr(data, hostname, remote_port);
 
     if(dns) {
 #ifdef CURLRES_ASYNCH
-      conn->async.dns = dns;
-      conn->async.done = TRUE;
+      data->state.async.dns = dns;
+      data->state.async.done = TRUE;
 #endif
       infof(data, "SOCKS5: hostname '%s' found\n", hostname);
     }
 
     if(!dns) {
-      result = Curl_resolv_check(data->conn, &dns);
-      if(!dns)
-        return result;
+      result = Curl_resolv_check(data, &dns);
+      if(!dns) {
+        if(result)
+          return CURLPX_RESOLVE_HOST;
+        return CURLPX_OK;
+      }
     }
     /* FALLTHROUGH */
   CONNECT_RESOLVED:
@@ -793,7 +799,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
     if(!hp) {
       failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
             hostname);
-      return CURLE_COULDNT_RESOLVE_HOST;
+      return CURLPX_RESOLVE_HOST;
     }
 
     Curl_printable_address(hp, dest, sizeof(dest));
@@ -833,7 +839,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
 #endif
     else {
       hp = NULL; /* fail! */
-      failf(data, "SOCKS5 connection to %s not supported\n", dest);
+      failf(data, "SOCKS5 connection to %s not supported", dest);
     }
 
     Curl_resolv_unlock(data, dns); /* not used anymore from now on */
@@ -867,64 +873,81 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
     if(conn->socks5_gssapi_enctype) {
       failf(data, "SOCKS5 GSS-API protection not yet implemented.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_GSSAPI_PROTECTION;
     }
 #endif
     sx->outp = socksreq;
     sx->outstanding = len;
-    sxstate(conn, CONNECT_REQ_SENDING);
+    sxstate(data, CONNECT_REQ_SENDING);
     /* FALLTHROUGH */
   case CONNECT_REQ_SENDING:
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to send SOCKS5 connect request.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_SEND_REQUEST;
     }
     if(sx->outstanding != written) {
       /* remain in state */
       sx->outstanding -= written;
       sx->outp += written;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
     if(conn->socks5_gssapi_enctype) {
       failf(data, "SOCKS5 GSS-API protection not yet implemented.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_GSSAPI_PROTECTION;
     }
 #endif
     sx->outstanding = 10; /* minimum packet size is 10 */
     sx->outp = socksreq;
-    sxstate(conn, CONNECT_REQ_READ);
+    sxstate(data, CONNECT_REQ_READ);
     /* FALLTHROUGH */
   case CONNECT_REQ_READ:
     result = Curl_read_plain(sockfd, (char *)sx->outp,
                              sx->outstanding, &actualread);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to receive SOCKS5 connect request ack.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_RECV_REQACK;
     }
     else if(!result && !actualread) {
       /* connection closed */
       failf(data, "connection to proxy closed");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_CLOSED;
     }
     else if(actualread != sx->outstanding) {
       /* remain in state */
       sx->outstanding -= actualread;
       sx->outp += actualread;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
 
     if(socksreq[0] != 5) { /* version */
       failf(data,
             "SOCKS5 reply has wrong version, version should be 5.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_BAD_VERSION;
     }
     else if(socksreq[1] != 0) { /* Anything besides 0 is an error */
+      CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
+      int code = socksreq[1];
       failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
             hostname, (unsigned char)socksreq[1]);
-      return CURLE_COULDNT_CONNECT;
+      if(code < 9) {
+        /* RFC 1928 section 6 lists: */
+        static const CURLproxycode lookup[] = {
+          CURLPX_OK,
+          CURLPX_REPLY_GENERAL_SERVER_FAILURE,
+          CURLPX_REPLY_NOT_ALLOWED,
+          CURLPX_REPLY_NETWORK_UNREACHABLE,
+          CURLPX_REPLY_HOST_UNREACHABLE,
+          CURLPX_REPLY_CONNECTION_REFUSED,
+          CURLPX_REPLY_TTL_EXPIRED,
+          CURLPX_REPLY_COMMAND_NOT_SUPPORTED,
+          CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
+        };
+        rc = lookup[code];
+      }
+      return rc;
     }
 
     /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
@@ -958,7 +981,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
     }
     else {
       failf(data, "SOCKS5 reply has wrong address type.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_BAD_ADDRESS_TYPE;
     }
 
     /* At this point we already read first 10 bytes */
@@ -969,10 +992,10 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
       if(len > 10) {
         sx->outstanding = len - 10; /* get the rest */
         sx->outp = &socksreq[10];
-        sxstate(conn, CONNECT_REQ_READ_MORE);
+        sxstate(data, CONNECT_REQ_READ_MORE);
       }
       else {
-        sxstate(conn, CONNECT_DONE);
+        sxstate(data, CONNECT_DONE);
         break;
       }
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
@@ -984,25 +1007,25 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
                              sx->outstanding, &actualread);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to receive SOCKS5 connect request ack.");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_RECV_ADDRESS;
     }
     else if(!result && !actualread) {
       /* connection closed */
       failf(data, "connection to proxy closed");
-      return CURLE_COULDNT_CONNECT;
+      return CURLPX_CLOSED;
     }
     else if(actualread != sx->outstanding) {
       /* remain in state */
       sx->outstanding -= actualread;
       sx->outp += actualread;
-      return CURLE_OK;
+      return CURLPX_OK;
     }
-    sxstate(conn, CONNECT_DONE);
+    sxstate(data, CONNECT_DONE);
   }
   infof(data, "SOCKS5 request granted.\n");
 
   *done = TRUE;
-  return CURLE_OK; /* Proxy was successful! */
+  return CURLPX_OK; /* Proxy was successful! */
 }
 
 #endif /* CURL_DISABLE_PROXY */
index 64a7563..b0c7f9b 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -35,7 +35,7 @@
  *
  * This is STUPID BLOCKING behavior
  */
-int Curl_blockread_all(struct connectdata *conn,
+int Curl_blockread_all(struct Curl_easy *data,
                        curl_socket_t sockfd,
                        char *buf,
                        ssize_t buffersize,
@@ -48,31 +48,31 @@ int Curl_SOCKS_getsock(struct connectdata *conn,
  * This function logs in to a SOCKS4(a) proxy and sends the specifics to the
  * final destination server.
  */
-CURLcode Curl_SOCKS4(const char *proxy_name,
-                     const char *hostname,
-                     int remote_port,
-                     int sockindex,
-                     struct connectdata *conn,
-                     bool *done);
+CURLproxycode Curl_SOCKS4(const char *proxy_name,
+                          const char *hostname,
+                          int remote_port,
+                          int sockindex,
+                          struct Curl_easy *data,
+                          bool *done);
 
 /*
  * This function logs in to a SOCKS5 proxy and sends the specifics to the
  * final destination server.
  */
-CURLcode Curl_SOCKS5(const char *proxy_name,
-                     const char *proxy_password,
-                     const char *hostname,
-                     int remote_port,
-                     int sockindex,
-                     struct connectdata *conn,
-                     bool *done);
+CURLproxycode Curl_SOCKS5(const char *proxy_name,
+                          const char *proxy_password,
+                          const char *hostname,
+                          int remote_port,
+                          int sockindex,
+                          struct Curl_easy *data,
+                          bool *done);
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
 /*
  * This function handles the SOCKS5 GSS-API negotiation and initialisation
  */
 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
-                                      struct connectdata *conn);
+                                      struct Curl_easy *data);
 #endif
 
 #endif /* CURL_DISABLE_PROXY */
index 2e36b99..3ab786d 100644 (file)
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -92,7 +92,7 @@ static int check_gss_err(struct Curl_easy *data,
       }
       gss_release_buffer(&min_stat, &status_string);
     }
-    failf(data, "GSS-API error: %s failed:\n%s", function, buf);
+    failf(data, "GSS-API error: %s failed: %s", function, buf);
     return 1;
   }
 
@@ -100,9 +100,9 @@ static int check_gss_err(struct Curl_easy *data,
 }
 
 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
-                                      struct connectdata *conn)
+                                      struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sock = conn->sock[sockindex];
   CURLcode code;
   ssize_t actualread;
@@ -201,7 +201,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       us_length = htons((short)gss_send_token.length);
       memcpy(socksreq + 2, &us_length, sizeof(short));
 
-      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+      code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
       if(code || (4 != written)) {
         failf(data, "Failed to send GSS-API authentication request.");
         gss_release_name(&gss_status, &server);
@@ -211,7 +211,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
         return CURLE_COULDNT_CONNECT;
       }
 
-      code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
+      code = Curl_write_plain(data, sock, (char *)gss_send_token.value,
                               gss_send_token.length, &written);
 
       if(code || ((ssize_t)gss_send_token.length != written)) {
@@ -240,7 +240,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
      * +----+------+-----+----------------+
      */
 
-    result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+    result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
     if(result || (actualread != 4)) {
       failf(data, "Failed to receive GSS-API authentication response.");
       gss_release_name(&gss_status, &server);
@@ -279,7 +279,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_OUT_OF_MEMORY;
     }
 
-    result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+    result = Curl_blockread_all(data, sock, (char *)gss_recv_token.value,
                                 gss_recv_token.length, &actualread);
 
     if(result || (actualread != us_length)) {
@@ -408,7 +408,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     memcpy(socksreq + 2, &us_length, sizeof(short));
   }
 
-  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+  code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
   if(code  || (4 != written)) {
     failf(data, "Failed to send GSS-API encryption request.");
     gss_release_buffer(&gss_status, &gss_w_token);
@@ -418,7 +418,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
   if(data->set.socks5_gssapi_nec) {
     memcpy(socksreq, &gss_enc, 1);
-    code = Curl_write_plain(conn, sock, socksreq, 1, &written);
+    code = Curl_write_plain(data, sock, socksreq, 1, &written);
     if(code || ( 1 != written)) {
       failf(data, "Failed to send GSS-API encryption type.");
       gss_delete_sec_context(&gss_status, &gss_context, NULL);
@@ -426,7 +426,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     }
   }
   else {
-    code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
+    code = Curl_write_plain(data, sock, (char *)gss_w_token.value,
                             gss_w_token.length, &written);
     if(code || ((ssize_t)gss_w_token.length != written)) {
       failf(data, "Failed to send GSS-API encryption type.");
@@ -437,7 +437,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_release_buffer(&gss_status, &gss_w_token);
   }
 
-  result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+  result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
   if(result || (actualread != 4)) {
     failf(data, "Failed to receive GSS-API encryption response.");
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
@@ -468,7 +468,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_OUT_OF_MEMORY;
   }
-  result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+  result = Curl_blockread_all(data, sock, (char *)gss_recv_token.value,
                               gss_recv_token.length, &actualread);
 
   if(result || (actualread != us_length)) {
@@ -493,7 +493,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_release_buffer(&gss_status, &gss_recv_token);
 
     if(gss_w_token.length != 1) {
-      failf(data, "Invalid GSS-API encryption response length (%d).",
+      failf(data, "Invalid GSS-API encryption response length (%zu).",
             gss_w_token.length);
       gss_release_buffer(&gss_status, &gss_w_token);
       gss_delete_sec_context(&gss_status, &gss_context, NULL);
@@ -505,7 +505,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   }
   else {
     if(gss_recv_token.length != 1) {
-      failf(data, "Invalid GSS-API encryption response length (%d).",
+      failf(data, "Invalid GSS-API encryption response length (%zu).",
             gss_recv_token.length);
       gss_release_buffer(&gss_status, &gss_recv_token);
       gss_delete_sec_context(&gss_status, &gss_context, NULL);
index 2f1fd36..b343538 100644 (file)
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -43,7 +43,7 @@
 /*
  * Helper sspi error functions.
  */
-static int check_sspi_err(struct connectdata *conn,
+static int check_sspi_err(struct Curl_easy *data,
                           SECURITY_STATUS status,
                           const char *function)
 {
@@ -52,7 +52,7 @@ static int check_sspi_err(struct connectdata *conn,
      status != SEC_I_COMPLETE_NEEDED &&
      status != SEC_I_CONTINUE_NEEDED) {
     char buffer[STRERROR_LEN];
-    failf(conn->data, "SSPI error: %s failed: %s", function,
+    failf(data, "SSPI error: %s failed: %s", function,
           Curl_sspi_strerror(status, buffer, sizeof(buffer)));
     return 1;
   }
@@ -61,9 +61,9 @@ static int check_sspi_err(struct connectdata *conn,
 
 /* This is the SSPI-using version of this function */
 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
-                                      struct connectdata *conn)
+                                      struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sock = conn->sock[sockindex];
   CURLcode code;
   ssize_t actualread;
@@ -86,7 +86,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   unsigned long qop;
   unsigned char socksreq[4]; /* room for GSS-API exchange header only */
   const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
-                        data->set.str[STRING_PROXY_SERVICE_NAME]  : "rcmd";
+    data->set.str[STRING_PROXY_SERVICE_NAME]  : "rcmd";
   const size_t service_length = strlen(service);
 
   /*   GSS-API request looks like
@@ -146,7 +146,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                               &cred_handle,
                                               &expiry);
 
-  if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) {
+  if(check_sspi_err(data, status, "AcquireCredentialsHandle")) {
     failf(data, "Failed to acquire credentials.");
     free(service_name);
     s_pSecFn->FreeCredentialsHandle(&cred_handle);
@@ -188,7 +188,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       sspi_recv_token.cbBuffer = 0;
     }
 
-    if(check_sspi_err(conn, status, "InitializeSecurityContext")) {
+    if(check_sspi_err(data, status, "InitializeSecurityContext")) {
       free(service_name);
       s_pSecFn->FreeCredentialsHandle(&cred_handle);
       s_pSecFn->DeleteSecurityContext(&sspi_context);
@@ -204,7 +204,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       us_length = htons((short)sspi_send_token.cbBuffer);
       memcpy(socksreq + 2, &us_length, sizeof(short));
 
-      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+      code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
       if(code || (4 != written)) {
         failf(data, "Failed to send SSPI authentication request.");
         free(service_name);
@@ -217,7 +217,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
         return CURLE_COULDNT_CONNECT;
       }
 
-      code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+      code = Curl_write_plain(data, sock, (char *)sspi_send_token.pvBuffer,
                               sspi_send_token.cbBuffer, &written);
       if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
         failf(data, "Failed to send SSPI authentication token.");
@@ -258,7 +258,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
      * +----+------+-----+----------------+
      */
 
-    result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+    result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
     if(result || (actualread != 4)) {
       failf(data, "Failed to receive SSPI authentication response.");
       free(service_name);
@@ -298,7 +298,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       s_pSecFn->DeleteSecurityContext(&sspi_context);
       return CURLE_OUT_OF_MEMORY;
     }
-    result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer,
+    result = Curl_blockread_all(data, sock, (char *)sspi_recv_token.pvBuffer,
                                 sspi_recv_token.cbBuffer, &actualread);
 
     if(result || (actualread != us_length)) {
@@ -321,7 +321,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                                 SECPKG_CRED_ATTR_NAMES,
                                                 &names);
   s_pSecFn->FreeCredentialsHandle(&cred_handle);
-  if(check_sspi_err(conn, status, "QueryCredentialAttributes")) {
+  if(check_sspi_err(data, status, "QueryCredentialAttributes")) {
     s_pSecFn->DeleteSecurityContext(&sspi_context);
     s_pSecFn->FreeContextBuffer(names.sUserName);
     failf(data, "Failed to determine user name.");
@@ -386,7 +386,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     status = s_pSecFn->QueryContextAttributes(&sspi_context,
                                               SECPKG_ATTR_SIZES,
                                               &sspi_sizes);
-    if(check_sspi_err(conn, status, "QueryContextAttributes")) {
+    if(check_sspi_err(data, status, "QueryContextAttributes")) {
       s_pSecFn->DeleteSecurityContext(&sspi_context);
       failf(data, "Failed to query security context attributes.");
       return CURLE_COULDNT_CONNECT;
@@ -423,7 +423,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                       KERB_WRAP_NO_ENCRYPT,
                                       &wrap_desc,
                                       0);
-    if(check_sspi_err(conn, status, "EncryptMessage")) {
+    if(check_sspi_err(data, status, "EncryptMessage")) {
       s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
       s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
       s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
@@ -466,7 +466,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     memcpy(socksreq + 2, &us_length, sizeof(short));
   }
 
-  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+  code = Curl_write_plain(data, sock, (char *)socksreq, 4, &written);
   if(code || (4 != written)) {
     failf(data, "Failed to send SSPI encryption request.");
     if(sspi_send_token.pvBuffer)
@@ -477,7 +477,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
   if(data->set.socks5_gssapi_nec) {
     memcpy(socksreq, &gss_enc, 1);
-    code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written);
+    code = Curl_write_plain(data, sock, (char *)socksreq, 1, &written);
     if(code || (1 != written)) {
       failf(data, "Failed to send SSPI encryption type.");
       s_pSecFn->DeleteSecurityContext(&sspi_context);
@@ -485,7 +485,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     }
   }
   else {
-    code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+    code = Curl_write_plain(data, sock, (char *)sspi_send_token.pvBuffer,
                             sspi_send_token.cbBuffer, &written);
     if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
       failf(data, "Failed to send SSPI encryption type.");
@@ -498,7 +498,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
   }
 
-  result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+  result = Curl_blockread_all(data, sock, (char *)socksreq, 4, &actualread);
   if(result || (actualread != 4)) {
     failf(data, "Failed to receive SSPI encryption response.");
     s_pSecFn->DeleteSecurityContext(&sspi_context);
@@ -530,7 +530,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     return CURLE_OUT_OF_MEMORY;
   }
 
-  result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer,
+  result = Curl_blockread_all(data, sock, (char *)sspi_w_token[0].pvBuffer,
                               sspi_w_token[0].cbBuffer, &actualread);
 
   if(result || (actualread != us_length)) {
@@ -553,7 +553,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                       0,
                                       &qop);
 
-    if(check_sspi_err(conn, status, "DecryptMessage")) {
+    if(check_sspi_err(data, status, "DecryptMessage")) {
       if(sspi_w_token[0].pvBuffer)
         s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
       if(sspi_w_token[1].pvBuffer)
index 3aeea91..841d256 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -39,6 +39,10 @@ void Curl_speedinit(struct Curl_easy *data)
 CURLcode Curl_speedcheck(struct Curl_easy *data,
                          struct curltime now)
 {
+  if(data->req.keepon & KEEP_RECV_PAUSE)
+    /* A paused transfer is not qualified for speed checks */
+    return CURLE_OK;
+
   if((data->progress.current_speed >= 0) && data->set.low_speed_time) {
     if(data->progress.current_speed < data->set.low_speed_limit) {
       if(!data->state.keeps_speed.tv_sec)
index 5c2dc9a..1d4c7bf 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 0f5fcd1..98baf5d 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1997 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1997 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -206,9 +206,9 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i,
  *
  * @unittest: 1309
  */
-int Curl_splayremovebyaddr(struct Curl_tree *t,
-                           struct Curl_tree *removenode,
-                           struct Curl_tree **newroot)
+int Curl_splayremove(struct Curl_tree *t,
+                     struct Curl_tree *removenode,
+                     struct Curl_tree **newroot)
 {
   static const struct curltime KEY_NOTUSED = {
     (time_t)-1, (unsigned int)-1
index 9292f34..eb9f65f 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1997 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1997 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -40,19 +40,13 @@ struct Curl_tree *Curl_splayinsert(struct curltime key,
                                    struct Curl_tree *t,
                                    struct Curl_tree *newnode);
 
-#if 0
-struct Curl_tree *Curl_splayremove(struct curltime key,
-                                   struct Curl_tree *t,
-                                   struct Curl_tree **removed);
-#endif
-
 struct Curl_tree *Curl_splaygetbest(struct curltime key,
                                     struct Curl_tree *t,
                                     struct Curl_tree **removed);
 
-int Curl_splayremovebyaddr(struct Curl_tree *t,
-                           struct Curl_tree *removenode,
-                           struct Curl_tree **newroot);
+int Curl_splayremove(struct Curl_tree *t,
+                     struct Curl_tree *removenode,
+                     struct Curl_tree **newroot);
 
 #define Curl_splaycomparekeys(i,j) ( ((i.tv_sec)  < (j.tv_sec)) ? -1 : \
                                    ( ((i.tv_sec)  > (j.tv_sec)) ?  1 : \
index a309e35..955e3c7 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index cd4c419..10dc698 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 7732802..9af47ea 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index ae3d5d0..0936956 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 015e588..3862aab 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2004 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2004 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -320,6 +320,9 @@ curl_easy_strerror(CURLcode error)
   case CURLE_QUIC_CONNECT_ERROR:
     return "QUIC connection error";
 
+ case CURLE_PROXY:
+    return "proxy handshake error";
+
     /* error codes not used by current libcurl */
   case CURLE_OBSOLETE20:
   case CURLE_OBSOLETE24:
@@ -652,34 +655,27 @@ static const char *
 get_winapi_error(int err, char *buf, size_t buflen)
 {
   char *p;
+  wchar_t wbuf[256];
 
   if(!buflen)
     return NULL;
 
   *buf = '\0';
-
-#ifdef _WIN32_WCE
-  {
-    wchar_t wbuf[256];
-    wbuf[0] = L'\0';
-
-    if(FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |
-                      FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err,
-                     LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
-      size_t written = wcstombs(buf, wbuf, buflen - 1);
-      if(written != (size_t)-1)
-        buf[written] = '\0';
-      else
-        *buf = '\0';
-    }
-  }
-#else
-  if(!FormatMessageA((FORMAT_MESSAGE_FROM_SYSTEM |
-                      FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err,
-                     LANG_NEUTRAL, buf, (DWORD)buflen, NULL)) {
-    *buf = '\0';
+  *wbuf = L'\0';
+
+  /* We return the local codepage version of the error string because if it is
+     output to the user's terminal it will likely be with functions which
+     expect the local codepage (eg fprintf, failf, infof).
+     FormatMessageW -> wcstombs is used for Windows CE compatibility. */
+  if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
+                     FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err,
+                    LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
+    size_t written = wcstombs(buf, wbuf, buflen - 1);
+    if(written != (size_t)-1)
+      buf[written] = '\0';
+    else
+      *buf = '\0';
   }
-#endif
 
   /* Truncate multiple lines */
   p = strchr(buf, '\n');
@@ -725,7 +721,9 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
   if(!buflen)
     return NULL;
 
+#ifndef WIN32
   DEBUGASSERT(err >= 0);
+#endif
 
   max = buflen - 1;
   *buf = '\0';
@@ -785,7 +783,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
   }
 #else
   {
-    char *msg = strerror(err);
+    const char *msg = strerror(err);
     if(msg)
       strncpy(buf, msg, max);
     else
index bae8f89..96a7e27 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index ba6e025..d53e587 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index e221fa6..831ef0c 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 96e3820..ac87cfc 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index be19cd7..4d22ba3 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 2e59e03..2132f43 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -55,12 +55,7 @@ CURLcode Curl_win32_init(long flags)
     WSADATA wsaData;
     int res;
 
-#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
-#error IPV6_requires_winsock2
-#endif
-
-    wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
-
+    wVersionRequested = MAKEWORD(2, 2);
     res = WSAStartup(wVersionRequested, &wsaData);
 
     if(res != 0)
@@ -83,9 +78,9 @@ CURLcode Curl_win32_init(long flags)
       return CURLE_FAILED_INIT;
     }
     /* The Windows Sockets DLL is acceptable. Proceed. */
-  #elif defined(USE_LWIPSOCK)
+#elif defined(USE_LWIPSOCK)
     lwip_init();
-  #endif
+#endif
   } /* CURL_GLOBAL_WIN32 */
 
 #ifdef USE_WINDOWS_SSPI
@@ -201,7 +196,7 @@ HMODULE Curl_load_library(LPCTSTR filename)
       pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
       LoadLibrary(filename);
   }
-  /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only
+  /* Detect if KB2533623 is installed, as LOAD_LIBRARY_SEARCH_SYSTEM32 is only
      supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
      Server 2008 R2 with this patch or natively on Windows 8 and above */
   else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
index 2547bda..69e0c81 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index c3b58e5..f96a4cb 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #define printoption(a,b,c,d)  Curl_nop_stmt
 #endif
 
-#ifdef USE_WINSOCK
-typedef WSAEVENT (WINAPI *WSOCK2_EVENT)(void);
-typedef FARPROC WSOCK2_FUNC;
-static CURLcode check_wsock2(struct Curl_easy *data);
-#endif
-
 static
-CURLcode telrcv(struct connectdata *,
+CURLcode telrcv(struct Curl_easy *data,
                 const unsigned char *inbuf, /* Data received from socket */
                 ssize_t count);             /* Number of bytes received */
 
@@ -104,23 +98,23 @@ static void printoption(struct Curl_easy *data,
                         int cmd, int option);
 #endif
 
-static void negotiate(struct connectdata *);
-static void send_negotiation(struct connectdata *, int cmd, int option);
-static void set_local_option(struct connectdata *conn,
+static void negotiate(struct Curl_easy *data);
+static void send_negotiation(struct Curl_easy *data, int cmd, int option);
+static void set_local_option(struct Curl_easy *data,
                              int option, int newstate);
-static void set_remote_option(struct connectdata *conn,
+static void set_remote_option(struct Curl_easy *data,
                               int option, int newstate);
 
 static void printsub(struct Curl_easy *data,
                      int direction, unsigned char *pointer,
                      size_t length);
-static void suboption(struct connectdata *);
-static void sendsuboption(struct connectdata *conn, int option);
+static void suboption(struct Curl_easy *data);
+static void sendsuboption(struct Curl_easy *data, int option);
 
-static CURLcode telnet_do(struct connectdata *conn, bool *done);
-static CURLcode telnet_done(struct connectdata *conn,
+static CURLcode telnet_do(struct Curl_easy *data, bool *done);
+static CURLcode telnet_done(struct Curl_easy *data,
                                  CURLcode, bool premature);
-static CURLcode send_telnet_data(struct connectdata *conn,
+static CURLcode send_telnet_data(struct Curl_easy *data,
                                  char *buffer, ssize_t nread);
 
 /* For negotiation compliant to RFC 1143 */
@@ -162,13 +156,12 @@ struct TELNET {
   char subopt_xdisploc[128];         /* Set with suboption XDISPLOC */
   unsigned short subopt_wsx;         /* Set with suboption NAWS */
   unsigned short subopt_wsy;         /* Set with suboption NAWS */
+  TelnetReceive telrcv_state;
   struct curl_slist *telnet_vars;    /* Environment variables */
 
   /* suboptions */
   unsigned char subbuffer[SUBBUFSIZE];
   unsigned char *subpointer, *subend;      /* buffer for sub-options */
-
-  TelnetReceive telrcv_state;
 };
 
 
@@ -194,52 +187,13 @@ const struct Curl_handler Curl_handler_telnet = {
   ZERO_NULL,                            /* connection_check */
   PORT_TELNET,                          /* defport */
   CURLPROTO_TELNET,                     /* protocol */
+  CURLPROTO_TELNET,                     /* family */
   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
 };
 
 
-#ifdef USE_WINSOCK
-static CURLcode
-check_wsock2(struct Curl_easy *data)
-{
-  int err;
-  WORD wVersionRequested;
-  WSADATA wsaData;
-
-  DEBUGASSERT(data);
-
-  /* telnet requires at least WinSock 2.0 so ask for it. */
-  wVersionRequested = MAKEWORD(2, 0);
-
-  err = WSAStartup(wVersionRequested, &wsaData);
-
-  /* We must've called this once already, so this call */
-  /* should always succeed.  But, just in case... */
-  if(err != 0) {
-    failf(data,"WSAStartup failed (%d)",err);
-    return CURLE_FAILED_INIT;
-  }
-
-  /* We have to have a WSACleanup call for every successful */
-  /* WSAStartup call. */
-  WSACleanup();
-
-  /* Check that our version is supported */
-  if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
-      HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
-      /* Our version isn't supported */
-    failf(data, "insufficient winsock version to support "
-          "telnet");
-    return CURLE_FAILED_INIT;
-  }
-
-  /* Our version is supported */
-  return CURLE_OK;
-}
-#endif
-
 static
-CURLcode init_telnet(struct connectdata *conn)
+CURLcode init_telnet(struct Curl_easy *data)
 {
   struct TELNET *tn;
 
@@ -247,7 +201,7 @@ CURLcode init_telnet(struct connectdata *conn)
   if(!tn)
     return CURLE_OUT_OF_MEMORY;
 
-  conn->data->req.protop = tn; /* make us known */
+  data->req.p.telnet = tn; /* make us known */
 
   tn->telrcv_state = CURL_TS_DATA;
 
@@ -259,7 +213,7 @@ CURLcode init_telnet(struct connectdata *conn)
   tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
 
   /* To be compliant with previous releases of libcurl
-     we enable this option by default. This behaviour
+     we enable this option by default. This behavior
          can be changed thanks to the "BINARY" option in
          CURLOPT_TELNETOPTIONS
   */
@@ -289,20 +243,20 @@ CURLcode init_telnet(struct connectdata *conn)
   return CURLE_OK;
 }
 
-static void negotiate(struct connectdata *conn)
+static void negotiate(struct Curl_easy *data)
 {
   int i;
-  struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
 
   for(i = 0; i < CURL_NTELOPTS; i++) {
     if(i == CURL_TELOPT_ECHO)
       continue;
 
     if(tn->us_preferred[i] == CURL_YES)
-      set_local_option(conn, i, CURL_YES);
+      set_local_option(data, i, CURL_YES);
 
     if(tn->him_preferred[i] == CURL_YES)
-      set_remote_option(conn, i, CURL_YES);
+      set_remote_option(data, i, CURL_YES);
   }
 }
 
@@ -343,34 +297,34 @@ static void printoption(struct Curl_easy *data,
 }
 #endif
 
-static void send_negotiation(struct connectdata *conn, int cmd, int option)
+static void send_negotiation(struct Curl_easy *data, int cmd, int option)
 {
-   unsigned char buf[3];
-   ssize_t bytes_written;
-   struct Curl_easy *data = conn->data;
+  unsigned char buf[3];
+  ssize_t bytes_written;
+  struct connectdata *conn = data->conn;
 
-   buf[0] = CURL_IAC;
-   buf[1] = (unsigned char)cmd;
-   buf[2] = (unsigned char)option;
+  buf[0] = CURL_IAC;
+  buf[1] = (unsigned char)cmd;
+  buf[2] = (unsigned char)option;
 
-   bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
-   if(bytes_written < 0) {
-     int err = SOCKERRNO;
-     failf(data,"Sending data failed (%d)",err);
-   }
+  bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
+  if(bytes_written < 0) {
+    int err = SOCKERRNO;
+    failf(data,"Sending data failed (%d)",err);
+  }
 
-   printoption(conn->data, "SENT", cmd, option);
+  printoption(data, "SENT", cmd, option);
 }
 
 static
-void set_remote_option(struct connectdata *conn, int option, int newstate)
+void set_remote_option(struct Curl_easy *data, int option, int newstate)
 {
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
   if(newstate == CURL_YES) {
     switch(tn->him[option]) {
     case CURL_NO:
       tn->him[option] = CURL_WANTYES;
-      send_negotiation(conn, CURL_DO, option);
+      send_negotiation(data, CURL_DO, option);
       break;
 
     case CURL_YES:
@@ -409,7 +363,7 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
 
     case CURL_YES:
       tn->him[option] = CURL_WANTNO;
-      send_negotiation(conn, CURL_DONT, option);
+      send_negotiation(data, CURL_DONT, option);
       break;
 
     case CURL_WANTNO:
@@ -437,17 +391,17 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
 }
 
 static
-void rec_will(struct connectdata *conn, int option)
+void rec_will(struct Curl_easy *data, int option)
 {
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
   switch(tn->him[option]) {
   case CURL_NO:
     if(tn->him_preferred[option] == CURL_YES) {
       tn->him[option] = CURL_YES;
-      send_negotiation(conn, CURL_DO, option);
+      send_negotiation(data, CURL_DO, option);
     }
     else
-      send_negotiation(conn, CURL_DONT, option);
+      send_negotiation(data, CURL_DONT, option);
 
     break;
 
@@ -477,7 +431,7 @@ void rec_will(struct connectdata *conn, int option)
     case CURL_OPPOSITE:
       tn->him[option] = CURL_WANTNO;
       tn->himq[option] = CURL_EMPTY;
-      send_negotiation(conn, CURL_DONT, option);
+      send_negotiation(data, CURL_DONT, option);
       break;
     }
     break;
@@ -485,9 +439,9 @@ void rec_will(struct connectdata *conn, int option)
 }
 
 static
-void rec_wont(struct connectdata *conn, int option)
+void rec_wont(struct Curl_easy *data, int option)
 {
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
   switch(tn->him[option]) {
   case CURL_NO:
     /* Already disabled */
@@ -495,7 +449,7 @@ void rec_wont(struct connectdata *conn, int option)
 
   case CURL_YES:
     tn->him[option] = CURL_NO;
-    send_negotiation(conn, CURL_DONT, option);
+    send_negotiation(data, CURL_DONT, option);
     break;
 
   case CURL_WANTNO:
@@ -507,7 +461,7 @@ void rec_wont(struct connectdata *conn, int option)
     case CURL_OPPOSITE:
       tn->him[option] = CURL_WANTYES;
       tn->himq[option] = CURL_EMPTY;
-      send_negotiation(conn, CURL_DO, option);
+      send_negotiation(data, CURL_DO, option);
       break;
     }
     break;
@@ -527,14 +481,14 @@ void rec_wont(struct connectdata *conn, int option)
 }
 
 static void
-set_local_option(struct connectdata *conn, int option, int newstate)
+set_local_option(struct Curl_easy *data, int option, int newstate)
 {
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
   if(newstate == CURL_YES) {
     switch(tn->us[option]) {
     case CURL_NO:
       tn->us[option] = CURL_WANTYES;
-      send_negotiation(conn, CURL_WILL, option);
+      send_negotiation(data, CURL_WILL, option);
       break;
 
     case CURL_YES:
@@ -573,7 +527,7 @@ set_local_option(struct connectdata *conn, int option, int newstate)
 
     case CURL_YES:
       tn->us[option] = CURL_WANTNO;
-      send_negotiation(conn, CURL_WONT, option);
+      send_negotiation(data, CURL_WONT, option);
       break;
 
     case CURL_WANTNO:
@@ -601,26 +555,26 @@ set_local_option(struct connectdata *conn, int option, int newstate)
 }
 
 static
-void rec_do(struct connectdata *conn, int option)
+void rec_do(struct Curl_easy *data, int option)
 {
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
   switch(tn->us[option]) {
   case CURL_NO:
     if(tn->us_preferred[option] == CURL_YES) {
       tn->us[option] = CURL_YES;
-      send_negotiation(conn, CURL_WILL, option);
+      send_negotiation(data, CURL_WILL, option);
       if(tn->subnegotiation[option] == CURL_YES)
         /* transmission of data option */
-        sendsuboption(conn, option);
+        sendsuboption(data, option);
     }
     else if(tn->subnegotiation[option] == CURL_YES) {
       /* send information to achieve this option*/
       tn->us[option] = CURL_YES;
-      send_negotiation(conn, CURL_WILL, option);
-      sendsuboption(conn, option);
+      send_negotiation(data, CURL_WILL, option);
+      sendsuboption(data, option);
     }
     else
-      send_negotiation(conn, CURL_WONT, option);
+      send_negotiation(data, CURL_WONT, option);
     break;
 
   case CURL_YES:
@@ -647,13 +601,13 @@ void rec_do(struct connectdata *conn, int option)
       tn->us[option] = CURL_YES;
       if(tn->subnegotiation[option] == CURL_YES) {
         /* transmission of data option */
-        sendsuboption(conn, option);
+        sendsuboption(data, option);
       }
       break;
     case CURL_OPPOSITE:
       tn->us[option] = CURL_WANTNO;
       tn->himq[option] = CURL_EMPTY;
-      send_negotiation(conn, CURL_WONT, option);
+      send_negotiation(data, CURL_WONT, option);
       break;
     }
     break;
@@ -661,9 +615,9 @@ void rec_do(struct connectdata *conn, int option)
 }
 
 static
-void rec_dont(struct connectdata *conn, int option)
+void rec_dont(struct Curl_easy *data, int option)
 {
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
   switch(tn->us[option]) {
   case CURL_NO:
     /* Already disabled */
@@ -671,7 +625,7 @@ void rec_dont(struct connectdata *conn, int option)
 
   case CURL_YES:
     tn->us[option] = CURL_NO;
-    send_negotiation(conn, CURL_WONT, option);
+    send_negotiation(data, CURL_WONT, option);
     break;
 
   case CURL_WANTNO:
@@ -683,7 +637,7 @@ void rec_dont(struct connectdata *conn, int option)
     case CURL_OPPOSITE:
       tn->us[option] = CURL_WANTYES;
       tn->usq[option] = CURL_EMPTY;
-      send_negotiation(conn, CURL_WILL, option);
+      send_negotiation(data, CURL_WILL, option);
       break;
     }
     break;
@@ -815,14 +769,14 @@ static void printsub(struct Curl_easy *data,
   }
 }
 
-static CURLcode check_telnet_options(struct connectdata *conn)
+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 Curl_easy *data = conn->data;
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
+  struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
   int binary_option;
 
@@ -919,7 +873,7 @@ static CURLcode check_telnet_options(struct connectdata *conn)
  * side.
  */
 
-static void suboption(struct connectdata *conn)
+static void suboption(struct Curl_easy *data)
 {
   struct curl_slist *v;
   unsigned char temp[2048];
@@ -928,8 +882,8 @@ static void suboption(struct connectdata *conn)
   int err;
   char varname[128] = "";
   char varval[128] = "";
-  struct Curl_easy *data = conn->data;
-  struct TELNET *tn = (struct TELNET *)data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
+  struct connectdata *conn = data->conn;
 
   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
   switch(CURL_SB_GET(tn)) {
@@ -996,15 +950,14 @@ static void suboption(struct connectdata *conn)
  * Send suboption information to the server side.
  */
 
-static void sendsuboption(struct connectdata *conn, int option)
+static void sendsuboption(struct Curl_easy *data, int option)
 {
   ssize_t bytes_written;
   int err;
   unsigned short x, y;
   unsigned char *uc1, *uc2;
-
-  struct Curl_easy *data = conn->data;
-  struct TELNET *tn = (struct TELNET *)data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
+  struct connectdata *conn = data->conn;
 
   switch(option) {
   case CURL_TELOPT_NAWS:
@@ -1040,7 +993,7 @@ static void sendsuboption(struct connectdata *conn, int option)
     }
     /* ... then the window size with the send_telnet_data() function
        to deal with 0xFF cases ... */
-    send_telnet_data(conn, (char *)tn->subbuffer + 3, 4);
+    send_telnet_data(data, (char *)tn->subbuffer + 3, 4);
     /* ... and the footer */
     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
     if(bytes_written < 0) {
@@ -1053,7 +1006,7 @@ static void sendsuboption(struct connectdata *conn, int option)
 
 
 static
-CURLcode telrcv(struct connectdata *conn,
+CURLcode telrcv(struct Curl_easy *data,
                 const unsigned char *inbuf, /* Data received from socket */
                 ssize_t count)              /* Number of bytes received */
 {
@@ -1061,12 +1014,11 @@ CURLcode telrcv(struct connectdata *conn,
   CURLcode result;
   int in = 0;
   int startwrite = -1;
-  struct Curl_easy *data = conn->data;
-  struct TELNET *tn = (struct TELNET *)data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
 
 #define startskipping()                                       \
   if(startwrite >= 0) {                                       \
-    result = Curl_client_write(conn,                          \
+    result = Curl_client_write(data,                          \
                                CLIENTWRITE_BODY,              \
                                (char *)&inbuf[startwrite],    \
                                in-startwrite);                \
@@ -1142,28 +1094,28 @@ CURLcode telrcv(struct connectdata *conn,
       case CURL_TS_WILL:
         printoption(data, "RCVD", CURL_WILL, c);
         tn->please_negotiate = 1;
-        rec_will(conn, c);
+        rec_will(data, c);
         tn->telrcv_state = CURL_TS_DATA;
         break;
 
       case CURL_TS_WONT:
         printoption(data, "RCVD", CURL_WONT, c);
         tn->please_negotiate = 1;
-        rec_wont(conn, c);
+        rec_wont(data, c);
         tn->telrcv_state = CURL_TS_DATA;
         break;
 
       case CURL_TS_DO:
         printoption(data, "RCVD", CURL_DO, c);
         tn->please_negotiate = 1;
-        rec_do(conn, c);
+        rec_do(data, c);
         tn->telrcv_state = CURL_TS_DATA;
         break;
 
       case CURL_TS_DONT:
         printoption(data, "RCVD", CURL_DONT, c);
         tn->please_negotiate = 1;
-        rec_dont(conn, c);
+        rec_dont(data, c);
         tn->telrcv_state = CURL_TS_DATA;
         break;
 
@@ -1192,7 +1144,7 @@ CURLcode telrcv(struct connectdata *conn,
             CURL_SB_TERM(tn);
 
             printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
-            suboption(conn);   /* handle sub-option */
+            suboption(data);   /* handle sub-option */
             tn->telrcv_state = CURL_TS_IAC;
             goto process_iac;
           }
@@ -1204,7 +1156,7 @@ CURLcode telrcv(struct connectdata *conn,
           CURL_SB_ACCUM(tn, CURL_SE);
           tn->subpointer -= 2;
           CURL_SB_TERM(tn);
-          suboption(conn);   /* handle sub-option */
+          suboption(data);   /* handle sub-option */
           tn->telrcv_state = CURL_TS_DATA;
         }
         break;
@@ -1216,13 +1168,14 @@ CURLcode telrcv(struct connectdata *conn,
 }
 
 /* Escape and send a telnet data block */
-static CURLcode send_telnet_data(struct connectdata *conn,
+static CURLcode send_telnet_data(struct Curl_easy *data,
                                  char *buffer, ssize_t nread)
 {
   ssize_t escapes, i, outlen;
   unsigned char *outbuf = NULL;
   CURLcode result = CURLE_OK;
   ssize_t bytes_written, total_written;
+  struct connectdata *conn = data->conn;
 
   /* Determine size of new buffer after escaping */
   escapes = 0;
@@ -1261,7 +1214,7 @@ static CURLcode send_telnet_data(struct connectdata *conn,
         break;
       default:                    /* write! */
         bytes_written = 0;
-        result = Curl_write(conn, conn->sock[FIRSTSOCKET],
+        result = Curl_write(data, conn->sock[FIRSTSOCKET],
                             outbuf + total_written,
                             outlen - total_written,
                             &bytes_written);
@@ -1277,10 +1230,10 @@ static CURLcode send_telnet_data(struct connectdata *conn,
   return result;
 }
 
-static CURLcode telnet_done(struct connectdata *conn,
-                                 CURLcode status, bool premature)
+static CURLcode telnet_done(struct Curl_easy *data,
+                            CURLcode status, bool premature)
 {
-  struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+  struct TELNET *tn = data->req.p.telnet;
   (void)status; /* unused */
   (void)premature; /* not used */
 
@@ -1290,22 +1243,17 @@ static CURLcode telnet_done(struct connectdata *conn,
   curl_slist_free_all(tn->telnet_vars);
   tn->telnet_vars = NULL;
 
-  Curl_safefree(conn->data->req.protop);
+  Curl_safefree(data->req.p.telnet);
 
   return CURLE_OK;
 }
 
-static CURLcode telnet_do(struct connectdata *conn, bool *done)
+static CURLcode telnet_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 #ifdef USE_WINSOCK
-  HMODULE wsock2;
-  WSOCK2_FUNC close_event_func;
-  WSOCK2_EVENT create_event_func;
-  WSOCK2_FUNC event_select_func;
-  WSOCK2_FUNC enum_netevents_func;
   WSAEVENT event_handle;
   WSANETWORKEVENTS events;
   HANDLE stdin_handle;
@@ -1329,86 +1277,32 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
 
   *done = TRUE; /* unconditionally */
 
-  result = init_telnet(conn);
+  result = init_telnet(data);
   if(result)
     return result;
 
-  tn = (struct TELNET *)data->req.protop;
+  tn = data->req.p.telnet;
 
-  result = check_telnet_options(conn);
+  result = check_telnet_options(data);
   if(result)
     return result;
 
 #ifdef USE_WINSOCK
-  /*
-  ** This functionality only works with WinSock >= 2.0.  So,
-  ** make sure we have it.
-  */
-  result = check_wsock2(data);
-  if(result)
-    return result;
-
-  /* OK, so we have WinSock 2.0.  We need to dynamically */
-  /* load ws2_32.dll and get the function pointers we need. */
-  wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
-  if(wsock2 == NULL) {
-    failf(data, "failed to load WS2_32.DLL (%u)", GetLastError());
-    return CURLE_FAILED_INIT;
-  }
-
-  /* Grab a pointer to WSACreateEvent */
-  create_event_func =
-    CURLX_FUNCTION_CAST(WSOCK2_EVENT,
-                        (GetProcAddress(wsock2, "WSACreateEvent")));
-  if(create_event_func == NULL) {
-    failf(data, "failed to find WSACreateEvent function (%u)", GetLastError());
-    FreeLibrary(wsock2);
-    return CURLE_FAILED_INIT;
-  }
-
-  /* And WSACloseEvent */
-  close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
-  if(close_event_func == NULL) {
-    failf(data, "failed to find WSACloseEvent function (%u)", GetLastError());
-    FreeLibrary(wsock2);
-    return CURLE_FAILED_INIT;
-  }
-
-  /* And WSAEventSelect */
-  event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
-  if(event_select_func == NULL) {
-    failf(data, "failed to find WSAEventSelect function (%u)", GetLastError());
-    FreeLibrary(wsock2);
-    return CURLE_FAILED_INIT;
-  }
-
-  /* And WSAEnumNetworkEvents */
-  enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
-  if(enum_netevents_func == NULL) {
-    failf(data, "failed to find WSAEnumNetworkEvents function (%u)",
-          GetLastError());
-    FreeLibrary(wsock2);
-    return CURLE_FAILED_INIT;
-  }
-
   /* We want to wait for both stdin and the socket. Since
   ** the select() function in winsock only works on sockets
   ** we have to use the WaitForMultipleObjects() call.
   */
 
   /* First, create a sockets event object */
-  event_handle = (WSAEVENT)create_event_func();
+  event_handle = WSACreateEvent();
   if(event_handle == WSA_INVALID_EVENT) {
     failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
-    FreeLibrary(wsock2);
     return CURLE_FAILED_INIT;
   }
 
   /* Tell winsock what events we want to listen to */
-  if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
-     SOCKET_ERROR) {
-    close_event_func(event_handle);
-    FreeLibrary(wsock2);
+  if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
+    WSACloseEvent(event_handle);
     return CURLE_OK;
   }
 
@@ -1439,6 +1333,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
     DWORD waitret = WaitForMultipleObjects(obj_count, objs,
                                            FALSE, wait_timeout);
     switch(waitret) {
+
     case WAIT_TIMEOUT:
     {
       for(;;) {
@@ -1481,7 +1376,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
           }
         }
 
-        result = send_telnet_data(conn, buf, readfile_read);
+        result = send_telnet_data(data, buf, readfile_read);
         if(result) {
           keepon = FALSE;
           break;
@@ -1499,7 +1394,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
         break;
       }
 
-      result = send_telnet_data(conn, buf, readfile_read);
+      result = send_telnet_data(data, buf, readfile_read);
       if(result) {
         keepon = FALSE;
         break;
@@ -1508,9 +1403,9 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
     break;
 
     case WAIT_OBJECT_0:
-
+    {
       events.lNetworkEvents = 0;
-      if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
+      if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) {
         err = SOCKERRNO;
         if(err != EINPROGRESS) {
           infof(data, "WSAEnumNetworkEvents failed (%d)", err);
@@ -1521,7 +1416,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
       }
       if(events.lNetworkEvents & FD_READ) {
         /* read data from network */
-        result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
+        result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
         /* read would've blocked. Loop again */
         if(result == CURLE_AGAIN)
           break;
@@ -1537,7 +1432,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
           break;
         }
 
-        result = telrcv(conn, (unsigned char *) buf, nread);
+        result = telrcv(data, (unsigned char *) buf, nread);
         if(result) {
           keepon = FALSE;
           break;
@@ -1547,14 +1442,15 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
            otherwise don't. We don't want to speak telnet with
            non-telnet servers, like POP or SMTP. */
         if(tn->please_negotiate && !tn->already_negotiated) {
-          negotiate(conn);
+          negotiate(data);
           tn->already_negotiated = 1;
         }
       }
       if(events.lNetworkEvents & FD_CLOSE) {
         keepon = FALSE;
       }
-      break;
+    }
+    break;
 
     }
 
@@ -1569,19 +1465,9 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
   }
 
   /* We called WSACreateEvent, so call WSACloseEvent */
-  if(!close_event_func(event_handle)) {
+  if(!WSACloseEvent(event_handle)) {
     infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
   }
-
-  /* "Forget" pointers into the library we're about to free */
-  create_event_func = NULL;
-  close_event_func = NULL;
-  event_select_func = NULL;
-  enum_netevents_func = NULL;
-
-  /* We called LoadLibrary, so call FreeLibrary */
-  if(!FreeLibrary(wsock2))
-    infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError());
 #else
   pfd[0].fd = sockfd;
   pfd[0].events = POLLIN;
@@ -1610,7 +1496,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
     default:                    /* read! */
       if(pfd[0].revents & POLLIN) {
         /* read data from network */
-        result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
+        result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
         /* read would've blocked. Loop again */
         if(result == CURLE_AGAIN)
           break;
@@ -1628,7 +1514,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
 
         total_dl += nread;
         Curl_pgrsSetDownloadCounter(data, total_dl);
-        result = telrcv(conn, (unsigned char *)buf, nread);
+        result = telrcv(data, (unsigned char *)buf, nread);
         if(result) {
           keepon = FALSE;
           break;
@@ -1638,7 +1524,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
            otherwise don't. We don't want to speak telnet with
            non-telnet servers, like POP or SMTP. */
         if(tn->please_negotiate && !tn->already_negotiated) {
-          negotiate(conn);
+          negotiate(data);
           tn->already_negotiated = 1;
         }
       }
@@ -1662,7 +1548,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
       }
 
       if(nread > 0) {
-        result = send_telnet_data(conn, buf, nread);
+        result = send_telnet_data(data, buf, nread);
         if(result) {
           keepon = FALSE;
           break;
@@ -1685,7 +1571,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
       }
     }
 
-    if(Curl_pgrsUpdate(conn)) {
+    if(Curl_pgrsUpdate(data)) {
       result = CURLE_ABORTED_BY_CALLBACK;
       break;
     }
index 431427f..1427473 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 378d956..3f1d1b5 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -124,7 +124,7 @@ struct tftp_state_data {
   tftp_mode_t     mode;
   tftp_error_t    error;
   tftp_event_t    event;
-  struct connectdata      *conn;
+  struct Curl_easy *data;
   curl_socket_t   sockfd;
   int             retries;
   int             retry_time;
@@ -132,7 +132,6 @@ struct tftp_state_data {
   time_t          start_time;
   time_t          max_time;
   time_t          rx_time;
-  unsigned short  block;
   struct Curl_sockaddr_storage   local_addr;
   struct Curl_sockaddr_storage   remote_addr;
   curl_socklen_t  remote_addrlen;
@@ -140,6 +139,7 @@ struct tftp_state_data {
   int             sbytes;
   int             blksize;
   int             requested_blksize;
+  unsigned short  block;
   struct tftp_packet rpacket;
   struct tftp_packet spacket;
 };
@@ -148,16 +148,19 @@ struct tftp_state_data {
 /* Forward declarations */
 static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event);
 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event);
-static CURLcode tftp_connect(struct connectdata *conn, bool *done);
-static CURLcode tftp_disconnect(struct connectdata *conn,
+static CURLcode tftp_connect(struct Curl_easy *data, bool *done);
+static CURLcode tftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection);
-static CURLcode tftp_do(struct connectdata *conn, bool *done);
-static CURLcode tftp_done(struct connectdata *conn,
+static CURLcode tftp_do(struct Curl_easy *data, bool *done);
+static CURLcode tftp_done(struct Curl_easy *data,
                           CURLcode, bool premature);
-static CURLcode tftp_setup_connection(struct connectdata *conn);
-static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
-static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
-static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks);
+static CURLcode tftp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done);
+static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done);
+static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t *socks);
 static CURLcode tftp_translate_code(tftp_error_t error);
 
 
@@ -183,6 +186,7 @@ const struct Curl_handler Curl_handler_tftp = {
   ZERO_NULL,                            /* connection_check */
   PORT_TFTP,                            /* defport */
   CURLPROTO_TFTP,                       /* protocol */
+  CURLPROTO_TFTP,                       /* family */
   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
 };
 
@@ -205,11 +209,11 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
   time(&state->start_time);
 
   /* Compute drop-dead time */
-  timeout_ms = Curl_timeleft(state->conn->data, NULL, start);
+  timeout_ms = Curl_timeleft(state->data, NULL, start);
 
   if(timeout_ms < 0) {
     /* time-out, bail out, go home */
-    failf(state->conn->data, "Connection time-out");
+    failf(state->data, "Connection time-out");
     return CURLE_OPERATION_TIMEDOUT;
   }
 
@@ -260,7 +264,7 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
   if(state->retry_time<1)
     state->retry_time = 1;
 
-  infof(state->conn->data,
+  infof(state->data,
         "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
         (int)state->state, (long)(state->max_time-state->start_time),
         state->retry_time, state->retry_max);
@@ -302,7 +306,7 @@ static unsigned short getrpacketblock(const struct tftp_packet *packet)
   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
 }
 
-static size_t Curl_strnlen(const char *string, size_t maxlen)
+static size_t tftp_strnlen(const char *string, size_t maxlen)
 {
   const char *end = memchr(string, '\0', maxlen);
   return end ? (size_t) (end - string) : maxlen;
@@ -313,14 +317,14 @@ static const char *tftp_option_get(const char *buf, size_t len,
 {
   size_t loc;
 
-  loc = Curl_strnlen(buf, len);
+  loc = tftp_strnlen(buf, len);
   loc++; /* NULL term */
 
   if(loc >= len)
     return NULL;
   *option = buf;
 
-  loc += Curl_strnlen(buf + loc, len-loc);
+  loc += tftp_strnlen(buf + loc, len-loc);
   loc++; /* NULL term */
 
   if(loc > len)
@@ -334,7 +338,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
                                       const char *ptr, int len)
 {
   const char *tmp = ptr;
-  struct Curl_easy *data = state->conn->data;
+  struct Curl_easy *data = state->data;
 
   /* if OACK doesn't contain blksize option, the default (512) must be used */
   state->blksize = TFTP_BLKSIZE_DEFAULT;
@@ -418,7 +422,7 @@ static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
 {
   CURLcode result;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-  struct Curl_easy *data = state->conn->data;
+  struct Curl_easy *data = state->data;
 
   infof(data, "%s\n", "Connected for transmit");
 #endif
@@ -434,7 +438,7 @@ static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
 {
   CURLcode result;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-  struct Curl_easy *data = state->conn->data;
+  struct Curl_easy *data = state->data;
 
   infof(data, "%s\n", "Connected for receive");
 #endif
@@ -452,7 +456,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
   ssize_t senddata;
   const char *mode = "octet";
   char *filename;
-  struct Curl_easy *data = state->conn->data;
+  struct Curl_easy *data = state->data;
   CURLcode result = CURLE_OK;
 
   /* Set ascii mode if -B flag was used */
@@ -474,7 +478,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
     if(data->set.upload) {
       /* If we are uploading, send an WRQ */
       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
-      state->conn->data->req.upload_fromhere =
+      state->data->req.upload_fromhere =
         (char *)state->spacket.data + 4;
       if(data->state.infilesize != -1)
         Curl_pgrsSetUploadSize(data, data->state.infilesize);
@@ -486,13 +490,13 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
     /* As RFC3617 describes the separator slash is not actually part of the
        file name so we skip the always-present first letter of the path
        string. */
-    result = Curl_urldecode(data, &state->conn->data->state.up.path[1], 0,
+    result = Curl_urldecode(data, &state->data->state.up.path[1], 0,
                             &filename, NULL, REJECT_ZERO);
     if(result)
       return result;
 
     if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
-      failf(data, "TFTP file name too long\n");
+      failf(data, "TFTP file name too long");
       free(filename);
       return CURLE_TFTP_ILLEGAL; /* too long file name field */
     }
@@ -550,8 +554,8 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
        not have a size_t argument, like older unixes that want an 'int' */
     senddata = sendto(state->sockfd, (void *)state->spacket.data,
                       (SEND_TYPE_ARG3)sbytes, 0,
-                      state->conn->ip_addr->ai_addr,
-                      state->conn->ip_addr->ai_addrlen);
+                      data->conn->ip_addr->ai_addr,
+                      data->conn->ip_addr->ai_addrlen);
     if(senddata != (ssize_t)sbytes) {
       char buffer[STRERROR_LEN];
       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
@@ -581,7 +585,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
     break;
 
   default:
-    failf(state->conn->data, "tftp_send_first: internal error");
+    failf(state->data, "tftp_send_first: internal error");
     break;
   }
 
@@ -604,7 +608,7 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
 {
   ssize_t sbytes;
   int rblock;
-  struct Curl_easy *data = state->conn->data;
+  struct Curl_easy *data = state->data;
   char buffer[STRERROR_LEN];
 
   switch(event) {
@@ -724,7 +728,7 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
  **********************************************************/
 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
 {
-  struct Curl_easy *data = state->conn->data;
+  struct Curl_easy *data = state->data;
   ssize_t sbytes;
   CURLcode result = CURLE_OK;
   struct SingleRequest *k = &data->req;
@@ -793,14 +797,13 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
      * data block.
      * */
     state->sbytes = 0;
-    state->conn->data->req.upload_fromhere = (char *)state->spacket.data + 4;
+    state->data->req.upload_fromhere = (char *)state->spacket.data + 4;
     do {
-      result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
-                                   &cb);
+      result = Curl_fillreadbuffer(data, state->blksize - state->sbytes, &cb);
       if(result)
         return result;
       state->sbytes += (int)cb;
-      state->conn->data->req.upload_fromhere += cb;
+      state->data->req.upload_fromhere += cb;
     } while(state->sbytes < state->blksize && cb != 0);
 
     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
@@ -926,7 +929,7 @@ static CURLcode tftp_state_machine(struct tftp_state_data *state,
                                    tftp_event_t event)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = state->conn->data;
+  struct Curl_easy *data = state->data;
 
   switch(state->state) {
   case TFTP_STATE_START:
@@ -961,9 +964,11 @@ static CURLcode tftp_state_machine(struct tftp_state_data *state,
  * The disconnect callback
  *
  **********************************************************/
-static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode tftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
 {
   struct tftp_state_data *state = conn->proto.tftpc;
+  (void) data;
   (void) dead_connection;
 
   /* done, free dynamically allocated pkt buffers */
@@ -983,11 +988,12 @@ static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
  * The connect callback
  *
  **********************************************************/
-static CURLcode tftp_connect(struct connectdata *conn, bool *done)
+static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
 {
   struct tftp_state_data *state;
   int blksize;
   int need_blksize;
+  struct connectdata *conn = data->conn;
 
   blksize = TFTP_BLKSIZE_DEFAULT;
 
@@ -996,8 +1002,8 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
     return CURLE_OUT_OF_MEMORY;
 
   /* alloc pkt buffers based on specified blksize */
-  if(conn->data->set.tftp_blksize) {
-    blksize = (int)conn->data->set.tftp_blksize;
+  if(data->set.tftp_blksize) {
+    blksize = (int)data->set.tftp_blksize;
     if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
       return CURLE_TFTP_ILLEGAL;
   }
@@ -1025,8 +1031,8 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
    * little gain for UDP */
   connclose(conn, "TFTP");
 
-  state->conn = conn;
-  state->sockfd = state->conn->sock[FIRSTSOCKET];
+  state->data = data;
+  state->sockfd = conn->sock[FIRSTSOCKET];
   state->state = TFTP_STATE_START;
   state->error = TFTP_ERR_NONE;
   state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
@@ -1055,14 +1061,14 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
                   conn->ip_addr->ai_addrlen);
     if(rc) {
       char buffer[STRERROR_LEN];
-      failf(conn->data, "bind() failed; %s",
+      failf(data, "bind() failed; %s",
             Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
       return CURLE_COULDNT_CONNECT;
     }
     conn->bits.bound = TRUE;
   }
 
-  Curl_pgrsStartNow(conn->data);
+  Curl_pgrsStartNow(data);
 
   *done = TRUE;
 
@@ -1076,16 +1082,17 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
  * The done callback
  *
  **********************************************************/
-static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
+static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
                           bool premature)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct tftp_state_data *state = conn->proto.tftpc;
 
   (void)status; /* unused */
   (void)premature; /* not used */
 
-  if(Curl_pgrsDone(conn))
+  if(Curl_pgrsDone(data))
     return CURLE_ABORTED_BY_CALLBACK;
 
   /* If we have encountered an error */
@@ -1102,8 +1109,10 @@ static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
  * The getsock callback
  *
  **********************************************************/
-static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int tftp_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks)
 {
+  (void)data;
   socks[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_READSOCK(0);
 }
@@ -1115,12 +1124,12 @@ static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks)
  * Called once select fires and data is ready on the socket
  *
  **********************************************************/
-static CURLcode tftp_receive_packet(struct connectdata *conn)
+static CURLcode tftp_receive_packet(struct Curl_easy *data)
 {
   struct Curl_sockaddr_storage fromaddr;
   curl_socklen_t        fromlen;
   CURLcode              result = CURLE_OK;
-  struct Curl_easy  *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct tftp_state_data *state = conn->proto.tftpc;
   struct SingleRequest  *k = &data->req;
 
@@ -1153,7 +1162,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
       /* Don't pass to the client empty or retransmitted packets */
       if(state->rbytes > 4 &&
          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
-        result = Curl_client_write(conn, CLIENTWRITE_BODY,
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
                                    (char *)state->rpacket.data + 4,
                                    state->rbytes-4);
         if(result) {
@@ -1170,7 +1179,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
       char *str = (char *)state->rpacket.data + 4;
       size_t strn = state->rbytes - 4;
       state->error = (tftp_error_t)error;
-      if(Curl_strnlen(str, strn) < strn)
+      if(tftp_strnlen(str, strn) < strn)
         infof(data, "TFTP error: %s\n", str);
       break;
     }
@@ -1191,7 +1200,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
     }
 
     /* Update the progress meter */
-    if(Curl_pgrsUpdate(conn)) {
+    if(Curl_pgrsUpdate(data)) {
       tftp_state_machine(state, TFTP_EVENT_ERROR);
       return CURLE_ABORTED_BY_CALLBACK;
     }
@@ -1206,9 +1215,10 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
  * Check if timeouts have been reached
  *
  **********************************************************/
-static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
+static long tftp_state_timeout(struct Curl_easy *data, tftp_event_t *event)
 {
   time_t current;
+  struct connectdata *conn = data->conn;
   struct tftp_state_data *state = conn->proto.tftpc;
 
   if(event)
@@ -1216,7 +1226,7 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
 
   time(&current);
   if(current > state->max_time) {
-    DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
+    DEBUGF(infof(data, "timeout: %ld > %ld\n",
                  (long)current, (long)state->max_time));
     state->error = TFTP_ERR_TIMEOUT;
     state->state = TFTP_STATE_FIN;
@@ -1241,13 +1251,13 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
  * Handle single RX socket event and return
  *
  **********************************************************/
-static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
+static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
 {
-  tftp_event_t          event;
-  CURLcode              result = CURLE_OK;
-  struct Curl_easy  *data = conn->data;
+  tftp_event_t event;
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct tftp_state_data *state = conn->proto.tftpc;
-  long                  timeout_ms = tftp_state_timeout(conn, &event);
+  long timeout_ms = tftp_state_timeout(data, &event);
 
   *done = FALSE;
 
@@ -1276,7 +1286,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
       state->event = TFTP_EVENT_ERROR;
     }
     else if(rc != 0) {
-      result = tftp_receive_packet(conn);
+      result = tftp_receive_packet(data);
       if(result)
         return result;
       result = tftp_state_machine(state, state->event);
@@ -1300,22 +1310,22 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
  * Called from multi.c while DOing
  *
  **********************************************************/
-static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
+static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
 {
   CURLcode result;
-  result = tftp_multi_statemach(conn, dophase_done);
+  result = tftp_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
   else if(!result) {
     /* The multi code doesn't have this logic for the DOING state so we
        provide it for TFTP since it may do the entire transfer in this
        state. */
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
-      result = Curl_speedcheck(conn->data, Curl_now());
+      result = Curl_speedcheck(data, Curl_now());
   }
   return result;
 }
@@ -1327,9 +1337,10 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
  * Entry point for transfer from tftp_do, sarts state mach
  *
  **********************************************************/
-static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
+static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
 {
-  CURLcode              result = CURLE_OK;
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct tftp_state_data *state = conn->proto.tftpc;
 
   *dophase_done = FALSE;
@@ -1339,10 +1350,10 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
   if((state->state == TFTP_STATE_FIN) || result)
     return result;
 
-  tftp_multi_statemach(conn, dophase_done);
+  tftp_multi_statemach(data, dophase_done);
 
   if(*dophase_done)
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
 
   return result;
 }
@@ -1358,15 +1369,16 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
  *
  **********************************************************/
 
-static CURLcode tftp_do(struct connectdata *conn, bool *done)
+static CURLcode tftp_do(struct Curl_easy *data, bool *done)
 {
   struct tftp_state_data *state;
   CURLcode result;
+  struct connectdata *conn = data->conn;
 
   *done = FALSE;
 
   if(!conn->proto.tftpc) {
-    result = tftp_connect(conn, done);
+    result = tftp_connect(data, done);
     if(result)
       return result;
   }
@@ -1375,7 +1387,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
   if(!state)
     return CURLE_TFTP_ILLEGAL;
 
-  result = tftp_perform(conn, done);
+  result = tftp_perform(data, done);
 
   /* If tftp_perform() returned an error, use that for return code. If it
      was OK, see if tftp_translate_code() has an error. */
@@ -1386,9 +1398,9 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
   return result;
 }
 
-static CURLcode tftp_setup_connection(struct connectdata *conn)
+static CURLcode tftp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
-  struct Curl_easy *data = conn->data;
   char *type;
 
   conn->transport = TRNSPRT_UDP;
index 3334830..4b5bea2 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index e761966..8523dad 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 53e0636..685e729 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index a07c7af..2f29b29 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -78,6 +78,7 @@
 #include "mime.h"
 #include "strcase.h"
 #include "urlapi-int.h"
+#include "hsts.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
  *
  * Returns a pointer to the first matching header or NULL if none matched.
  */
-char *Curl_checkheaders(const struct connectdata *conn,
+char *Curl_checkheaders(const struct Curl_easy *data,
                         const char *thisheader)
 {
   struct curl_slist *head;
   size_t thislen = strlen(thisheader);
-  struct Curl_easy *data = conn->data;
 
   for(head = data->set.headers; head; head = head->next) {
     if(strncasecompare(head->data, thisheader, thislen) &&
@@ -124,8 +124,8 @@ CURLcode Curl_get_upload_buffer(struct Curl_easy *data)
  * This function will be called to loop through the trailers buffer
  * until no more data is available for sending.
  */
-static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems,
-                                 void *raw)
+static size_t trailers_read(char *buffer, size_t size, size_t nitems,
+                            void *raw)
 {
   struct Curl_easy *data = (struct Curl_easy *)raw;
   struct dynbuf *trailers_buf = &data->state.trailers_buf;
@@ -141,7 +141,7 @@ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems,
   return to_copy;
 }
 
-static size_t Curl_trailers_left(void *raw)
+static size_t trailers_left(void *raw)
 {
   struct Curl_easy *data = (struct Curl_easy *)raw;
   struct dynbuf *trailers_buf = &data->state.trailers_buf;
@@ -153,10 +153,9 @@ static size_t Curl_trailers_left(void *raw)
  * This function will call the read callback to fill our buffer with data
  * to upload.
  */
-CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
+CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
                              size_t *nreadp)
 {
-  struct Curl_easy *data = conn->data;
   size_t buffersize = bytes;
   size_t nread;
 
@@ -165,9 +164,10 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
 
 #ifdef CURL_DOES_CONVERSIONS
   bool sending_http_headers = FALSE;
+  struct connectdata *conn = data->conn;
 
   if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
-    const struct HTTP *http = data->req.protop;
+    const struct HTTP *http = data->req.p.http;
 
     if(http->sending == HTTPSEND_REQUEST)
       /* We're sending the HTTP request headers, not the data.
@@ -230,7 +230,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
        simply return to the previous point in the state machine as if
        nothing happened.
        */
-    readfunc = Curl_trailers_read;
+    readfunc = trailers_read;
     extra_data = (void *)data;
   }
   else
@@ -253,7 +253,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
   if(nread == CURL_READFUNC_PAUSE) {
     struct SingleRequest *k = &data->req;
 
-    if(conn->handler->flags & PROTOPT_NONETWORK) {
+    if(data->conn->handler->flags & PROTOPT_NONETWORK) {
       /* protocols that work without network cannot be paused. This is
          actually only FILE:// just now, and it can't pause since the transfer
          isn't done using the "normal" procedure. */
@@ -366,7 +366,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
 
 #ifndef CURL_DISABLE_HTTP
     if(data->state.trailers_state == TRAILERS_SENDING &&
-       !Curl_trailers_left(data)) {
+       !trailers_left(data)) {
       Curl_dyn_free(&data->state.trailers_buf);
       data->state.trailers_state = TRAILERS_DONE;
       data->set.trailer_data = NULL;
@@ -409,9 +409,9 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
  * POST/PUT with multi-pass authentication when a sending was denied and a
  * resend is necessary.
  */
-CURLcode Curl_readrewind(struct connectdata *conn)
+CURLcode Curl_readrewind(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_mimepart *mimepart = &data->set.mimepost;
 
   conn->bits.rewindaftersend = FALSE; /* we rewind now */
@@ -426,7 +426,7 @@ CURLcode Curl_readrewind(struct connectdata *conn)
      CURLOPT_HTTPPOST, call app to rewind
   */
   if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
-    struct HTTP *http = data->req.protop;
+    struct HTTP *http = data->req.p.http;
 
     if(http->sendit)
       mimepart = http->sendit;
@@ -435,9 +435,10 @@ CURLcode Curl_readrewind(struct connectdata *conn)
     ; /* do nothing */
   else if(data->state.httpreq == HTTPREQ_POST_MIME ||
           data->state.httpreq == HTTPREQ_POST_FORM) {
-    if(Curl_mime_rewind(mimepart)) {
+    CURLcode result = Curl_mime_rewind(mimepart);
+    if(result) {
       failf(data, "Cannot rewind mime/post data");
-      return CURLE_SEND_FAIL_REWIND;
+      return result;
     }
   }
   else {
@@ -598,7 +599,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
 
     if(bytestoread) {
       /* receive data from the network! */
-      result = Curl_read(conn, conn->sockfd, buf, bytestoread, &nread);
+      result = Curl_read(data, conn->sockfd, buf, bytestoread, &nread);
 
       /* read would've blocked */
       if(CURLE_AGAIN == result)
@@ -707,64 +708,10 @@ static CURLcode readwrite_data(struct Curl_easy *data,
            write a piece of the body */
         if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
           /* HTTP-only checks */
-
-          if(data->req.newurl) {
-            if(conn->bits.close) {
-              /* Abort after the headers if "follow Location" is set
-                 and we're set to close anyway. */
-              k->keepon &= ~KEEP_RECV;
-              *done = TRUE;
-              return CURLE_OK;
-            }
-            /* We have a new url to load, but since we want to be able
-               to re-use this connection properly, we read the full
-               response in "ignore more" */
-            k->ignorebody = TRUE;
-            infof(data, "Ignoring the response-body\n");
-          }
-          if(data->state.resume_from && !k->content_range &&
-             (data->state.httpreq == HTTPREQ_GET) &&
-             !k->ignorebody) {
-
-            if(k->size == data->state.resume_from) {
-              /* The resume point is at the end of file, consider this fine
-                 even if it doesn't allow resume from here. */
-              infof(data, "The entire document is already downloaded");
-              connclose(conn, "already downloaded");
-              /* Abort download */
-              k->keepon &= ~KEEP_RECV;
-              *done = TRUE;
-              return CURLE_OK;
-            }
-
-            /* we wanted to resume a download, although the server doesn't
-             * seem to support this and we did this with a GET (if it
-             * wasn't a GET we did a POST or PUT resume) */
-            failf(data, "HTTP server doesn't seem to support "
-                  "byte ranges. Cannot resume.");
-            return CURLE_RANGE_ERROR;
-          }
-
-          if(data->set.timecondition && !data->state.range) {
-            /* A time condition has been set AND no ranges have been
-               requested. This seems to be what chapter 13.3.4 of
-               RFC 2616 defines to be the correct action for a
-               HTTP/1.1 client */
-
-            if(!Curl_meets_timecondition(data, k->timeofdoc)) {
-              *done = TRUE;
-              /* We're simulating a http 304 from server so we return
-                 what should have been returned from the server */
-              data->info.httpcode = 304;
-              infof(data, "Simulate a HTTP 304 response!\n");
-              /* we abort the transfer before it is completed == we ruin the
-                 re-use ability. Close the connection */
-              connclose(conn, "Simulated 304 handling");
-              return CURLE_OK;
-            }
-          } /* we have a time condition */
-
-        } /* this is HTTP or RTSP */
+          result = Curl_http_firstwrite(data, conn, done);
+          if(result || *done)
+            return result;
+        }
       } /* this is the first time we write a body part */
 #endif /* CURL_DISABLE_HTTP */
 
@@ -795,7 +742,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
          */
         CURLcode extra;
         CHUNKcode res =
-          Curl_httpchunk_read(conn, k->str, nread, &nread, &extra);
+          Curl_httpchunk_read(data, k->str, nread, &nread, &extra);
 
         if(CHUNKE_OK < res) {
           if(CHUNKE_PASSTHRU_ERROR == res) {
@@ -806,18 +753,15 @@ static CURLcode readwrite_data(struct Curl_easy *data,
           return CURLE_RECV_ERROR;
         }
         if(CHUNKE_STOP == res) {
-          size_t dataleft;
           /* we're done reading chunks! */
           k->keepon &= ~KEEP_RECV; /* read no more */
 
-          /* There are now possibly N number of bytes at the end of the
-             str buffer that weren't written to the client.
-             Push it back to be read on the next pass. */
-
-          dataleft = conn->chunk.dataleft;
-          if(dataleft != 0) {
-            infof(conn->data, "Leftovers after chunking: %zu bytes\n",
-                  dataleft);
+          /* N number of bytes at the end of the str buffer that weren't
+             written to the client. */
+          if(conn->chunk.datasize) {
+            infof(data, "Leftovers after chunking: % "
+                  CURL_FORMAT_CURL_OFF_T "u bytes\n",
+                  conn->chunk.datasize);
           }
         }
         /* If it returned OK, we just keep going */
@@ -867,11 +811,11 @@ static CURLcode readwrite_data(struct Curl_easy *data,
 
           /* Don't let excess data pollute body writes */
           if(k->maxdownload == -1 || (curl_off_t)headlen <= k->maxdownload)
-            result = Curl_client_write(conn, CLIENTWRITE_BODY,
+            result = Curl_client_write(data, CLIENTWRITE_BODY,
                                        Curl_dyn_ptr(&data->state.headerb),
                                        headlen);
           else
-            result = Curl_client_write(conn, CLIENTWRITE_BODY,
+            result = Curl_client_write(data, CLIENTWRITE_BODY,
                                        Curl_dyn_ptr(&data->state.headerb),
                                        (size_t)k->maxdownload);
 
@@ -884,19 +828,19 @@ static CURLcode readwrite_data(struct Curl_easy *data,
              in http_chunks.c.
              Make sure that ALL_CONTENT_ENCODINGS contains all the
              encodings handled here. */
-          if(conn->data->set.http_ce_skip || !k->writer_stack) {
+          if(data->set.http_ce_skip || !k->writer_stack) {
             if(!k->ignorebody) {
 #ifndef CURL_DISABLE_POP3
               if(conn->handler->protocol & PROTO_FAMILY_POP3)
-                result = Curl_pop3_write(conn, k->str, nread);
+                result = Curl_pop3_write(data, k->str, nread);
               else
 #endif /* CURL_DISABLE_POP3 */
-                result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
+                result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
                                            nread);
             }
           }
           else if(!k->ignorebody)
-            result = Curl_unencode_write(conn, k->writer_stack, k->str, nread);
+            result = Curl_unencode_write(data, k->writer_stack, k->str, nread);
         }
         k->badheader = HEADER_NORMAL; /* taken care of now */
 
@@ -957,17 +901,18 @@ static CURLcode readwrite_data(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-CURLcode Curl_done_sending(struct connectdata *conn,
+CURLcode Curl_done_sending(struct Curl_easy *data,
                            struct SingleRequest *k)
 {
+  struct connectdata *conn = data->conn;
   k->keepon &= ~KEEP_SEND; /* we're done writing */
 
   /* These functions should be moved into the handler struct! */
-  Curl_http2_done_sending(conn);
-  Curl_quic_done_sending(conn);
+  Curl_http2_done_sending(data, conn);
+  Curl_quic_done_sending(data);
 
   if(conn->bits.rewindaftersend) {
-    CURLcode result = Curl_readrewind(conn);
+    CURLcode result = Curl_readrewind(data);
     if(result)
       return result;
   }
@@ -1015,6 +960,8 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
   *didwhat |= KEEP_SEND;
 
   do {
+    curl_off_t nbody;
+
     /* only read more data if there's no upload data already
        present in the upload buffer */
     if(0 == k->upload_present) {
@@ -1028,7 +975,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
         /* HTTP pollution, this should be written nicer to become more
            protocol agnostic. */
         size_t fillcount;
-        struct HTTP *http = k->protop;
+        struct HTTP *http = k->p.http;
 
         if((k->exp100 == EXP100_SENDING_REQUEST) &&
            (http->sending == HTTPSEND_BODY)) {
@@ -1053,7 +1000,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
             sending_http_headers = FALSE;
         }
 
-        result = Curl_fillreadbuffer(conn, data->set.upload_buffer_size,
+        result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
                                      &fillcount);
         if(result)
           return result;
@@ -1068,7 +1015,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
         break;
       }
       if(nread <= 0) {
-        result = Curl_done_sending(conn, k);
+        result = Curl_done_sending(data, k);
         if(result)
           return result;
         break;
@@ -1130,7 +1077,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
 
 #ifndef CURL_DISABLE_SMTP
       if(conn->handler->protocol & PROTO_FAMILY_SMTP) {
-        result = Curl_smtp_escape_eob(conn, nread);
+        result = Curl_smtp_escape_eob(data, nread);
         if(result)
           return result;
       }
@@ -1142,7 +1089,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
     }
 
     /* write to socket (send away data) */
-    result = Curl_write(conn,
+    result = Curl_write(data,
                         conn->writesockfd,  /* socket to send to */
                         k->upload_fromhere, /* buffer pointer */
                         k->upload_present,  /* buffer size */
@@ -1152,13 +1099,26 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
 
     win_update_buffer_size(conn->writesockfd);
 
-    if(data->set.verbose)
+    if(k->pendingheader) {
+      /* parts of what was sent was header */
+      curl_off_t n = CURLMIN(k->pendingheader, bytes_written);
       /* show the data before we change the pointer upload_fromhere */
-      Curl_debug(data, CURLINFO_DATA_OUT, k->upload_fromhere,
-                 (size_t)bytes_written);
+      Curl_debug(data, CURLINFO_HEADER_OUT, k->upload_fromhere, (size_t)n);
+      k->pendingheader -= n;
+      nbody = bytes_written - n; /* size of the written body part */
+    }
+    else
+      nbody = bytes_written;
 
-    k->writebytecount += bytes_written;
-    Curl_pgrsSetUploadCounter(data, k->writebytecount);
+    if(nbody) {
+      /* show the data before we change the pointer upload_fromhere */
+      Curl_debug(data, CURLINFO_DATA_OUT,
+                 &k->upload_fromhere[bytes_written - nbody],
+                 (size_t)nbody);
+
+      k->writebytecount += nbody;
+      Curl_pgrsSetUploadCounter(data, k->writebytecount);
+    }
 
     if((!k->upload_chunky || k->forbidchunk) &&
        (k->writebytecount == data->state.infilesize)) {
@@ -1186,7 +1146,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
       k->upload_present = 0; /* no more bytes left */
 
       if(k->upload_done) {
-        result = Curl_done_sending(conn, k);
+        result = Curl_done_sending(data, k);
         if(result)
           return result;
       }
@@ -1233,7 +1193,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
   else
     fd_write = CURL_SOCKET_BAD;
 
-  if(conn->data->state.drain) {
+  if(data->state.drain) {
     select_res |= CURL_CSELECT_IN;
     DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n"));
   }
@@ -1247,6 +1207,10 @@ CURLcode Curl_readwrite(struct connectdata *conn,
     return CURLE_SEND_ERROR;
   }
 
+#ifdef USE_HYPER
+  if(conn->datastream)
+    return conn->datastream(data, conn, &didwhat, done, select_res);
+#endif
   /* We go ahead and do a read if we have a readable socket or if
      the stream was rewound (in which case we have data in a
      buffer) */
@@ -1266,10 +1230,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
   }
 
   k->now = Curl_now();
-  if(didwhat) {
-    ;
-  }
-  else {
+  if(!didwhat) {
     /* no read no write, this is a timeout? */
     if(k->exp100 == EXP100_AWAITING_CONTINUE) {
       /* This should allow some time for the header to arrive, but only a
@@ -1296,7 +1257,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
     }
   }
 
-  if(Curl_pgrsUpdate(conn))
+  if(Curl_pgrsUpdate(data))
     result = CURLE_ABORTED_BY_CALLBACK;
   else
     result = Curl_speedcheck(data, k->now);
@@ -1355,7 +1316,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
       failf(data, "transfer closed with outstanding read data remaining");
       return CURLE_PARTIAL_FILE;
     }
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       return CURLE_ABORTED_BY_CALLBACK;
   }
 
@@ -1373,15 +1334,15 @@ CURLcode Curl_readwrite(struct connectdata *conn,
  * keeps track of. This function will only be called for connections that are
  * in the proper state to have this information available.
  */
-int Curl_single_getsock(const struct connectdata *conn,
+int Curl_single_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
                         curl_socket_t *sock)
 {
-  const struct Curl_easy *data = conn->data;
   int bitmap = GETSOCK_BLANK;
   unsigned sockindex = 0;
 
   if(conn->handler->perform_getsock)
-    return conn->handler->perform_getsock(conn, sock);
+    return conn->handler->perform_getsock(data, conn, sock);
 
   /* don't include HOLD and PAUSE connections */
   if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) {
@@ -1529,8 +1490,23 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
     }
 #endif
     Curl_http2_init_state(&data->state);
+    Curl_hsts_loadcb(data, data->hsts);
+  }
+
+  /*
+   * Set user-agent. Used for HTTP, but since we can attempt to tunnel
+   * basically anything through a http proxy we can't limit this based on
+   * protocol.
+   */
+  if(data->set.str[STRING_USERAGENT]) {
+    Curl_safefree(data->state.aptr.uagent);
+    data->state.aptr.uagent =
+      aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
+    if(!data->state.aptr.uagent)
+      return CURLE_OUT_OF_MEMORY;
   }
 
+  data->req.headerbytecount = 0;
   return result;
 }
 
@@ -1573,6 +1549,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
   bool reachedmax = FALSE;
   CURLUcode uc;
 
+  DEBUGASSERT(type != FOLLOW_NONE);
+
   if(type == FOLLOW_REDIR) {
     if((data->set.maxredirs != -1) &&
        (data->set.followlocation >= data->set.maxredirs)) {
@@ -1604,8 +1582,11 @@ CURLcode Curl_follow(struct Curl_easy *data,
     }
   }
 
-  if(Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
-    /* This is an absolute URL, don't allow the custom port number */
+  if((type != FOLLOW_RETRY) &&
+     (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
+     Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
+    /* If this is not redirect due to a 401 or 407 response and an absolute
+       URL: don't allow a custom port number */
     disallowport = TRUE;
 
   DEBUGASSERT(data->state.uh);
@@ -1686,7 +1667,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
      * request with an error page. To be sure that libcurl gets the page that
      * most user agents would get, libcurl has to force GET.
      *
-     * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
+     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
      * can be overridden with CURLOPT_POSTREDIR.
      */
     if((data->state.httpreq == HTTPREQ_POST
@@ -1711,7 +1692,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
      * request with an error page. To be sure that libcurl gets the page that
      * most user agents would get, libcurl has to force GET.
      *
-     * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
+     * This behavior is forbidden by RFC1945 and the obsolete RFC2616, and
      * can be overridden with CURLOPT_POSTREDIR.
      */
     if((data->state.httpreq == HTTPREQ_POST
@@ -1765,10 +1746,9 @@ CURLcode Curl_follow(struct Curl_easy *data,
 /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
 
    NOTE: that the *url is malloc()ed. */
-CURLcode Curl_retry_request(struct connectdata *conn,
-                            char **url)
+CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   bool retry = FALSE;
   *url = NULL;
 
@@ -1798,7 +1778,7 @@ CURLcode Curl_retry_request(struct connectdata *conn,
        to issue again, but the nghttp2 API can deliver the message to other
        streams as well, which is why this adds the check the data counters
        too. */
-    infof(conn->data, "REFUSED_STREAM, retrying a fresh connect\n");
+    infof(data, "REFUSED_STREAM, retrying a fresh connect\n");
     data->state.refused_stream = FALSE; /* clear again */
     retry = TRUE;
   }
@@ -1810,9 +1790,9 @@ CURLcode Curl_retry_request(struct connectdata *conn,
       data->state.retrycount = 0;
       return CURLE_SEND_ERROR;
     }
-    infof(conn->data, "Connection died, retrying a fresh connect\
+    infof(data, "Connection died, retrying a fresh connect\
 (retry count: %d)\n", data->state.retrycount);
-    *url = strdup(conn->data->change.url);
+    *url = strdup(data->change.url);
     if(!*url)
       return CURLE_OUT_OF_MEMORY;
 
@@ -1826,7 +1806,7 @@ CURLcode Curl_retry_request(struct connectdata *conn,
 
     if(conn->handler->protocol&PROTO_FAMILY_HTTP) {
       if(data->req.writebytecount) {
-        CURLcode result = Curl_readrewind(conn);
+        CURLcode result = Curl_readrewind(data);
         if(result) {
           Curl_safefree(*url);
           return result;
@@ -1853,7 +1833,7 @@ Curl_setup_transfer(
 {
   struct SingleRequest *k = &data->req;
   struct connectdata *conn = data->conn;
-  struct HTTP *http = data->req.protop;
+  struct HTTP *http = data->req.p.http;
   bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
                       (http->sending == HTTPSEND_REQUEST));
   DEBUGASSERT(conn != NULL);
index 67fd91f..0fa3d55 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -23,7 +23,7 @@
  ***************************************************************************/
 
 #define Curl_headersep(x) ((((x)==':') || ((x)==';')))
-char *Curl_checkheaders(const struct connectdata *conn,
+char *Curl_checkheaders(const struct Curl_easy *data,
                         const char *thisheader);
 
 void Curl_init_CONNECT(struct Curl_easy *data);
@@ -36,9 +36,8 @@ typedef enum {
                    allow initing to this */
   FOLLOW_FAKE,  /* only records stuff, not actually following */
   FOLLOW_RETRY, /* set if this is a request retry as opposed to a real
-                          redirect following */
-  FOLLOW_REDIR, /* a full true redirect */
-  FOLLOW_LAST   /* never used */
+                   redirect following */
+  FOLLOW_REDIR /* a full true redirect */
 } followtype;
 
 CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
@@ -46,16 +45,16 @@ CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
 CURLcode Curl_readwrite(struct connectdata *conn,
                         struct Curl_easy *data, bool *done,
                         bool *comeback);
-int Curl_single_getsock(const struct connectdata *conn,
-                        curl_socket_t *socks);
-CURLcode Curl_readrewind(struct connectdata *conn);
-CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
+int Curl_single_getsock(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
+CURLcode Curl_readrewind(struct Curl_easy *data);
+CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
                              size_t *nreadp);
-CURLcode Curl_retry_request(struct connectdata *conn, char **url);
+CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
 bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
 CURLcode Curl_get_upload_buffer(struct Curl_easy *data);
 
-CURLcode Curl_done_sending(struct connectdata *conn,
+CURLcode Curl_done_sending(struct Curl_easy *data,
                            struct SingleRequest *k);
 
 /* This sets up a forthcoming transfer */
index 150667a..c02d2c2 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -96,6 +96,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
 #include "getinfo.h"
 #include "urlapi-int.h"
 #include "system_win32.h"
+#include "hsts.h"
 
 /* And now for the protocols */
 #include "ftp.h"
@@ -130,7 +131,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
 #include "memdebug.h"
 
 static void conn_free(struct connectdata *conn);
-static unsigned int get_protocol_family(unsigned int protocol);
 
 /* Some parts of the code (e.g. chunked encoding) assume this buffer has at
  * more than just a few bytes to play with. Don't let it become too small or
@@ -140,6 +140,24 @@ static unsigned int get_protocol_family(unsigned int protocol);
 # error READBUFFER_SIZE is too small
 #endif
 
+/*
+* get_protocol_family()
+*
+* This is used to return the protocol family for a given protocol.
+*
+* Parameters:
+*
+* 'h'  [in]  - struct Curl_handler pointer.
+*
+* Returns the family as a single bit protocol identifier.
+*/
+static unsigned int get_protocol_family(const struct Curl_handler *h)
+{
+  DEBUGASSERT(h);
+  DEBUGASSERT(h->family);
+  return h->family;
+}
+
 
 /*
  * Protocol table. Schemes (roughly) in 2019 popularity order:
@@ -215,9 +233,8 @@ static const struct Curl_handler * const protocols[] = {
 #endif
 #endif
 
-#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
-   (CURL_SIZEOF_CURL_OFF_T > 4) && \
-   (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO))
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
+   (CURL_SIZEOF_CURL_OFF_T > 4)
   &Curl_handler_smb,
 #ifdef USE_SSL
   &Curl_handler_smbs,
@@ -228,12 +245,15 @@ static const struct Curl_handler * const protocols[] = {
   &Curl_handler_rtsp,
 #endif
 
-#ifdef CURL_ENABLE_MQTT
+#ifndef CURL_DISABLE_MQTT
   &Curl_handler_mqtt,
 #endif
 
 #ifndef CURL_DISABLE_GOPHER
   &Curl_handler_gopher,
+#ifdef USE_SSL
+  &Curl_handler_gophers,
+#endif
 #endif
 
 #ifdef USE_LIBRTMP
@@ -274,6 +294,7 @@ static const struct Curl_handler Curl_handler_dummy = {
   ZERO_NULL,                            /* connection_check */
   0,                                    /* defport */
   0,                                    /* protocol */
+  0,                                    /* family */
   PROTOPT_NONE                          /* flags */
 };
 
@@ -343,6 +364,9 @@ CURLcode Curl_close(struct Curl_easy **datap)
 
   Curl_expire_clear(data); /* shut off timers */
 
+  /* Detach connection if any is left. This should not be normal, but can be
+     the case for example with CONNECT_ONLY + recv/send (test 556) */
+  Curl_detach_connnection(data);
   m = data->multi;
   if(m)
     /* This handle is still part of a multi handle, take care of this first
@@ -392,11 +416,10 @@ CURLcode Curl_close(struct Curl_easy **datap)
   Curl_dyn_free(&data->state.headerb);
   Curl_safefree(data->state.ulbuf);
   Curl_flush_cookies(data, TRUE);
-#ifdef USE_ALTSVC
   Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
-  Curl_altsvc_cleanup(data->asi);
-  data->asi = NULL;
-#endif
+  Curl_altsvc_cleanup(&data->asi);
+  Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
+  Curl_hsts_cleanup(&data->hsts);
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
   Curl_http_auth_cleanup_digest(data);
 #endif
@@ -404,7 +427,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
   Curl_safefree(data->info.wouldredirect);
 
   /* this destroys the channel and we cannot use it anymore after this */
-  Curl_resolver_cleanup(data->state.resolver);
+  Curl_resolver_cleanup(data->state.async.resolver);
 
   Curl_http2_cleanup_dependencies(data);
   Curl_convert_close(data);
@@ -428,9 +451,12 @@ CURLcode Curl_close(struct Curl_easy **datap)
   Curl_safefree(data->state.aptr.rtsp_transport);
 
 #ifndef CURL_DISABLE_DOH
-  Curl_dyn_free(&data->req.doh.probe[0].serverdoh);
-  Curl_dyn_free(&data->req.doh.probe[1].serverdoh);
-  curl_slist_free_all(data->req.doh.headers);
+  if(data->req.doh) {
+    Curl_dyn_free(&data->req.doh->probe[0].serverdoh);
+    Curl_dyn_free(&data->req.doh->probe[1].serverdoh);
+    curl_slist_free_all(data->req.doh->headers);
+    Curl_safefree(data->req.doh);
+  }
 #endif
 
   /* destruct wildcard structures if it is needed */
@@ -480,6 +506,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
   set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
   set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
   set->ftp_filemethod = FTPFILE_MULTICWD;
+  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
 #endif
   set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
 
@@ -616,7 +643,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
 
   data->magic = CURLEASY_MAGIC_NUMBER;
 
-  result = Curl_resolver_init(data, &data->state.resolver);
+  result = Curl_resolver_init(data, &data->state.async.resolver);
   if(result) {
     DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
     free(data);
@@ -637,7 +664,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
   }
 
   if(result) {
-    Curl_resolver_cleanup(data->state.resolver);
+    Curl_resolver_cleanup(data->state.async.resolver);
     Curl_dyn_free(&data->state.headerb);
     Curl_freeset(data);
     free(data);
@@ -688,29 +715,29 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
 #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
 
 
-static void conn_shutdown(struct connectdata *conn)
+static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn)
 {
   DEBUGASSERT(conn);
-  infof(conn->data, "Closing connection %ld\n", conn->connection_id);
-  DEBUGASSERT(conn->data);
+  DEBUGASSERT(data);
+  infof(data, "Closing connection %ld\n", conn->connection_id);
 
   /* possible left-overs from the async name resolvers */
-  Curl_resolver_cancel(conn);
+  Curl_resolver_cancel(data);
 
   /* close the SSL stuff before we close any sockets since they will/may
      write to the sockets */
-  Curl_ssl_close(conn, FIRSTSOCKET);
-  Curl_ssl_close(conn, SECONDARYSOCKET);
+  Curl_ssl_close(data, conn, FIRSTSOCKET);
+  Curl_ssl_close(data, conn, SECONDARYSOCKET);
 
   /* close possibly still open sockets */
   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
-    Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+    Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
   if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
-    Curl_closesocket(conn, conn->sock[FIRSTSOCKET]);
+    Curl_closesocket(data, conn, conn->sock[FIRSTSOCKET]);
   if(CURL_SOCKET_BAD != conn->tempsock[0])
-    Curl_closesocket(conn, conn->tempsock[0]);
+    Curl_closesocket(data, conn, conn->tempsock[0]);
   if(CURL_SOCKET_BAD != conn->tempsock[1])
-    Curl_closesocket(conn, conn->tempsock[1]);
+    Curl_closesocket(data, conn, conn->tempsock[1]);
 }
 
 static void conn_free(struct connectdata *conn)
@@ -805,19 +832,23 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
   /* Cleanup NEGOTIATE connection-related data */
   Curl_http_auth_cleanup_negotiate(conn);
 
-  /* the protocol specific disconnect handler and conn_shutdown need a transfer
-     for the connection! */
-  conn->data = data;
-
   if(conn->bits.connect_only)
     /* treat the connection as dead in CONNECT_ONLY situations */
     dead_connection = TRUE;
 
+  /* temporarily attach the connection to this transfer handle for the
+     disonnect and shutdown */
+  Curl_attach_connnection(data, conn);
+
   if(conn->handler->disconnect)
     /* This is set if protocol-specific cleanups should be made */
-    conn->handler->disconnect(conn, dead_connection);
+    conn->handler->disconnect(data, conn, dead_connection);
+
+  conn_shutdown(data, conn);
+
+  /* detach it again */
+  Curl_detach_connnection(data);
 
-  conn_shutdown(conn);
   conn_free(conn);
   return CURLE_OK;
 }
@@ -915,15 +946,13 @@ static bool conn_maxage(struct Curl_easy *data,
                         struct connectdata *conn,
                         struct curltime now)
 {
-  if(!conn->data) {
-    timediff_t idletime = Curl_timediff(now, conn->lastused);
-    idletime /= 1000; /* integer seconds is fine */
+  timediff_t idletime = Curl_timediff(now, conn->lastused);
+  idletime /= 1000; /* integer seconds is fine */
 
-    if(idletime > data->set.maxage_conn) {
-      infof(data, "Too old connection (%ld seconds), disconnect it\n",
-            idletime);
-      return TRUE;
-    }
+  if(idletime > data->set.maxage_conn) {
+    infof(data, "Too old connection (%ld seconds), disconnect it\n",
+          idletime);
+    return TRUE;
   }
   return FALSE;
 }
@@ -940,23 +969,29 @@ static bool conn_maxage(struct Curl_easy *data,
 static bool extract_if_dead(struct connectdata *conn,
                             struct Curl_easy *data)
 {
-  if(!CONN_INUSE(conn) && !conn->data) {
+  if(!CONN_INUSE(conn)) {
     /* The check for a dead socket makes sense only if the connection isn't in
        use */
     bool dead;
     struct curltime now = Curl_now();
     if(conn_maxage(data, conn, now)) {
+      /* avoid check if already too old */
       dead = TRUE;
     }
     else if(conn->handler->connection_check) {
       /* The protocol has a special method for checking the state of the
          connection. Use it to check if the connection is dead. */
       unsigned int state;
-      struct Curl_easy *olddata = conn->data;
-      conn->data = data; /* use this transfer for now */
-      state = conn->handler->connection_check(conn, CONNCHECK_ISDEAD);
-      conn->data = olddata;
+
+      /* briefly attach the connection to this transfer for the purpose of
+         checking it */
+      Curl_attach_connnection(data, conn);
+      conn->data = data; /* find the way back if necessary */
+      state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
       dead = (state & CONNRESULT_DEAD);
+      /* detach the connection again */
+      Curl_detach_connnection(data);
+      conn->data = NULL; /* clear it again */
     }
     else {
       /* Use the general method for determining the death of a connection */
@@ -981,10 +1016,11 @@ struct prunedead {
  * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
  *
  */
-static int call_extract_if_dead(struct connectdata *conn, void *param)
+static int call_extract_if_dead(struct Curl_easy *data,
+                                struct connectdata *conn, void *param)
 {
   struct prunedead *p = (struct prunedead *)param;
-  if(extract_if_dead(conn, p->data)) {
+  if(extract_if_dead(conn, data)) {
     /* stop the iteration here, pass back the connection that was extracted */
     p->extracted = conn;
     return 1;
@@ -994,14 +1030,16 @@ static int call_extract_if_dead(struct connectdata *conn, void *param)
 
 /*
  * This function scans the connection cache for half-open/dead connections,
- * closes and removes them.
- * The cleanup is done at most once per second.
+ * closes and removes them. The cleanup is done at most once per second.
+ *
+ * When called, this transfer has no connection attached.
  */
 static void prune_dead_connections(struct Curl_easy *data)
 {
   struct curltime now = Curl_now();
   timediff_t elapsed;
 
+  DEBUGASSERT(!data->conn); /* no connection */
   CONNCACHE_LOCK(data);
   elapsed =
     Curl_timediff(now, data->state.conn_cache->last_cleanup);
@@ -1019,7 +1057,7 @@ static void prune_dead_connections(struct Curl_easy *data)
       Curl_conncache_remove_conn(data, prune.extracted, TRUE);
 
       /* disconnect it */
-      (void)Curl_disconnect(data, prune.extracted, /* dead_connection */TRUE);
+      (void)Curl_disconnect(data, prune.extracted, TRUE);
     }
     CONNCACHE_LOCK(data);
     data->state.conn_cache->last_cleanup = now;
@@ -1071,11 +1109,11 @@ ConnectionExists(struct Curl_easy *data,
 
   /* Look up the bundle with all the connections to this particular host.
      Locks the connection cache, beware of early returns! */
-  bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache,
+  bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache,
                                       &hostbundle);
   if(bundle) {
     /* Max pipe length is zero (unlimited) for multiplexed connections */
-    struct curl_llist_element *curr;
+    struct Curl_llist_element *curr;
 
     infof(data, "Found bundle for host %s: %p [%s]\n",
           hostbundle, (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
@@ -1121,13 +1159,16 @@ ConnectionExists(struct Curl_easy *data,
         /* connect-only or to-be-closed connections will not be reused */
         continue;
 
+      if(extract_if_dead(check, data)) {
+        /* disconnect it */
+        (void)Curl_disconnect(data, check, TRUE);
+        continue;
+      }
+
       if(bundle->multiuse == BUNDLE_MULTIPLEX)
         multiplexed = CONN_INUSE(check);
 
-      if(canmultiplex) {
-        ;
-      }
-      else {
+      if(!canmultiplex) {
         if(multiplexed) {
           /* can only happen within multi handles, and means that another easy
              handle is using this connection */
@@ -1135,9 +1176,9 @@ ConnectionExists(struct Curl_easy *data,
         }
 
         if(Curl_resolver_asynch()) {
-          /* ip_addr_str[0] is NUL only if the resolving of the name hasn't
+          /* primary_ip[0] is NUL only if the resolving of the name hasn't
              completed yet and until then we don't re-use this connection */
-          if(!check->ip_addr_str[0]) {
+          if(!check->primary_ip[0]) {
             infof(data,
                   "Connection #%ld is still name resolving, can't reuse\n",
                   check->connection_id);
@@ -1171,7 +1212,7 @@ ConnectionExists(struct Curl_easy *data,
       if((needle->handler->flags&PROTOPT_SSL) !=
          (check->handler->flags&PROTOPT_SSL))
         /* don't do mixed SSL and non-SSL connections */
-        if(get_protocol_family(check->handler->protocol) !=
+        if(get_protocol_family(check->handler) !=
            needle->handler->protocol || !check->bits.tls_upgraded)
           /* except protocols that have been upgraded via TLS */
           continue;
@@ -1276,7 +1317,7 @@ ConnectionExists(struct Curl_easy *data,
            is allowed to be upgraded via TLS */
 
         if((strcasecompare(needle->handler->scheme, check->handler->scheme) ||
-            (get_protocol_family(check->handler->protocol) ==
+            (get_protocol_family(check->handler) ==
              needle->handler->protocol && check->bits.tls_upgraded)) &&
            (!needle->bits.conn_to_host || strcasecompare(
             needle->conn_to_host.name, check->conn_to_host.name)) &&
@@ -1439,17 +1480,18 @@ ConnectionExists(struct Curl_easy *data,
  * verboseconnect() displays verbose information after a connect
  */
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-void Curl_verboseconnect(struct connectdata *conn)
+void Curl_verboseconnect(struct Curl_easy *data,
+                         struct connectdata *conn)
 {
-  if(conn->data->set.verbose)
-    infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n",
+  if(data->set.verbose)
+    infof(data, "Connected to %s (%s) port %ld (#%ld)\n",
 #ifndef CURL_DISABLE_PROXY
           conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
           conn->bits.httpproxy ? conn->http_proxy.host.dispname :
 #endif
           conn->bits.conn_to_host ? conn->conn_to_host.dispname :
           conn->host.dispname,
-          conn->ip_addr_str, conn->port, conn->connection_id);
+          conn->primary_ip, conn->port, conn->connection_id);
 }
 #endif
 
@@ -1488,16 +1530,14 @@ static void strip_trailing_dot(struct hostname *host)
 /*
  * Perform any necessary IDN conversion of hostname
  */
-CURLcode Curl_idnconvert_hostname(struct connectdata *conn,
+CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
                                   struct hostname *host)
 {
-  struct Curl_easy *data = conn->data;
-
 #ifndef USE_LIBIDN2
   (void)data;
-  (void)conn;
+  (void)data;
 #elif defined(CURL_DISABLE_VERBOSE_STRINGS)
-  (void)conn;
+  (void)data;
 #endif
 
   /* set the name we use to display the host name */
@@ -1517,13 +1557,18 @@ CURLcode Curl_idnconvert_hostname(struct connectdata *conn,
       int flags = IDN2_NFC_INPUT;
 #endif
       int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags);
+      if(rc != IDN2_OK)
+        /* fallback to TR46 Transitional mode for better IDNA2003
+           compatibility */
+        rc = idn2_lookup_ul((const char *)host->name, &ace_hostname,
+                            IDN2_TRANSITIONAL);
       if(rc == IDN2_OK) {
         host->encalloc = (char *)ace_hostname;
         /* change the name pointer to point to the encoded hostname */
         host->name = host->encalloc;
       }
       else {
-        failf(data, "Failed to convert %s to ACE; %s\n", host->name,
+        failf(data, "Failed to convert %s to ACE; %s", host->name,
               idn2_strerror(rc));
         return CURLE_URL_MALFORMAT;
       }
@@ -1538,7 +1583,7 @@ CURLcode Curl_idnconvert_hostname(struct connectdata *conn,
     }
     else {
       char buffer[STRERROR_LEN];
-      failf(data, "Failed to convert %s to ACE; %s\n", host->name,
+      failf(data, "Failed to convert %s to ACE; %s", host->name,
             Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
       return CURLE_URL_MALFORMAT;
     }
@@ -1629,9 +1674,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
   /* Store current time to give a baseline to keepalive connection times. */
   conn->keepalive = Curl_now();
 
-  /* Store off the configured connection upkeep time. */
-  conn->upkeep_interval_ms = data->set.upkeep_interval_ms;
-
   conn->data = data; /* Setup the association between this connection
                         and the Curl_easy */
 
@@ -1787,12 +1829,14 @@ CURLcode Curl_uc_to_curlcode(CURLUcode uc)
  * the scope_id based on that!
  */
 
-static void zonefrom_url(CURLU *uh, struct connectdata *conn)
+static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
+                         struct connectdata *conn)
 {
   char *zoneid;
-  CURLUcode uc;
-
-  uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
+  CURLUcode uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
 
   if(!uc && zoneid) {
     char *endp;
@@ -1815,7 +1859,7 @@ static void zonefrom_url(CURLU *uh, struct connectdata *conn)
       scopeidx = if_nametoindex(zoneid);
 #endif
       if(!scopeidx)
-        infof(conn->data, "Invalid zoneid: %s; %s\n", zoneid,
+        infof(data, "Invalid zoneid: %s; %s\n", zoneid,
               strerror(errno));
       else
         conn->scope_id = scopeidx;
@@ -1891,6 +1935,37 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
   if(uc)
     return Curl_uc_to_curlcode(uc);
 
+  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
+  if(uc) {
+    if(!strcasecompare("file", data->state.up.scheme))
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+#ifdef USE_HSTS
+  if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
+    if(Curl_hsts(data->hsts, data->state.up.hostname, TRUE)) {
+      char *url;
+      Curl_safefree(data->state.up.scheme);
+      uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
+      if(uc)
+        return Curl_uc_to_curlcode(uc);
+      if(data->change.url_alloc)
+        Curl_safefree(data->change.url);
+      /* after update, get the updated version */
+      uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
+      if(uc)
+        return Curl_uc_to_curlcode(uc);
+      uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
+      if(uc)
+        return Curl_uc_to_curlcode(uc);
+      data->change.url = url;
+      data->change.url_alloc = TRUE;
+      infof(data, "Switched from HTTP to HTTPS due to HSTS => %s\n",
+            data->change.url);
+    }
+  }
+#endif
+
   result = findprotocol(data, conn, data->state.up.scheme);
   if(result)
     return result;
@@ -1936,12 +2011,6 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
   else if(uc != CURLUE_NO_OPTIONS)
     return Curl_uc_to_curlcode(uc);
 
-  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
-  if(uc) {
-    if(!strcasecompare("file", data->state.up.scheme))
-      return CURLE_OUT_OF_MEMORY;
-  }
-
   uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, 0);
   if(uc)
     return Curl_uc_to_curlcode(uc);
@@ -1954,7 +2023,9 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
   }
   else {
     unsigned long port = strtoul(data->state.up.port, NULL, 10);
-    conn->port = conn->remote_port = curlx_ultous(port);
+    conn->port = conn->remote_port =
+      (data->set.use_port && data->state.allow_port) ?
+      (int)data->set.use_port : curlx_ultous(port);
   }
 
   (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
@@ -1970,7 +2041,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
     hlen = strlen(hostname);
     hostname[hlen - 1] = 0;
 
-    zonefrom_url(uh, conn);
+    zonefrom_url(uh, data, conn);
   }
 
   /* make sure the connect struct gets its own copy of the host name */
@@ -2028,7 +2099,8 @@ static CURLcode setup_range(struct Curl_easy *data)
  *
  * This MUST get called after proxy magic has been figured out.
  */
-static CURLcode setup_connection_internals(struct connectdata *conn)
+static CURLcode setup_connection_internals(struct Curl_easy *data,
+                                           struct connectdata *conn)
 {
   const struct Curl_handler *p;
   CURLcode result;
@@ -2037,7 +2109,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
   p = conn->handler;
 
   if(p->setup_connection) {
-    result = (*p->setup_connection)(conn);
+    result = (*p->setup_connection)(data, conn);
 
     if(result)
       return result;
@@ -2060,12 +2132,14 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
 
 void Curl_free_request_state(struct Curl_easy *data)
 {
-  Curl_safefree(data->req.protop);
+  Curl_safefree(data->req.p.http);
   Curl_safefree(data->req.newurl);
 
 #ifndef CURL_DISABLE_DOH
-  Curl_close(&data->req.doh.probe[0].easy);
-  Curl_close(&data->req.doh.probe[1].easy);
+  if(data->req.doh) {
+    Curl_close(&data->req.doh->probe[0].easy);
+    Curl_close(&data->req.doh->probe[1].easy);
+  }
 #endif
 }
 
@@ -2122,7 +2196,7 @@ static bool check_noproxy(const char *name, const char *no_proxy)
         /* Look for the end of the token. */
         ;
 
-      /* To match previous behaviour, where it was necessary to specify
+      /* To match previous behavior, where it was necessary to specify
        * ".local.com" to prevent matching "notlocal.com", we will leave
        * the '.' off.
        */
@@ -2155,7 +2229,8 @@ static bool check_noproxy(const char *name, const char *no_proxy)
 * name and is not limited to HTTP proxies only.
 * The returned pointer must be freed by the caller (unless NULL)
 ****************************************************************/
-static char *detect_proxy(struct connectdata *conn)
+static char *detect_proxy(struct Curl_easy *data,
+                          struct connectdata *conn)
 {
   char *proxy = NULL;
 
@@ -2180,6 +2255,9 @@ static char *detect_proxy(struct connectdata *conn)
   const char *protop = conn->handler->scheme;
   char *envp = proxy_env;
   char *prox;
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
 
   /* Now, build <protocol>_proxy and check for such a one to use */
   while(*protop)
@@ -2222,7 +2300,7 @@ static char *detect_proxy(struct connectdata *conn)
     }
   }
   if(proxy)
-    infof(conn->data, "Uses proxy env variable %s == '%s'\n", envp, proxy);
+    infof(data, "Uses proxy env variable %s == '%s'\n", envp, proxy);
 
   return proxy;
 }
@@ -2238,7 +2316,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
                             curl_proxytype proxytype)
 {
   char *portptr = NULL;
-  long port = -1;
+  int port = -1;
   char *proxyuser = NULL;
   char *proxypasswd = NULL;
   char *host;
@@ -2327,14 +2405,14 @@ static CURLcode parse_proxy(struct Curl_easy *data,
   curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
 
   if(portptr) {
-    port = strtol(portptr, NULL, 10);
+    port = (int)strtol(portptr, NULL, 10);
     free(portptr);
   }
   else {
     if(data->set.proxyport)
       /* None given in the proxy string, then get the default one if it is
          given */
-      port = data->set.proxyport;
+      port = (int)data->set.proxyport;
     else {
       if(proxytype == CURLPROXY_HTTPS)
         port = CURL_DEFAULT_HTTPS_PROXY_PORT;
@@ -2361,7 +2439,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
     size_t len = strlen(host);
     host[len-1] = 0; /* clear the trailing bracket */
     host++;
-    zonefrom_url(uhp, conn);
+    zonefrom_url(uhp, data, conn);
   }
   proxyinfo->host.name = host;
 
@@ -2377,8 +2455,10 @@ static CURLcode parse_proxy(struct Curl_easy *data,
 static CURLcode parse_proxy_auth(struct Curl_easy *data,
                                  struct connectdata *conn)
 {
-  char *proxyuser = data->set.str[STRING_PROXYUSERNAME];
-  char *proxypasswd = data->set.str[STRING_PROXYPASSWORD];
+  const char *proxyuser = data->set.str[STRING_PROXYUSERNAME] ?
+    data->set.str[STRING_PROXYUSERNAME] : "";
+  const char *proxypasswd = data->set.str[STRING_PROXYPASSWORD] ?
+    data->set.str[STRING_PROXYPASSWORD] : "";
   CURLcode result = CURLE_OK;
 
   if(proxyuser)
@@ -2392,13 +2472,13 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data,
 
 /* create_conn helper to parse and init proxy values. to be called after unix
    socket init but before any proxy vars are evaluated. */
-static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
+static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+                                              struct connectdata *conn)
 {
   char *proxy = NULL;
   char *socksproxy = NULL;
   char *no_proxy = NULL;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
   /*************************************************************
    * Extract the user and password from the authentication string
@@ -2440,7 +2520,7 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
       no_proxy = curl_getenv(p);
     }
     if(no_proxy) {
-      infof(conn->data, "Uses proxy env variable %s == '%s'\n", p, no_proxy);
+      infof(data, "Uses proxy env variable %s == '%s'\n", p, no_proxy);
     }
   }
 
@@ -2452,7 +2532,7 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
 #ifndef CURL_DISABLE_HTTP
   else if(!proxy && !socksproxy)
     /* if the host is not in the noproxy list, detect proxy. */
-    proxy = detect_proxy(conn);
+    proxy = detect_proxy(data, conn);
 #endif /* CURL_DISABLE_HTTP */
 
   Curl_safefree(no_proxy);
@@ -2551,6 +2631,9 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
     conn->bits.socksproxy = FALSE;
     conn->bits.proxy_user_passwd = FALSE;
     conn->bits.tunnel_proxy = FALSE;
+    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
+       to signal that CURLPROXY_HTTPS is not used for this connection */
+    conn->http_proxy.proxytype = CURLPROXY_HTTP;
   }
 
 out:
@@ -3070,7 +3153,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
     conn_to_host = conn_to_host->next;
   }
 
-#ifdef USE_ALTSVC
+#ifndef CURL_DISABLE_ALTSVC
   if(data->asi && !host && (port == -1) &&
      ((conn->handler->protocol == CURLPROTO_HTTPS) ||
 #ifdef CURLDEBUG
@@ -3223,7 +3306,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
       conn->hostname_resolve = strdup(connhost->name);
       if(!conn->hostname_resolve)
         return CURLE_OUT_OF_MEMORY;
-      rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port,
+      rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
                                &hostaddr, timeout_ms);
       if(rc == CURLRESOLV_PENDING)
         *async = TRUE;
@@ -3248,7 +3331,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
       conn->hostname_resolve = strdup(host->name);
       if(!conn->hostname_resolve)
         return CURLE_OUT_OF_MEMORY;
-      rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port,
+      rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
                                &hostaddr, timeout_ms);
 
       if(rc == CURLRESOLV_PENDING)
@@ -3276,9 +3359,15 @@ static CURLcode resolve_server(struct Curl_easy *data,
  * previously existing one.  All relevant data is copied over and old_conn is
  * ready for freeing once this function returns.
  */
-static void reuse_conn(struct connectdata *old_conn,
+static void reuse_conn(struct Curl_easy *data,
+                       struct connectdata *old_conn,
                        struct connectdata *conn)
 {
+  /* 'local_ip' and 'local_port' get filled with local's numerical
+     ip address and port number whenever an outgoing connection is
+     **established** from the primary socket to a remote address. */
+  char local_ip[MAX_IPADR_LEN] = "";
+  long local_port = -1;
 #ifndef CURL_DISABLE_PROXY
   Curl_free_idnconverted_hostname(&old_conn->http_proxy.host);
   Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host);
@@ -3291,7 +3380,7 @@ static void reuse_conn(struct connectdata *old_conn,
      allocated in vain and is targeted for destruction */
   Curl_free_primary_ssl_config(&old_conn->ssl_config);
 
-  conn->data = old_conn->data;
+  conn->data = data;
 
   /* get the user+password information from the old_conn struct since it may
    * be new for this request even when we re-use an existing connection */
@@ -3345,7 +3434,11 @@ static void reuse_conn(struct connectdata *old_conn,
   old_conn->hostname_resolve = NULL;
 
   /* persist connection info in session handle */
-  Curl_persistconninfo(conn);
+  if(conn->transport == TRNSPRT_TCP) {
+    Curl_conninfo_local(data, conn->sock[FIRSTSOCKET],
+                        local_ip, &local_port);
+  }
+  Curl_persistconninfo(data, conn, local_ip, local_port);
 
   conn_reset_all_postponed_data(old_conn); /* free buffers */
 
@@ -3446,7 +3539,7 @@ static CURLcode create_conn(struct Curl_easy *data,
   /* After the unix socket init but before the proxy vars are used, parse and
      initialize the proxy vars */
 #ifndef CURL_DISABLE_PROXY
-  result = create_conn_helper_init_proxy(conn);
+  result = create_conn_helper_init_proxy(data, conn);
   if(result)
     goto out;
 
@@ -3487,22 +3580,22 @@ static CURLcode create_conn(struct Curl_easy *data,
   /*************************************************************
    * IDN-convert the hostnames
    *************************************************************/
-  result = Curl_idnconvert_hostname(conn, &conn->host);
+  result = Curl_idnconvert_hostname(data, &conn->host);
   if(result)
     goto out;
   if(conn->bits.conn_to_host) {
-    result = Curl_idnconvert_hostname(conn, &conn->conn_to_host);
+    result = Curl_idnconvert_hostname(data, &conn->conn_to_host);
     if(result)
       goto out;
   }
 #ifndef CURL_DISABLE_PROXY
   if(conn->bits.httpproxy) {
-    result = Curl_idnconvert_hostname(conn, &conn->http_proxy.host);
+    result = Curl_idnconvert_hostname(data, &conn->http_proxy.host);
     if(result)
       goto out;
   }
   if(conn->bits.socksproxy) {
-    result = Curl_idnconvert_hostname(conn, &conn->socks_proxy.host);
+    result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host);
     if(result)
       goto out;
   }
@@ -3539,7 +3632,7 @@ static CURLcode create_conn(struct Curl_easy *data,
    * Setup internals depending on protocol. Needs to be done after
    * we figured out what/if proxy to use.
    *************************************************************/
-  result = setup_connection_internals(conn);
+  result = setup_connection_internals(data, conn);
   if(result)
     goto out;
 
@@ -3559,15 +3652,15 @@ static CURLcode create_conn(struct Curl_easy *data,
     /* this is supposed to be the connect function so we better at least check
        that the file is present here! */
     DEBUGASSERT(conn->handler->connect_it);
-    Curl_persistconninfo(conn);
-    result = conn->handler->connect_it(conn, &done);
+    Curl_persistconninfo(data, conn, NULL, -1);
+    result = conn->handler->connect_it(data, &done);
 
     /* Setup a "faked" transfer that'll do nothing */
     if(!result) {
       conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
 
       Curl_attach_connnection(data, conn);
-      result = Curl_conncache_add_conn(data->state.conn_cache, conn);
+      result = Curl_conncache_add_conn(data);
       if(result)
         goto out;
 
@@ -3578,7 +3671,7 @@ static CURLcode create_conn(struct Curl_easy *data,
       if(result) {
         DEBUGASSERT(conn->handler->done);
         /* we ignore the return code for the protocol-specific DONE */
-        (void)conn->handler->done(conn, result, FALSE);
+        (void)conn->handler->done(data, result, FALSE);
         goto out;
       }
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
@@ -3611,6 +3704,7 @@ static CURLcode create_conn(struct Curl_easy *data,
   data->set.ssl.primary.pinned_key =
     data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
   data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
+  data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
 
 #ifndef CURL_DISABLE_PROXY
   data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
@@ -3627,18 +3721,15 @@ static CURLcode create_conn(struct Curl_easy *data,
   data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
   data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
   data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
-  data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY];
   data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
   data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
   data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
   data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
   data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
-  data->set.proxy_ssl.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
   data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
 #endif
   data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
   data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
-  data->set.ssl.cert = data->set.str[STRING_CERT_ORIG];
   data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
   data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
   data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
@@ -3653,7 +3744,6 @@ static CURLcode create_conn(struct Curl_easy *data,
 #endif
 #endif
 
-  data->set.ssl.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
   data->set.ssl.key_blob = data->set.blobs[BLOB_KEY_ORIG];
   data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG];
 
@@ -3694,12 +3784,11 @@ static CURLcode create_conn(struct Curl_easy *data,
 
   if(reuse) {
     /*
-     * We already have a connection for this, we got the former connection
-     * in the conn_temp variable and thus we need to cleanup the one we
-     * just allocated before we can move along and use the previously
-     * existing one.
+     * We already have a connection for this, we got the former connection in
+     * the conn_temp variable and thus we need to cleanup the one we just
+     * allocated before we can move along and use the previously existing one.
      */
-    reuse_conn(conn, conn_temp);
+    reuse_conn(data, conn, conn_temp);
 #ifdef USE_SSL
     free(conn->ssl_extra);
 #endif
@@ -3741,7 +3830,8 @@ static CURLcode create_conn(struct Curl_easy *data,
       /* this gets a lock on the conncache */
       const char *bundlehost;
       struct connectbundle *bundle =
-        Curl_conncache_find_bundle(conn, data->state.conn_cache, &bundlehost);
+        Curl_conncache_find_bundle(data, conn, data->state.conn_cache,
+                                   &bundlehost);
 
       if(max_host_connections > 0 && bundle &&
          (bundle->num_connections >= max_host_connections)) {
@@ -3752,8 +3842,7 @@ static CURLcode create_conn(struct Curl_easy *data,
         CONNCACHE_UNLOCK(data);
 
         if(conn_candidate)
-          (void)Curl_disconnect(data, conn_candidate,
-                                /* dead_connection */ FALSE);
+          (void)Curl_disconnect(data, conn_candidate, FALSE);
         else {
           infof(data, "No more connections allowed to host %s: %zu\n",
                 bundlehost, max_host_connections);
@@ -3773,8 +3862,7 @@ static CURLcode create_conn(struct Curl_easy *data,
       /* The cache is full. Let's see if we can kill a connection. */
       conn_candidate = Curl_conncache_extract_oldest(data);
       if(conn_candidate)
-        (void)Curl_disconnect(data, conn_candidate,
-                              /* dead_connection */ FALSE);
+        (void)Curl_disconnect(data, conn_candidate, FALSE);
       else {
         infof(data, "No connections available in cache\n");
         connections_available = FALSE;
@@ -3796,8 +3884,7 @@ static CURLcode create_conn(struct Curl_easy *data,
        * cache of ours!
        */
       Curl_attach_connnection(data, conn);
-
-      result = Curl_conncache_add_conn(data->state.conn_cache, conn);
+      result = Curl_conncache_add_conn(data);
       if(result)
         goto out;
     }
@@ -3869,11 +3956,11 @@ out:
  * conn->data MUST already have been setup fine (in create_conn)
  */
 
-CURLcode Curl_setup_conn(struct connectdata *conn,
+CURLcode Curl_setup_conn(struct Curl_easy *data,
                          bool *protocol_done)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   Curl_pgrsTime(data, TIMER_NAMELOOKUP);
 
@@ -3891,20 +3978,6 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
      lingering set from a previous invoke */
   conn->bits.proxy_connect_closed = FALSE;
 #endif
-  /*
-   * Set user-agent. Used for HTTP, but since we can attempt to tunnel
-   * basically anything through a http proxy we can't limit this based on
-   * protocol.
-   */
-  if(data->set.str[STRING_USERAGENT]) {
-    Curl_safefree(data->state.aptr.uagent);
-    data->state.aptr.uagent =
-      aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
-    if(!data->state.aptr.uagent)
-      return CURLE_OUT_OF_MEMORY;
-  }
-
-  data->req.headerbytecount = 0;
 
 #ifdef CURL_DO_LINEEND_CONV
   data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
@@ -3916,7 +3989,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
 
   if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
     conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
-    result = Curl_connecthost(conn, conn->dns_entry);
+    result = Curl_connecthost(data, conn, conn->dns_entry);
     if(result)
       return result;
   }
@@ -3927,8 +4000,8 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
       Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
     conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
     *protocol_done = TRUE;
-    Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
-    Curl_verboseconnect(conn);
+    Curl_updateconninfo(data, conn, conn->sock[FIRSTSOCKET]);
+    Curl_verboseconnect(data, conn);
   }
 
   conn->now = Curl_now(); /* time this *after* the connect is done, we set
@@ -3961,7 +4034,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
       /* DNS resolution is done: that's either because this is a reused
          connection, in which case DNS was unnecessary, or because DNS
          really did finish already (synch resolver/fast async resolve) */
-      result = Curl_setup_conn(conn, protocol_done);
+      result = Curl_setup_conn(data, protocol_done);
     }
   }
 
@@ -4026,113 +4099,3 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
 
   return CURLE_OK;
 }
-
-/*
-* get_protocol_family()
-*
-* This is used to return the protocol family for a given protocol.
-*
-* Parameters:
-*
-* protocol  [in]  - A single bit protocol identifier such as HTTP or HTTPS.
-*
-* Returns the family as a single bit protocol identifier.
-*/
-
-static unsigned int get_protocol_family(unsigned int protocol)
-{
-  unsigned int family;
-
-  switch(protocol) {
-  case CURLPROTO_HTTP:
-  case CURLPROTO_HTTPS:
-    family = CURLPROTO_HTTP;
-    break;
-
-  case CURLPROTO_FTP:
-  case CURLPROTO_FTPS:
-    family = CURLPROTO_FTP;
-    break;
-
-  case CURLPROTO_SCP:
-    family = CURLPROTO_SCP;
-    break;
-
-  case CURLPROTO_SFTP:
-    family = CURLPROTO_SFTP;
-    break;
-
-  case CURLPROTO_TELNET:
-    family = CURLPROTO_TELNET;
-    break;
-
-  case CURLPROTO_LDAP:
-  case CURLPROTO_LDAPS:
-    family = CURLPROTO_LDAP;
-    break;
-
-  case CURLPROTO_DICT:
-    family = CURLPROTO_DICT;
-    break;
-
-  case CURLPROTO_FILE:
-    family = CURLPROTO_FILE;
-    break;
-
-  case CURLPROTO_TFTP:
-    family = CURLPROTO_TFTP;
-    break;
-
-  case CURLPROTO_IMAP:
-  case CURLPROTO_IMAPS:
-    family = CURLPROTO_IMAP;
-    break;
-
-  case CURLPROTO_POP3:
-  case CURLPROTO_POP3S:
-    family = CURLPROTO_POP3;
-    break;
-
-  case CURLPROTO_SMTP:
-  case CURLPROTO_SMTPS:
-      family = CURLPROTO_SMTP;
-      break;
-
-  case CURLPROTO_RTSP:
-    family = CURLPROTO_RTSP;
-    break;
-
-  case CURLPROTO_RTMP:
-  case CURLPROTO_RTMPS:
-    family = CURLPROTO_RTMP;
-    break;
-
-  case CURLPROTO_RTMPT:
-  case CURLPROTO_RTMPTS:
-    family = CURLPROTO_RTMPT;
-    break;
-
-  case CURLPROTO_RTMPE:
-    family = CURLPROTO_RTMPE;
-    break;
-
-  case CURLPROTO_RTMPTE:
-    family = CURLPROTO_RTMPTE;
-    break;
-
-  case CURLPROTO_GOPHER:
-    family = CURLPROTO_GOPHER;
-    break;
-
-  case CURLPROTO_SMB:
-  case CURLPROTO_SMBS:
-    family = CURLPROTO_SMB;
-    break;
-
-  default:
-      family = 0;
-      break;
-  }
-
-  return family;
-}
index 1941dc6..929fc60 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
  ***************************************************************************/
 #include "curl_setup.h"
 
-#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
-#define READBUFFER_MAX  CURL_MAX_READ_SIZE
-#define READBUFFER_MIN  1024
-
-/* The default upload buffer size, should not be smaller than
-   CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in
-   a write callback.
-
-   The size was 16KB for many years but was bumped to 64KB because it makes
-   libcurl able to do significantly faster uploads in some circumstances. Even
-   larger buffers can help further, but this is deemed a fair memory/speed
-   compromise. */
-#define UPLOADBUFFER_DEFAULT 65536
-#define UPLOADBUFFER_MAX (2*1024*1024)
-#define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE
-
 /*
  * Prototypes for library-wide functions provided by url.c
  */
@@ -53,7 +37,7 @@ CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
 CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
 CURLcode Curl_disconnect(struct Curl_easy *data,
                          struct connectdata *, bool dead_connection);
-CURLcode Curl_setup_conn(struct connectdata *conn,
+CURLcode Curl_setup_conn(struct Curl_easy *data,
                          bool *protocol_done);
 void Curl_free_request_state(struct Curl_easy *data);
 CURLcode Curl_parse_login_details(const char *login, const size_t len,
@@ -63,7 +47,7 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
 const struct Curl_handler *Curl_builtin_scheme(const char *scheme);
 
 bool Curl_is_ASCII_name(const char *hostname);
-CURLcode Curl_idnconvert_hostname(struct connectdata *conn,
+CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
                                   struct hostname *host);
 void Curl_free_idnconverted_hostname(struct hostname *host);
 
@@ -72,9 +56,9 @@ void Curl_free_idnconverted_hostname(struct hostname *host);
                                              specified */
 
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
-#define Curl_verboseconnect(x)  Curl_nop_stmt
+#define Curl_verboseconnect(x,y)  Curl_nop_stmt
 #else
-void Curl_verboseconnect(struct connectdata *conn);
+void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn);
 #endif
 
 #ifdef CURL_DISABLE_PROXY
index d14d53d..4257233 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -28,7 +28,7 @@
 bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
 
 #ifdef DEBUGBUILD
-CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname);
+CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, bool);
 #endif
 
 #endif /* HEADER_CURL_URLAPI_INT_H */
index acbfb82..e3a7882 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -497,7 +497,8 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
   return result;
 }
 
-UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
+UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
+                                   bool has_scheme)
 {
   char *portptr = NULL;
   char endbracket;
@@ -542,10 +543,14 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
 
     /* Browser behavior adaptation. If there's a colon with no digits after,
        just cut off the name there which makes us ignore the colon and just
-       use the default port. Firefox, Chrome and Safari all do that. */
+       use the default port. Firefox, Chrome and Safari all do that.
+
+       Don't do it if the URL has no scheme, to make something that looks like
+       a scheme not work!
+    */
     if(!portptr[1]) {
       *portptr = '\0';
-      return CURLUE_OK;
+      return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER;
     }
 
     if(!ISDIGIT(portptr[1]))
@@ -904,7 +909,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
     if(result)
       return result;
 
-    result = Curl_parse_port(u, hostname);
+    result = Curl_parse_port(u, hostname, url_has_scheme);
     if(result)
       return result;
 
@@ -978,12 +983,14 @@ void curl_url_cleanup(CURLU *u)
   }
 }
 
-#define DUP(dest, src, name)         \
-  if(src->name) {                    \
-    dest->name = strdup(src->name);  \
-    if(!dest->name)                  \
-      goto fail;                     \
-  }
+#define DUP(dest, src, name)                    \
+  do {                                          \
+    if(src->name) {                             \
+      dest->name = strdup(src->name);           \
+      if(!dest->name)                           \
+        goto fail;                              \
+    }                                           \
+  } while(0)
 
 CURLU *curl_url_dup(CURLU *in)
 {
@@ -1255,8 +1262,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
       return CURLUE_UNKNOWN_PART;
     }
     if(storep && *storep) {
-      free(*storep);
-      *storep = NULL;
+      Curl_safefree(*storep);
     }
     return CURLUE_OK;
   }
@@ -1284,8 +1290,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
     break;
   case CURLUPART_HOST:
     storep = &u->host;
-    free(u->zoneid);
-    u->zoneid = NULL;
+    Curl_safefree(u->zoneid);
     break;
   case CURLUPART_ZONEID:
     storep = &u->zoneid;
@@ -1389,28 +1394,17 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
     if(urlencode) {
       const unsigned char *i;
       char *o;
-      bool free_part = FALSE;
       char *enc = malloc(nalloc * 3 + 1); /* for worst case! */
       if(!enc)
         return CURLUE_OUT_OF_MEMORY;
-      if(plusencode) {
-        /* space to plus */
-        i = (const unsigned char *)part;
-        for(o = enc; *i; ++o, ++i)
-          *o = (*i == ' ') ? '+' : *i;
-        *o = 0; /* null-terminate */
-        part = strdup(enc);
-        if(!part) {
-          free(enc);
-          return CURLUE_OUT_OF_MEMORY;
-        }
-        free_part = TRUE;
-      }
       for(i = (const unsigned char *)part, o = enc; *i; i++) {
-        if(Curl_isunreserved(*i) ||
-           ((*i == '/') && urlskipslash) ||
-           ((*i == '=') && equalsencode) ||
-           ((*i == '+') && plusencode)) {
+        if((*i == ' ') && plusencode) {
+          *o = '+';
+          o++;
+        }
+        else if(Curl_isunreserved(*i) ||
+                ((*i == '/') && urlskipslash) ||
+                ((*i == '=') && equalsencode)) {
           if((*i == '=') && equalsencode)
             /* only skip the first equals sign */
             equalsencode = FALSE;
@@ -1424,8 +1418,6 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
       }
       *o = 0; /* null-terminate */
       newp = enc;
-      if(free_part)
-        free((char *)part);
     }
     else {
       char *p;
index 0ae9269..f7d60b2 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -76,9 +76,7 @@
 /* length of longest IPv6 address string including the trailing null */
 #define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
 
-/* Default FTP/IMAP etc response timeout in milliseconds.
-   Symbian OS panics when given a timeout much greater than 1/2 hour.
-*/
+/* Default FTP/IMAP etc response timeout in milliseconds */
 #define RESP_TIMEOUT (120*1000)
 
 /* Max string input length is a precaution against abuse and to detect junk
 #include "dynbuf.h"
 
 /* return the count of bytes sent, or -1 on error */
-typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */
+typedef ssize_t (Curl_send)(struct Curl_easy *data,   /* transfer */
                             int sockindex,            /* socketindex */
                             const void *buf,          /* data to write */
                             size_t len,               /* max amount to write */
                             CURLcode *err);           /* error to return */
 
 /* return the count of bytes read, or -1 on error */
-typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
+typedef ssize_t (Curl_recv)(struct Curl_easy *data,   /* transfer */
                             int sockindex,            /* socketindex */
                             char *buf,                /* store data here */
                             size_t len,               /* max amount to read */
                             CURLcode *err);           /* error to return */
 
+#ifdef USE_HYPER
+typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    int *didwhat,
+                                    bool *done,
+                                    int select_res);
+#endif
+
 #include "mime.h"
 #include "imap.h"
 #include "pop3.h"
@@ -134,6 +140,7 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
 #include "wildcard.h"
 #include "multihandle.h"
 #include "quic.h"
+#include "c-hyper.h"
 
 #ifdef HAVE_GSSAPI
 # ifdef HAVE_GSSGNU
@@ -153,6 +160,22 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
 #include <libssh2_sftp.h>
 #endif /* HAVE_LIBSSH2_H */
 
+#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
+#define READBUFFER_MAX  CURL_MAX_READ_SIZE
+#define READBUFFER_MIN  1024
+
+/* The default upload buffer size, should not be smaller than
+   CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in
+   a write callback.
+
+   The size was 16KB for many years but was bumped to 64KB because it makes
+   libcurl able to do significantly faster uploads in some circumstances. Even
+   larger buffers can help further, but this is deemed a fair memory/speed
+   compromise. */
+#define UPLOADBUFFER_DEFAULT 65536
+#define UPLOADBUFFER_MAX (2*1024*1024)
+#define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE
+
 #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
 #define GOOD_EASY_HANDLE(x) \
   ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
@@ -207,14 +230,14 @@ struct ssl_backend_data;
 
 /* struct for data related to each SSL connection */
 struct ssl_connect_data {
-  /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm
-     but at least asked to or meaning to use it. See 'state' for the exact
-     current state of the connection. */
   ssl_connection_state state;
   ssl_connect_state connecting_state;
 #if defined(USE_SSL)
   struct ssl_backend_data *backend;
 #endif
+  /* Use ssl encrypted communications TRUE/FALSE. The library is not
+     necessarily using ssl at the moment but at least asked to or means to use
+     it. See 'state' for the exact current state of the connection. */
   BIT(use);
 };
 
@@ -230,6 +253,7 @@ struct ssl_primary_config {
   char *cipher_list13;   /* list of TLS 1.3 cipher suites to use */
   char *pinned_key;
   struct curl_blob *cert_blob;
+  char *curves;          /* list of curves to use */
   BIT(verifypeer);       /* set TRUE if this is desired */
   BIT(verifyhost);       /* set TRUE if CN/SAN must match hostname */
   BIT(verifystatus);     /* set TRUE if certificate status must be checked */
@@ -244,8 +268,6 @@ struct ssl_config_data {
   struct curl_blob *issuercert_blob;
   curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
   void *fsslctxp;        /* parameter for call back */
-  char *cert; /* client certificate file name */
-  struct curl_blob *cert_blob;
   char *cert_type; /* format for certificate (default: PEM)*/
   char *key; /* private key file name */
   struct curl_blob *key_blob;
@@ -271,7 +293,7 @@ struct ssl_general_config {
 };
 
 /* information stored about one single SSL session */
-struct curl_ssl_session {
+struct Curl_ssl_session {
   char *name;       /* host name for which this ID was used */
   char *conn_to_host; /* host name for the connection (may be NULL) */
   const char *scheme; /* protocol scheme used */
@@ -371,8 +393,8 @@ struct ntlmdata {
 #else
   unsigned int flags;
   unsigned char nonce[8];
-  void *target_info; /* TargetInfo received in the ntlm type-2 message */
   unsigned int target_info_len;
+  void *target_info; /* TargetInfo received in the ntlm type-2 message */
 
 #if defined(NTLM_WB_ENABLED)
   /* used for communication with Samba's winbind daemon helper ntlm_auth */
@@ -472,6 +494,7 @@ struct ConnectBits {
                          EPRT doesn't work we disable it for the forthcoming
                          requests */
   BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
+  BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */
 #endif
   BIT(netrc);         /* name+password provided by netrc */
   BIT(bound); /* set true if bind() has already been done on this socket/
@@ -516,24 +539,24 @@ struct hostname {
 #define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
 #define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
 
+#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
+#define USE_CURL_ASYNC
 struct Curl_async {
   char *hostname;
-  int port;
   struct Curl_dns_entry *dns;
+  struct thread_data *tdata;
+  void *resolver; /* resolver state, if it is used in the URL state -
+                     ares_channel f.e. */
+  int port;
   int status; /* if done is TRUE, this is the status from the callback */
-  void *os_specific;  /* 'struct thread_data' for Windows */
   BIT(done);  /* set TRUE when the lookup is complete */
 };
 
+#endif
+
 #define FIRSTSOCKET     0
 #define SECONDARYSOCKET 1
 
-/* These function pointer types are here only to allow easier typecasting
-   within the source when we need to cast between data pointers (such as NULL)
-   and function pointers. */
-typedef CURLcode (*Curl_do_more_func)(struct connectdata *, int *);
-typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool);
-
 enum expect100 {
   EXP100_SEND_DATA,           /* enough waiting, just send the body now */
   EXP100_AWAITING_CONTINUE,   /* waiting for the 100 Continue header */
@@ -580,8 +603,8 @@ struct dohdata {
   struct curl_slist *headers;
   struct dnsprobe probe[DOH_PROBE_SLOTS];
   unsigned int pending; /* still outstanding requests */
-  const char *host;
   int port;
+  const char *host;
 };
 
 /*
@@ -606,6 +629,8 @@ struct SingleRequest {
                                    following second response code) result in a
                                    CURLE_GOT_NOTHING error code */
 
+  curl_off_t pendingheader;      /* this many bytes left to send is actually
+                                    header and not body */
   struct curltime start;         /* transfer started at this time */
   struct curltime now;           /* current time */
   enum {
@@ -622,6 +647,7 @@ struct SingleRequest {
                                    Content-Range: header */
   int httpcode;                 /* error code from the 'HTTP/1.? XXX' or
                                    'RTSP/1.? XXX' line */
+  int keepon;
   struct curltime start100;      /* time stamp to wait for the 100 code from */
   enum expect100 exp100;        /* expect 100 continue state */
   enum upgrade101 upgr101;      /* 101 upgrade state */
@@ -630,7 +656,6 @@ struct SingleRequest {
   struct contenc_writer *writer_stack;
   time_t timeofdoc;
   long bodywrites;
-  int keepon;
   char *location;   /* This points to an allocated version of the Location:
                        header data */
   char *newurl;     /* Set to the new URL to use when a redirect or a retry is
@@ -645,10 +670,25 @@ struct SingleRequest {
      and the 'upload_present' contains the number of bytes available at this
      position */
   char *upload_fromhere;
-  void *protop;       /* Allocated protocol-specific data. Each protocol
-                         handler makes sure this points to data it needs. */
+
+  /* Allocated protocol-specific data. Each protocol handler makes sure this
+     points to data it needs. */
+  union {
+    struct FILEPROTO *file;
+    struct FTP *ftp;
+    struct HTTP *http;
+    struct IMAP *imap;
+    struct ldapreqinfo *ldap;
+    struct MQTT *mqtt;
+    struct POP3 *pop3;
+    struct RTSP *rtsp;
+    struct smb_request *smb;
+    struct SMTP *smtp;
+    struct SSHPROTO *ssh;
+    struct TELNET *telnet;
+  } p;
 #ifndef CURL_DISABLE_DOH
-  struct dohdata doh; /* DoH specific data for this request */
+  struct dohdata *doh; /* DoH specific data for this request */
 #endif
   BIT(header);       /* incoming data has HTTP header */
   BIT(content_range); /* set TRUE if Content-Range: was found */
@@ -673,18 +713,20 @@ struct SingleRequest {
 struct Curl_handler {
   const char *scheme;        /* URL scheme name. */
 
-  /* Complement to setup_connection_internals(). */
-  CURLcode (*setup_connection)(struct connectdata *);
+  /* Complement to setup_connection_internals(). This is done before the
+     transfer "owns" the connection. */
+  CURLcode (*setup_connection)(struct Curl_easy *data,
+                               struct connectdata *conn);
 
   /* These two functions MUST be set to be protocol dependent */
-  CURLcode (*do_it)(struct connectdata *, bool *done);
-  Curl_done_func done;
+  CURLcode (*do_it)(struct Curl_easy *data, bool *done);
+  CURLcode (*done)(struct Curl_easy *, CURLcode, bool);
 
   /* If the curl_do() function is better made in two halves, this
    * curl_do_more() function will be called afterwards, if set. For example
    * for doing the FTP stuff after the PASV/PORT command.
    */
-  Curl_do_more_func do_more;
+  CURLcode (*do_more)(struct Curl_easy *, int *);
 
   /* This function *MAY* be set to a protocol-dependent function that is run
    * after the connect() and everything is done, as a step in the connection.
@@ -692,39 +734,41 @@ struct Curl_handler {
    * function completes before return. If it doesn't complete, the caller
    * should call the curl_connecting() function until it is.
    */
-  CURLcode (*connect_it)(struct connectdata *, bool *done);
+  CURLcode (*connect_it)(struct Curl_easy *data, bool *done);
 
   /* See above. */
-  CURLcode (*connecting)(struct connectdata *, bool *done);
-  CURLcode (*doing)(struct connectdata *, bool *done);
+  CURLcode (*connecting)(struct Curl_easy *data, bool *done);
+  CURLcode (*doing)(struct Curl_easy *data, bool *done);
 
   /* Called from the multi interface during the PROTOCONNECT phase, and it
      should then return a proper fd set */
-  int (*proto_getsock)(struct connectdata *conn,
-                       curl_socket_t *socks);
+  int (*proto_getsock)(struct Curl_easy *data,
+                       struct connectdata *conn, curl_socket_t *socks);
 
   /* Called from the multi interface during the DOING phase, and it should
      then return a proper fd set */
-  int (*doing_getsock)(struct connectdata *conn,
-                       curl_socket_t *socks);
+  int (*doing_getsock)(struct Curl_easy *data,
+                       struct connectdata *conn, curl_socket_t *socks);
 
   /* Called from the multi interface during the DO_MORE phase, and it should
      then return a proper fd set */
-  int (*domore_getsock)(struct connectdata *conn,
-                        curl_socket_t *socks);
+  int (*domore_getsock)(struct Curl_easy *data,
+                        struct connectdata *conn, curl_socket_t *socks);
 
   /* Called from the multi interface during the DO_DONE, PERFORM and
      WAITPERFORM phases, and it should then return a proper fd set. Not setting
      this will make libcurl use the generic default one. */
-  int (*perform_getsock)(const struct connectdata *conn,
-                         curl_socket_t *socks);
+  int (*perform_getsock)(struct Curl_easy *data,
+                         struct connectdata *conn, curl_socket_t *socks);
 
   /* This function *MAY* be set to a protocol-dependent function that is run
    * by the curl_disconnect(), as a step in the disconnection.  If the handler
-   * is called because the connection has been considered dead, dead_connection
-   * is set to TRUE.
+   * is called because the connection has been considered dead,
+   * dead_connection is set to TRUE. The connection is already disassociated
+   * from the transfer here.
    */
-  CURLcode (*disconnect)(struct connectdata *, bool dead_connection);
+  CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *,
+                         bool dead_connection);
 
   /* If used, this function gets called from transfer.c:readwrite_data() to
      allow the protocol to do extra reads/writes */
@@ -734,12 +778,15 @@ struct Curl_handler {
   /* This function can perform various checks on the connection. See
      CONNCHECK_* for more information about the checks that can be performed,
      and CONNRESULT_* for the results that can be returned. */
-  unsigned int (*connection_check)(struct connectdata *conn,
+  unsigned int (*connection_check)(struct Curl_easy *data,
+                                   struct connectdata *conn,
                                    unsigned int checks_to_perform);
 
-  long defport;           /* Default port. */
+  int defport;            /* Default port. */
   unsigned int protocol;  /* See CURLPROTO_* - this needs to be the single
                              specific protocol bit */
+  unsigned int family;    /* single bit for protocol family; basically the
+                             non-TLS name of the protocol this is */
   unsigned int flags;     /* Extra particular characteristics, see PROTOPT_* */
 };
 
@@ -802,7 +849,11 @@ struct proxy_info {
 /* struct for HTTP CONNECT state data */
 struct http_connect_state {
   struct dynbuf rcvbuf;
-  int keepon;
+  enum keeponval {
+    KEEPON_DONE,
+    KEEPON_CONNECT,
+    KEEPON_IGNORE
+  } keepon;
   curl_off_t cl; /* size of content to read and ignore */
   enum {
     TUNNEL_INIT,    /* init/default/no tunnel state */
@@ -839,13 +890,9 @@ enum connect_t {
 
 #define SOCKS_STATE(x) (((x) >= CONNECT_SOCKS_INIT) &&  \
                         ((x) < CONNECT_DONE))
-#define SOCKS_REQUEST_BUFSIZE 600  /* room for large user/pw (255 max each) */
 
 struct connstate {
   enum connect_t state;
-  unsigned char socksreq[SOCKS_REQUEST_BUFSIZE];
-
-  /* CONNECT_SOCKS_SEND */
   ssize_t outstanding;  /* send this many bytes more */
   unsigned char *outp; /* send from this pointer */
 };
@@ -860,7 +907,7 @@ struct connectdata {
      connection is used! */
   struct Curl_easy *data;
   struct connstate cnnct;
-  struct curl_llist_element bundle_node; /* conncache */
+  struct Curl_llist_element bundle_node; /* conncache */
 
   /* chunk is for HTTP chunked encoding, but is in the general connectdata
      struct only because we can do just about any protocol through a HTTP proxy
@@ -892,11 +939,6 @@ struct connectdata {
   struct Curl_addrinfo *ip_addr;
   struct Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */
 
-  /* 'ip_addr_str' is the ip_addr data as a human readable string.
-     It remains available as long as the connection does, which is longer than
-     the ip_addr itself. */
-  char ip_addr_str[MAX_IPADR_LEN];
-
   unsigned int scope_id;  /* Scope id for IPv6 */
 
   enum {
@@ -919,7 +961,7 @@ struct connectdata {
   struct proxy_info socks_proxy;
   struct proxy_info http_proxy;
 #endif
-  long port;       /* which port to use locally */
+  int port;        /* which port to use locally - to connect to */
   int remote_port; /* the remote port, not the proxy port! */
   int conn_to_port; /* the remote port to connect to. valid only if
                        bits.conn_to_port is set */
@@ -934,14 +976,7 @@ struct connectdata {
      these are updated with data which comes directly from the socket. */
 
   char primary_ip[MAX_IPADR_LEN];
-  long primary_port;
-
-  /* 'local_ip' and 'local_port' get filled with local's numerical
-     ip address and port number whenever an outgoing connection is
-     **established** from the primary socket to a remote address. */
-
-  char local_ip[MAX_IPADR_LEN];
-  long local_port;
+  unsigned char ip_version; /* copied from the Curl_easy at creation time */
 
   char *user;    /* user name string, allocated */
   char *passwd;  /* password string, allocated */
@@ -978,13 +1013,14 @@ struct connectdata {
 #endif
   struct ConnectBits bits;    /* various state-flags for this connection */
 
+  /* The field below gets set in Curl_connecthost */
+  int num_addr; /* number of addresses to try to connect to */
  /* connecttime: when connect() is called on the current IP address. Used to
     be able to track when to move on to try next IP - but only when the multi
     interface is used. */
   struct curltime connecttime;
-  /* The two fields below get set in Curl_connecthost */
-  int num_addr; /* number of addresses to try to connect to */
 
+  /* The field below gets set in Curl_connecthost */
   /* how long time in milliseconds to spend on trying to connect to each IP
      address, per family */
   timediff_t timeoutms_per_addr[2];
@@ -992,15 +1028,11 @@ struct connectdata {
   const struct Curl_handler *handler; /* Connection's protocol handler */
   const struct Curl_handler *given;   /* The protocol first given */
 
-  long ip_version; /* copied from the Curl_easy at creation time */
-
   /* Protocols can use a custom keepalive mechanism to keep connections alive.
      This allows those protocols to track the last time the keepalive mechanism
      was used on this connection. */
   struct curltime keepalive;
 
-  long upkeep_interval_ms;      /* Time between calls for connection upkeep. */
-
   /**** curl_get() phase fields */
 
   curl_socket_t sockfd;   /* socket to read from or CURL_SOCKET_BAD */
@@ -1024,7 +1056,7 @@ struct connectdata {
   struct kerberos5data krb5;  /* variables into the structure definition, */
 #endif                        /* however, some of them are ftp specific. */
 
-  struct curl_llist easyq;    /* List of easy handles using this connection */
+  struct Curl_llist easyq;    /* List of easy handles using this connection */
   curl_seek_callback seek_func; /* function that seeks the input */
   void *seek_client;            /* pointer to pass to the seek() above */
 
@@ -1051,9 +1083,6 @@ struct connectdata {
   struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
 #endif
 
-  /* data used for the asynch name resolve callback */
-  struct Curl_async async;
-
   /* for chunked-encoded trailer */
   struct dynbuf trailer;
 
@@ -1072,27 +1101,30 @@ struct connectdata {
     struct mqtt_conn mqtt;
   } proto;
 
-  int cselect_bits; /* bitmask of socket events */
-  int waitfor;      /* current READ/WRITE bits to wait for */
-
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
-  int socks5_gssapi_enctype;
+  struct http_connect_state *connect_state; /* for HTTP CONNECT */
+  struct connectbundle *bundle; /* The bundle we are member of */
+#ifdef USE_UNIX_SOCKETS
+  char *unix_domain_socket;
+#endif
+#ifdef USE_HYPER
+  /* if set, an alternative data transfer function */
+  Curl_datastream datastream;
 #endif
-
   /* When this connection is created, store the conditions for the local end
      bind. This is stored before the actual bind and before any connection is
      made and will serve the purpose of being used for comparison reasons so
      that subsequent bound-requested connections aren't accidentally re-using
      wrong connections. */
   char *localdev;
-  unsigned short localport;
   int localportrange;
-  struct http_connect_state *connect_state; /* for HTTP CONNECT */
-  struct connectbundle *bundle; /* The bundle we are member of */
+  int cselect_bits; /* bitmask of socket events */
+  int waitfor;      /* current READ/WRITE bits to wait for */
   int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */
-#ifdef USE_UNIX_SOCKETS
-  char *unix_domain_socket;
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  int socks5_gssapi_enctype;
 #endif
+  unsigned short localport;
 };
 
 /* The end of connectdata. */
@@ -1134,6 +1166,7 @@ struct PureInfo {
                                  OpenSSL, GnuTLS, Schannel, NSS and GSKit
                                  builds. Asked for with CURLOPT_CERTINFO
                                  / CURLINFO_CERTINFO */
+  CURLproxycode pxcode;
   BIT(timecond);  /* set to TRUE if the time condition didn't match, which
                      thus made the document NOT get fetched */
 };
@@ -1187,17 +1220,6 @@ struct Progress {
 };
 
 typedef enum {
-  HTTPREQ_NONE, /* first in list */
-  HTTPREQ_GET,
-  HTTPREQ_POST,
-  HTTPREQ_POST_FORM, /* we make a difference internally */
-  HTTPREQ_POST_MIME, /* we make a difference internally */
-  HTTPREQ_PUT,
-  HTTPREQ_HEAD,
-  HTTPREQ_LAST /* last in list */
-} Curl_HttpReq;
-
-typedef enum {
     RTSPREQ_NONE, /* first in list */
     RTSPREQ_OPTIONS,
     RTSPREQ_DESCRIBE,
@@ -1274,7 +1296,7 @@ typedef enum {
  * One instance for each timeout an easy handle can set.
  */
 struct time_node {
-  struct curl_llist_element list;
+  struct Curl_llist_element list;
   struct curltime time;
   expire_id eid;
 };
@@ -1294,7 +1316,6 @@ struct urlpieces {
 struct UrlState {
   /* Points to the connection cache */
   struct conncache *conn_cache;
-
   int retrycount; /* number of retries on a new connection */
 
   /* buffers to store authentication data in, as parsed from input options */
@@ -1314,12 +1335,12 @@ struct UrlState {
                        strdup() data.
                     */
   int first_remote_port; /* remote port of the first (not followed) request */
-  struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
+  struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
   long sessionage;                  /* number of the most recent session */
-  unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */
   struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */
-  char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */
+  unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */
   int os_errno;  /* filled in with errno whenever an error occurs */
+  char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */
 #ifdef HAVE_SIGNAL
   /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
   void (*prev_signal)(int sig);
@@ -1329,8 +1350,9 @@ struct UrlState {
 
   struct auth authhost;  /* auth details for host */
   struct auth authproxy; /* auth details for proxy */
-  void *resolver; /* resolver state, if it is used in the URL state -
-                     ares_channel f.e. */
+#ifdef USE_CURL_ASYNC
+  struct Curl_async async;  /* asynchronous name resolver data */
+#endif
 
 #if defined(USE_OPENSSL)
   /* void instead of ENGINE to avoid bleeding OpenSSL into this header */
@@ -1338,7 +1360,7 @@ struct UrlState {
 #endif /* USE_OPENSSL */
   struct curltime expiretime; /* set this with Curl_expire() only */
   struct Curl_tree timenode; /* for the splay stuff */
-  struct curl_llist timeoutlist; /* list of pending timeouts */
+  struct Curl_llist timeoutlist; /* list of pending timeouts */
   struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */
 
   /* a place to store the most recently set FTP entrypath */
@@ -1347,8 +1369,7 @@ struct UrlState {
   int httpversion;       /* the lowest HTTP version*10 reported by any server
                             involved in this request */
 
-#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__) && \
-    !defined(__SYMBIAN32__)
+#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__)
 /* do FTP line-end conversions on most platforms */
 #define CURL_DO_LINEEND_CONV
   /* for FTP downloads: track CRLF sequences that span blocks */
@@ -1379,7 +1400,9 @@ struct UrlState {
   int stream_weight;
   CURLU *uh; /* URL handle for the current parsed URL */
   struct urlpieces up;
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
   Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
+#endif
 #ifndef CURL_DISABLE_HTTP
   size_t trailers_bytes_sent;
   struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
@@ -1387,6 +1410,9 @@ struct UrlState {
 #endif
   trailers_state trailers_state; /* whether we are sending trailers
                                        and what stage are we at */
+#ifdef USE_HYPER
+  CURLcode hresult; /* used to pass return codes back from hyper callbacks */
+#endif
 
   /* Dynamically allocated strings, MUST be freed before this struct is
      killed. */
@@ -1531,39 +1557,30 @@ enum dupstring {
   STRING_RTSP_SESSION_ID, /* Session ID to use */
   STRING_RTSP_STREAM_URI, /* Stream URI for this request */
   STRING_RTSP_TRANSPORT,  /* Transport for this session */
-
   STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
   STRING_SSH_PUBLIC_KEY,  /* path to the public key file for auth */
   STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
   STRING_SSH_KNOWNHOSTS,  /* file name of knownhosts file */
-
   STRING_PROXY_SERVICE_NAME, /* Proxy service name */
   STRING_SERVICE_NAME,    /* Service name */
   STRING_MAIL_FROM,
   STRING_MAIL_AUTH,
-
   STRING_TLSAUTH_USERNAME_ORIG,  /* TLS auth <username> */
   STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth <username> */
   STRING_TLSAUTH_PASSWORD_ORIG,  /* TLS auth <password> */
   STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth <password> */
-
   STRING_BEARER,                /* <bearer>, if used */
-
   STRING_UNIX_SOCKET_PATH,      /* path to Unix socket, if used */
-
   STRING_TARGET,                /* CURLOPT_REQUEST_TARGET */
   STRING_DOH,                   /* CURLOPT_DOH_URL */
-
   STRING_ALTSVC,                /* CURLOPT_ALTSVC */
-
+  STRING_HSTS,                  /* CURLOPT_HSTS */
   STRING_SASL_AUTHZID,          /* CURLOPT_SASL_AUTHZID */
-
-  STRING_TEMP_URL,              /* temp URL storage for proxy use */
-
   STRING_DNS_SERVERS,
   STRING_DNS_INTERFACE,
   STRING_DNS_LOCAL_IP4,
   STRING_DNS_LOCAL_IP6,
+  STRING_SSL_EC_CURVES,
 
   /* -- end of null-terminated strings -- */
 
@@ -1573,6 +1590,7 @@ enum dupstring {
 
   STRING_COPYPOSTFIELDS,  /* if POST, set the fields' values here */
 
+  STRING_AWS_SIGV4, /* Parameters for V4 signature */
 
   STRING_LAST /* not used, just an end-of-list marker */
 };
@@ -1647,7 +1665,12 @@ struct UserDefined {
   curl_conv_callback convtonetwork;
   /* function to convert from UTF-8 encoding: */
   curl_conv_callback convfromutf8;
-
+#ifdef USE_HSTS
+  curl_hstsread_callback hsts_read;
+  void *hsts_read_userp;
+  curl_hstswrite_callback hsts_write;
+  void *hsts_write_userp;
+#endif
   void *progress_client; /* pointer to pass to the progress callback */
   void *ioctl_client;   /* pointer to pass to the ioctl callback */
   long timeout;         /* in milliseconds, 0 means no timeout */
@@ -1683,8 +1706,11 @@ struct UserDefined {
   struct curl_slist *connect_to; /* list of host:port mappings to override
                                     the hostname and port to connect to */
   curl_TimeCond timecondition; /* kind of time/date comparison */
+  curl_proxytype proxytype; /* what kind of proxy that is in use */
   time_t timevalue;       /* what time to compare with */
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
   Curl_HttpReq method;   /* what kind of HTTP request (if any) is this */
+#endif
   long httpversion; /* when non-zero, a specific HTTP version requested to
                        be used in the library's request(s) */
   struct ssl_config_data ssl;  /* user defined SSL stuff */
@@ -1692,15 +1718,14 @@ struct UserDefined {
   struct ssl_config_data proxy_ssl;  /* user defined SSL stuff for proxy */
 #endif
   struct ssl_general_config general_ssl; /* general user defined SSL stuff */
-  curl_proxytype proxytype; /* what kind of proxy that is in use */
   long dns_cache_timeout; /* DNS cache timeout */
   long buffer_size;      /* size of receive buffer to use */
   size_t upload_buffer_size; /* size of upload buffer to use,
                                 keep it >= CURL_MAX_WRITE_SIZE */
   void *private_data; /* application-private data */
   struct curl_slist *http200aliases; /* linked list of aliases for http200 */
-  long ipver; /* the CURL_IPRESOLVE_* defines in the public header file
-                 0 - whatever, 1 - v2, 2 - v6 */
+  unsigned char ipver; /* the CURL_IPRESOLVE_* defines in the public header
+                          file 0 - whatever, 1 - v2, 2 - v6 */
   curl_off_t max_filesize; /* Maximum file size to download */
 #ifndef CURL_DISABLE_FTP
   curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used  */
@@ -1839,7 +1864,7 @@ struct UserDefined {
 };
 
 struct Names {
-  struct curl_hash *hostcache;
+  struct Curl_hash *hostcache;
   enum {
     HCACHE_NONE,    /* not pointing to anything */
     HCACHE_MULTI,   /* points to a shared one in the multi handle */
@@ -1858,13 +1883,17 @@ struct Names {
  */
 
 struct Curl_easy {
+  /* First a simple identifier to easier detect if a user mix up this easy
+     handle with a multi handle. Set this to CURLEASY_MAGIC_NUMBER */
+  unsigned int magic;
+
   /* first, two fields for the linked list of these */
   struct Curl_easy *next;
   struct Curl_easy *prev;
 
   struct connectdata *conn;
-  struct curl_llist_element connect_queue;
-  struct curl_llist_element conn_queue; /* list per connectdata */
+  struct Curl_llist_element connect_queue;
+  struct Curl_llist_element conn_queue; /* list per connectdata */
 
   CURLMstate mstate;  /* the handle's state */
   CURLcode result;   /* previous result */
@@ -1898,7 +1927,10 @@ struct Curl_easy {
                                   NOTE that the 'cookie' field in the
                                   UserDefined struct defines if the "engine"
                                   is to be used or not. */
-#ifdef USE_ALTSVC
+#ifdef USE_HSTS
+  struct hsts *hsts;
+#endif
+#ifndef CURL_DISABLE_ALTSVC
   struct altsvcinfo *asi;      /* the alt-svc cache */
 #endif
   struct Progress progress;    /* for all the progress meter data */
@@ -1915,7 +1947,9 @@ struct Curl_easy {
   iconv_t inbound_cd;          /* for translating from the network encoding */
   iconv_t utf8_cd;             /* for translating to UTF8 */
 #endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
-  unsigned int magic;          /* set to a CURLEASY_MAGIC_NUMBER */
+#ifdef USE_HYPER
+  struct hyptransfer hyp;
+#endif
 };
 
 #define LIBCURL_NAME "libcurl"
index 3a5c943..620dba0 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 717d7f0..1a37625 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index b9210a8..559852f 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
    It converts digest text to ASCII so the MD5 will be correct for
    what ultimately goes over the network.
 */
-#define CURL_OUTPUT_DIGEST_CONV(a, b) \
-  result = Curl_convert_to_network(a, b, strlen(b)); \
-  if(result) { \
-    free(b); \
-    return result; \
-  }
+#define CURL_OUTPUT_DIGEST_CONV(a, b)                  \
+  do {                                                 \
+    result = Curl_convert_to_network(a, b, strlen(b)); \
+    if(result) {                                       \
+      free(b);                                         \
+      return result;                                   \
+    }                                                  \
+  } while(0)
 #endif /* !USE_WINDOWS_SSPI */
 
 bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
index cc05fdb..ee373cd 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 4998306..dad947a 100644 (file)
@@ -10,7 +10,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -38,6 +38,7 @@
 #include "sendf.h"
 #include "strdup.h"
 #include "strcase.h"
+#include "strerror.h"
 
 /* The last #include files should be: */
 #include "curl_memory.h"
@@ -134,7 +135,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
   if(status != SEC_E_OK) {
     free(input_token);
 
-    failf(data, "SSPI: couldn't get auth info\n");
+    failf(data, "SSPI: couldn't get auth info");
     return CURLE_AUTH_ERROR;
   }
 
@@ -220,6 +221,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
      status == SEC_I_COMPLETE_AND_CONTINUE)
     s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
   else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+    char buffer[STRERROR_LEN];
+
     s_pSecFn->FreeCredentialsHandle(&credentials);
     Curl_sspi_free_identity(p_identity);
     free(spn);
@@ -229,6 +232,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
     if(status == SEC_E_INSUFFICIENT_MEMORY)
       return CURLE_OUT_OF_MEMORY;
 
+    infof(data, "schannel: InitializeSecurityContext failed: %s\n",
+          Curl_sspi_strerror(status, buffer, sizeof(buffer)));
+
     return CURLE_AUTH_ERROR;
   }
 
@@ -433,7 +439,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
                                               &SecurityPackage);
   if(status != SEC_E_OK) {
-    failf(data, "SSPI: couldn't get auth info\n");
+    failf(data, "SSPI: couldn't get auth info");
     return CURLE_AUTH_ERROR;
   }
 
@@ -611,6 +617,8 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
        status == SEC_I_COMPLETE_AND_CONTINUE)
       s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
     else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+      char buffer[STRERROR_LEN];
+
       s_pSecFn->FreeCredentialsHandle(&credentials);
 
       Curl_sspi_free_identity(p_identity);
@@ -621,6 +629,9 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
       if(status == SEC_E_INSUFFICIENT_MEMORY)
         return CURLE_OUT_OF_MEMORY;
 
+      infof(data, "schannel: InitializeSecurityContext failed: %s\n",
+            Curl_sspi_strerror(status, buffer, sizeof(buffer)));
+
       return CURLE_AUTH_ERROR;
     }
 
index 95bab0e..0412815 100644 (file)
@@ -6,11 +6,11 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>.
- * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 1fb6257..b2d1635 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -125,7 +125,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
                                                 TEXT(SP_NAME_KERBEROS),
                                                 &SecurityPackage);
     if(status != SEC_E_OK) {
-      failf(data, "SSPI: couldn't get auth info\n");
+      failf(data, "SSPI: couldn't get auth info");
       return CURLE_AUTH_ERROR;
     }
 
index ecfeacb..a3117f3 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -497,7 +497,6 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
                                              const char *passwdp,
                                              struct ntlmdata *ntlm,
                                              char **outptr, size_t *outlen)
-
 {
   /* NTLM type-3 message structure:
 
index 1136b0f..8ec23ad 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 84ea51d..07dc973 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -106,7 +106,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
                                               &SecurityPackage);
   if(status != SEC_E_OK) {
-    failf(data, "SSPI: couldn't get auth info\n");
+    failf(data, "SSPI: couldn't get auth info");
     return CURLE_AUTH_ERROR;
   }
 
index b4e9f8e..ca5842a 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index ed7ce02..120925f 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 194f250..4aa1ba9 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -130,7 +130,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
                                                       TEXT(SP_NAME_NEGOTIATE),
                                                       &SecurityPackage);
     if(nego->status != SEC_E_OK) {
-      failf(data, "SSPI: couldn't get auth info\n");
+      failf(data, "SSPI: couldn't get auth info");
       return CURLE_AUTH_ERROR;
     }
 
index d98e66c..129b8f8 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index a1a557d..f25cfc3 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>.
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 4f6dda2..a9102ec 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -31,8 +31,8 @@
 #include "curl_printf.h"
 
 #ifdef USE_ARES
-#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
-     (defined(WIN32) || defined(__SYMBIAN32__))
+#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
+  defined(WIN32)
 #    define CARES_STATICLIB
 #  endif
 #  include <ares.h>
 
 #ifdef HAVE_ZLIB_H
 #include <zlib.h>
-#ifdef __SYMBIAN32__
-/* zlib pollutes the namespace with this definition */
-#undef WIN32
-#endif
 #endif
 
 #ifdef HAVE_BROTLI
@@ -104,7 +100,7 @@ static size_t zstd_version(char *buf, size_t bufsz)
  * zeros in the data.
  */
 
-#define VERSION_PARTS 14 /* number of substrings we can concatenate */
+#define VERSION_PARTS 15 /* number of substrings we can concatenate */
 
 char *curl_version(void)
 {
@@ -148,6 +144,9 @@ char *curl_version(void)
 #ifdef USE_LIBRTMP
   char rtmp_version[40];
 #endif
+#ifdef USE_HYPER
+  char hyper_buf[30];
+#endif
   int i = 0;
   int j;
 
@@ -232,6 +231,10 @@ char *curl_version(void)
     src[i++] = rtmp_version;
   }
 #endif
+#ifdef USE_HYPER
+  msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s", hyper_version());
+  src[i++] = hyper_buf;
+#endif
 
   DEBUGASSERT(i <= VERSION_PARTS);
 
@@ -278,6 +281,9 @@ static const char * const protocols[] = {
 #ifndef CURL_DISABLE_GOPHER
   "gopher",
 #endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
+  "gophers",
+#endif
 #ifndef CURL_DISABLE_HTTP
   "http",
 #endif
@@ -298,7 +304,7 @@ static const char * const protocols[] = {
   "ldaps",
 #endif
 #endif
-#ifdef CURL_ENABLE_MQTT
+#ifndef CURL_DISABLE_MQTT
   "mqtt",
 #endif
 #ifndef CURL_DISABLE_POP3
@@ -319,9 +325,8 @@ static const char * const protocols[] = {
 #ifdef USE_SSH
   "sftp",
 #endif
-#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
-   (CURL_SIZEOF_CURL_OFF_T > 4) && \
-   (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO))
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
+   (CURL_SIZEOF_CURL_OFF_T > 4)
   "smb",
 #  ifdef USE_SSL
   "smbs",
@@ -399,7 +404,7 @@ static curl_version_info_data version_info = {
 #if defined(USE_TLS_SRP)
   | CURL_VERSION_TLSAUTH_SRP
 #endif
-#if defined(USE_NGHTTP2)
+#if defined(USE_NGHTTP2) || defined(USE_HYPER)
   | CURL_VERSION_HTTP2
 #endif
 #if defined(ENABLE_QUIC)
@@ -420,9 +425,12 @@ static curl_version_info_data version_info = {
 #if defined(HAVE_ZSTD)
   | CURL_VERSION_ZSTD
 #endif
-#if defined(USE_ALTSVC)
+#ifndef CURL_DISABLE_ALTSVC
   | CURL_VERSION_ALTSVC
 #endif
+#if defined(USE_HSTS)
+  | CURL_VERSION_HSTS
+#endif
   ,
   NULL, /* ssl_version */
   0,    /* ssl_version_num, this is kept at zero */
@@ -449,7 +457,8 @@ static curl_version_info_data version_info = {
   NULL,
 #endif
   0,    /* zstd_ver_num */
-  NULL  /* zstd version */
+  NULL, /* zstd version */
+  NULL  /* Hyper version */
 };
 
 curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -471,15 +480,16 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
   static char zstd_buffer[80];
 #endif
 
-
 #ifdef USE_SSL
   Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
   version_info.ssl_version = ssl_buffer;
+#ifndef CURL_DISABLE_PROXY
   if(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY)
     version_info.features |= CURL_VERSION_HTTPS_PROXY;
   else
     version_info.features &= ~CURL_VERSION_HTTPS_PROXY;
 #endif
+#endif
 
 #ifdef HAVE_LIBZ
   version_info.libz_version = zlibVersion();
@@ -544,6 +554,14 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
   }
 #endif
 
+#ifdef USE_HYPER
+  {
+    static char hyper_buffer[30];
+    msnprintf(hyper_buffer, sizeof(hyper_buffer), "Hyper/%s", hyper_version());
+    version_info.hyper_version = hyper_buffer;
+  }
+#endif
+
   (void)stamp; /* avoid compiler warnings, we don't use this */
   return &version_info;
 }
index 6561d36..b8157e9 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 94cc626..9b1bd88 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 20ee08d..d4d0e8b 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -87,10 +87,10 @@ struct h3out {
   "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1"
 #endif
 
-static CURLcode ng_process_ingress(struct connectdata *conn,
+static CURLcode ng_process_ingress(struct Curl_easy *data,
                                    curl_socket_t sockfd,
                                    struct quicsocket *qs);
-static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
+static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd,
                                 struct quicsocket *qs);
 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
                                    size_t datalen, void *user_data,
@@ -126,7 +126,7 @@ quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
   case ssl_encryption_handshake:
     return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
   case ssl_encryption_application:
-    return NGTCP2_CRYPTO_LEVEL_APP;
+    return NGTCP2_CRYPTO_LEVEL_APPLICATION;
   default:
     assert(0);
   }
@@ -143,7 +143,7 @@ quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)
   case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE:
     return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
   case GNUTLS_ENCRYPTION_LEVEL_APPLICATION:
-    return NGTCP2_CRYPTO_LEVEL_APP;
+    return NGTCP2_CRYPTO_LEVEL_APPLICATION;
   default:
     assert(0);
   }
@@ -170,20 +170,22 @@ static void quic_settings(struct quicsocket *qs,
                           uint64_t stream_buffer_size)
 {
   ngtcp2_settings *s = &qs->settings;
+  ngtcp2_transport_params *t = &qs->transport_params;
   ngtcp2_settings_default(s);
+  ngtcp2_transport_params_default(t);
 #ifdef DEBUG_NGTCP2
   s->log_printf = quic_printf;
 #else
   s->log_printf = NULL;
 #endif
   s->initial_ts = timestamp();
-  s->transport_params.initial_max_stream_data_bidi_local = stream_buffer_size;
-  s->transport_params.initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS;
-  s->transport_params.initial_max_stream_data_uni = QUIC_MAX_STREAMS;
-  s->transport_params.initial_max_data = QUIC_MAX_DATA;
-  s->transport_params.initial_max_streams_bidi = 1;
-  s->transport_params.initial_max_streams_uni = 3;
-  s->transport_params.max_idle_timeout = QUIC_IDLE_TIMEOUT;
+  t->initial_max_stream_data_bidi_local = stream_buffer_size;
+  t->initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS;
+  t->initial_max_stream_data_uni = QUIC_MAX_STREAMS;
+  t->initial_max_data = QUIC_MAX_DATA;
+  t->initial_max_streams_bidi = 1;
+  t->initial_max_streams_uni = 3;
+  t->max_idle_timeout = QUIC_IDLE_TIMEOUT;
   if(qs->qlogfd != -1) {
     s->qlog.write = qlog_callback;
   }
@@ -265,7 +267,7 @@ static int quic_set_encryption_secrets(SSL *ssl,
        qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
     return 0;
 
-  if(level == NGTCP2_CRYPTO_LEVEL_APP) {
+  if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
     if(init_ngh3_conn(qs) != CURLE_OK)
       return 0;
   }
@@ -349,14 +351,8 @@ static int quic_init_ssl(struct quicsocket *qs)
   SSL_set_app_data(qs->ssl, qs);
   SSL_set_connect_state(qs->ssl);
 
-  switch(qs->version) {
-#ifdef NGTCP2_PROTO_VER
-  case NGTCP2_PROTO_VER:
-    alpn = (const uint8_t *)NGHTTP3_ALPN_H3;
-    alpnlen = sizeof(NGHTTP3_ALPN_H3) - 1;
-    break;
-#endif
-  }
+  alpn = (const uint8_t *)NGHTTP3_ALPN_H3;
+  alpnlen = sizeof(NGHTTP3_ALPN_H3) - 1;
   if(alpn)
     SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
 
@@ -382,7 +378,7 @@ static int secret_func(gnutls_session_t ssl,
        qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
     return 0;
 
-  if(level == NGTCP2_CRYPTO_LEVEL_APP) {
+  if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
     if(init_ngh3_conn(qs) != CURLE_OK)
       return -1;
   }
@@ -532,15 +528,9 @@ static int quic_init_ssl(struct quicsocket *qs)
     return 1;
   }
 
-  switch(qs->version) {
-#ifdef NGTCP2_PROTO_VER
-  case NGTCP2_PROTO_VER:
-    /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
-    alpn.data = (unsigned char *)NGHTTP3_ALPN_H3 + 1;
-    alpn.size = sizeof(NGHTTP3_ALPN_H3) - 2;
-    break;
-#endif
-  }
+  /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
+  alpn.data = (unsigned char *)NGHTTP3_ALPN_H3 + 1;
+  alpn.size = sizeof(NGHTTP3_ALPN_H3) - 2;
   if(alpn.data)
     gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0);
 
@@ -568,10 +558,8 @@ cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level,
 
 static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
 {
-  struct quicsocket *qs = (struct quicsocket *)user_data;
+  (void)user_data;
   (void)tconn;
-  infof(qs->conn->data, "QUIC handshake is completed\n");
-
   return 0;
 }
 
@@ -599,8 +587,6 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
   nconsumed =
     nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin);
   if(nconsumed < 0) {
-    failf(qs->conn->data, "nghttp3_conn_read_stream returned error: %s\n",
-          nghttp3_strerror((int)nconsumed));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -628,8 +614,6 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
 
   rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_add_ack_offset returned error: %s\n",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -649,8 +633,6 @@ static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id,
   rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
                                  app_error_code);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_close_stream returned error: %s\n",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -670,8 +652,6 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
 
   rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_reset_stream returned error: %s\n",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -701,8 +681,6 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
 
   rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
   if(rv != 0) {
-    failf(qs->conn->data, "nghttp3_conn_unblock_stream returned error: %s\n",
-          nghttp3_strerror(rv));
     return NGTCP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -713,23 +691,23 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
                                     uint8_t *token, size_t cidlen,
                                     void *user_data)
 {
-  struct quicsocket *qs = (struct quicsocket *)user_data;
   CURLcode result;
   (void)tconn;
+  (void)user_data;
 
-  result = Curl_rand(qs->conn->data, cid->data, cidlen);
+  result = Curl_rand(NULL, cid->data, cidlen);
   if(result)
     return NGTCP2_ERR_CALLBACK_FAILURE;
   cid->datalen = cidlen;
 
-  result = Curl_rand(qs->conn->data, token, NGTCP2_STATELESS_RESET_TOKENLEN);
+  result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
   if(result)
     return NGTCP2_ERR_CALLBACK_FAILURE;
 
   return 0;
 }
 
-static ngtcp2_conn_callbacks ng_callbacks = {
+static ngtcp2_callbacks ng_callbacks = {
   ngtcp2_crypto_client_initial_cb,
   NULL, /* recv_client_initial */
   cb_recv_crypto_data,
@@ -767,7 +745,8 @@ static ngtcp2_conn_callbacks ng_callbacks = {
 /*
  * Might be called twice for happy eyeballs.
  */
-CURLcode Curl_quic_connect(struct connectdata *conn,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+                           struct connectdata *conn,
                            curl_socket_t sockfd,
                            int sockindex,
                            const struct sockaddr *addr,
@@ -777,14 +756,13 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
   int rv;
   CURLcode result;
   ngtcp2_path path; /* TODO: this must be initialized properly */
-  struct Curl_easy *data = conn->data;
   struct quicsocket *qs = &conn->hequic[sockindex];
   char ipbuf[40];
   long port;
   int qfd;
 
   if(qs->conn)
-    Curl_quic_disconnect(conn, sockindex);
+    Curl_quic_disconnect(data, conn, sockindex);
   qs->conn = conn;
 
   /* extract the used address as a string */
@@ -798,7 +776,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
   infof(data, "Connect socket %d over QUIC to %s:%ld\n",
         sockfd, ipbuf, port);
 
-  qs->version = NGTCP2_PROTO_VER;
+  qs->version = NGTCP2_PROTO_VER_MAX;
 #ifdef USE_OPENSSL
   qs->sslctx = quic_ssl_ctx(data);
   if(!qs->sslctx)
@@ -828,16 +806,13 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
   if(rv == -1)
     return CURLE_QUIC_CONNECT_ERROR;
 
-  ngtcp2_addr_init(&path.local, &qs->local_addr, qs->local_addrlen, NULL);
+  ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
+                   qs->local_addrlen, NULL);
   ngtcp2_addr_init(&path.remote, addr, addrlen, NULL);
 
-#ifdef NGTCP2_PROTO_VER
-#define QUICVER NGTCP2_PROTO_VER
-#else
-#error "unsupported ngtcp2 version"
-#endif
-  rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, QUICVER,
-                              &ng_callbacks, &qs->settings, NULL, qs);
+  rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path,
+                              NGTCP2_PROTO_VER_MIN, &ng_callbacks,
+                              &qs->settings, &qs->transport_params, NULL, qs);
   if(rc)
     return CURLE_QUIC_CONNECT_ERROR;
 
@@ -858,9 +833,10 @@ int Curl_quic_ver(char *p, size_t len)
                    ng2->version_str, ht3->version_str);
 }
 
-static int ng_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
+                      curl_socket_t *socks)
 {
-  struct SingleRequest *k = &conn->data->req;
+  struct SingleRequest *k = &data->req;
   int bitmap = GETSOCK_BLANK;
 
   socks[0] = conn->sock[FIRSTSOCKET];
@@ -876,12 +852,6 @@ static int ng_getsock(struct connectdata *conn, curl_socket_t *socks)
   return bitmap;
 }
 
-static int ng_perform_getsock(const struct connectdata *conn,
-                              curl_socket_t *socks)
-{
-  return ng_getsock((struct connectdata *)conn, socks);
-}
-
 static void qs_disconnect(struct quicsocket *qs)
 {
   int i;
@@ -912,25 +882,30 @@ static void qs_disconnect(struct quicsocket *qs)
 #endif
 }
 
-void Curl_quic_disconnect(struct connectdata *conn,
+void Curl_quic_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn,
                           int tempindex)
 {
+  (void)data;
   if(conn->transport == TRNSPRT_QUIC)
     qs_disconnect(&conn->hequic[tempindex]);
 }
 
-static CURLcode ng_disconnect(struct connectdata *conn,
+static CURLcode ng_disconnect(struct Curl_easy *data,
+                              struct connectdata *conn,
                               bool dead_connection)
 {
   (void)dead_connection;
-  Curl_quic_disconnect(conn, 0);
-  Curl_quic_disconnect(conn, 1);
+  Curl_quic_disconnect(data, conn, 0);
+  Curl_quic_disconnect(data, conn, 1);
   return CURLE_OK;
 }
 
-static unsigned int ng_conncheck(struct connectdata *conn,
+static unsigned int ng_conncheck(struct Curl_easy *data,
+                                 struct connectdata *conn,
                                  unsigned int checks_to_perform)
 {
+  (void)data;
   (void)conn;
   (void)checks_to_perform;
   return CONNRESULT_NONE;
@@ -948,12 +923,13 @@ static const struct Curl_handler Curl_handler_http3 = {
   ng_getsock,                           /* proto_getsock */
   ng_getsock,                           /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  ng_perform_getsock,                   /* perform_getsock */
+  ng_getsock,                           /* perform_getsock */
   ng_disconnect,                        /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ng_conncheck,                         /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
+  CURLPROTO_HTTP,                       /* family */
   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
 };
 
@@ -962,7 +938,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
                               void *stream_user_data)
 {
   struct Curl_easy *data = stream_user_data;
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   (void)conn;
   (void)stream_id;
   (void)app_error_code;
@@ -1008,7 +984,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
                            void *user_data, void *stream_user_data)
 {
   struct Curl_easy *data = stream_user_data;
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   CURLcode result = CURLE_OK;
   (void)conn;
 
@@ -1067,7 +1043,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
                              void *user_data, void *stream_user_data)
 {
   struct Curl_easy *data = stream_user_data;
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   CURLcode result = CURLE_OK;
   (void)conn;
   (void)stream_id;
@@ -1091,7 +1067,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
   nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
   nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
   struct Curl_easy *data = stream_user_data;
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   CURLcode result = CURLE_OK;
   (void)conn;
   (void)stream_id;
@@ -1148,7 +1124,7 @@ static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id,
   return 0;
 }
 
-static nghttp3_conn_callbacks ngh3_callbacks = {
+static nghttp3_callbacks ngh3_callbacks = {
   cb_h3_acked_stream_data, /* acked_stream_data */
   cb_h3_stream_close,
   cb_h3_recv_data,
@@ -1166,6 +1142,7 @@ static nghttp3_conn_callbacks ngh3_callbacks = {
   cb_h3_send_stop_sending,
   NULL, /* push_stream */
   NULL, /* end_stream */
+  NULL, /* reset_stream */
 };
 
 static int init_ngh3_conn(struct quicsocket *qs)
@@ -1175,11 +1152,10 @@ static int init_ngh3_conn(struct quicsocket *qs)
   int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
 
   if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) {
-    failf(qs->conn->data, "too few available QUIC streams");
     return CURLE_QUIC_CONNECT_ERROR;
   }
 
-  nghttp3_conn_settings_default(&qs->h3settings);
+  nghttp3_settings_default(&qs->h3settings);
 
   rc = nghttp3_conn_client_new(&qs->h3conn,
                                &ngh3_callbacks,
@@ -1248,14 +1224,15 @@ static size_t drain_overflow_buffer(struct HTTP *stream)
 }
 
 /* incoming data frames on the h3 stream */
-static ssize_t ngh3_stream_recv(struct connectdata *conn,
+static ssize_t ngh3_stream_recv(struct Curl_easy *data,
                                 int sockindex,
                                 char *buf,
                                 size_t buffersize,
                                 CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[sockindex];
-  struct HTTP *stream = conn->data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   struct quicsocket *qs = conn->quic;
 
   if(!stream->memlen) {
@@ -1270,11 +1247,11 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn,
      as possible to the receive buffer before receiving more */
   drain_overflow_buffer(stream);
 
-  if(ng_process_ingress(conn, sockfd, qs)) {
+  if(ng_process_ingress(data, sockfd, qs)) {
     *curlcode = CURLE_RECV_ERROR;
     return -1;
   }
-  if(ng_flush_egress(conn, sockfd, qs)) {
+  if(ng_flush_egress(data, sockfd, qs)) {
     *curlcode = CURLE_SEND_ERROR;
     return -1;
   }
@@ -1290,7 +1267,7 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn,
     /* extend the stream window with the data we're consuming and send out
        any additional packets to tell the server that we can receive more */
     extend_stream_window(qs->qconn, stream);
-    if(ng_flush_egress(conn, sockfd, qs)) {
+    if(ng_flush_egress(data, sockfd, qs)) {
       *curlcode = CURLE_SEND_ERROR;
       return -1;
     }
@@ -1302,7 +1279,7 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn,
     return 0;
   }
 
-  infof(conn->data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n");
+  infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n");
   *curlcode = CURLE_AGAIN;
   return -1;
 }
@@ -1313,9 +1290,8 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
                                    void *stream_user_data)
 {
   struct Curl_easy *data = stream_user_data;
-  struct HTTP *stream = data->req.protop;
-  (void)conn;
-  (void)stream_id;
+  struct HTTP *stream = data->req.p.http;
+  int rv;
   (void)user_data;
 
   if(!data->set.postfields) {
@@ -1324,6 +1300,13 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
                  "cb_h3_acked_stream_data, %zd bytes, %zd left unacked\n",
                  datalen, stream->h3out->used));
     DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
+
+    if(stream->h3out->used == 0) {
+      rv = nghttp3_conn_resume_stream(conn, stream_id);
+      if(rv != 0) {
+        return NGTCP2_ERR_CALLBACK_FAILURE;
+      }
+    }
   }
   return 0;
 }
@@ -1335,7 +1318,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
 {
   struct Curl_easy *data = stream_user_data;
   size_t nread;
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   (void)conn;
   (void)stream_id;
   (void)user_data;
@@ -1359,13 +1342,14 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
       nread = H3_SEND_SIZE - out->windex;
 
     memcpy(&out->buf[out->windex], stream->upload_mem, nread);
-    out->windex += nread;
-    out->used += nread;
 
     /* that's the chunk we return to nghttp3 */
     vec[0].base = &out->buf[out->windex];
     vec[0].len = nread;
 
+    out->windex += nread;
+    out->used += nread;
+
     if(out->windex == H3_SEND_SIZE)
       out->windex = 0; /* wrap */
     stream->upload_mem += nread;
@@ -1383,7 +1367,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
      (stream->upload_left <= 0)) {
     H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF\n"));
     *pflags = NGHTTP3_DATA_FLAG_EOF;
-    return 0;
+    return nread ? 1 : 0;
   }
   else if(!nread) {
     return NGHTTP3_ERR_WOULDBLOCK;
@@ -1395,10 +1379,11 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
    field list. */
 #define AUTHORITY_DST_IDX 3
 
-static CURLcode http_request(struct connectdata *conn, const void *mem,
+static CURLcode http_request(struct Curl_easy *data, const void *mem,
                              size_t len)
 {
-  struct HTTP *stream = conn->data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct HTTP *stream = data->req.p.http;
   size_t nheader;
   size_t i;
   size_t authority_idx;
@@ -1406,7 +1391,6 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
   char *end, *line_end;
   struct quicsocket *qs = conn->quic;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   nghttp3_nv *nva = NULL;
   int64_t stream3_id;
   int rc;
@@ -1414,7 +1398,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
 
   rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL);
   if(rc) {
-    failf(conn->data, "can get bidi streams");
+    failf(data, "can get bidi streams");
     result = CURLE_SEND_ERROR;
     goto fail;
   }
@@ -1573,7 +1557,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
 
     if(acc > MAX_ACC) {
       infof(data, "http_request: Warning: The cumulative length of all "
-            "headers exceeds %zu bytes and that could cause the "
+            "headers exceeds %d bytes and that could cause the "
             "stream to be rejected.\n", MAX_ACC);
     }
   }
@@ -1600,8 +1584,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
     stream->h3out = h3out;
 
     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
-                                     nva, nheader, &data_reader,
-                                     conn->data);
+                                     nva, nheader, &data_reader, data);
     if(rc) {
       result = CURLE_SEND_ERROR;
       goto fail;
@@ -1611,9 +1594,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
   default:
     stream->upload_left = 0; /* nothing left to send */
     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
-                                     nva, nheader,
-                                     NULL, /* no body! */
-                                     conn->data);
+                                     nva, nheader, NULL, data);
     if(rc) {
       result = CURLE_SEND_ERROR;
       goto fail;
@@ -1632,19 +1613,20 @@ fail:
   free(nva);
   return result;
 }
-static ssize_t ngh3_stream_send(struct connectdata *conn,
+static ssize_t ngh3_stream_send(struct Curl_easy *data,
                                 int sockindex,
                                 const void *mem,
                                 size_t len,
                                 CURLcode *curlcode)
 {
   ssize_t sent;
+  struct connectdata *conn = data->conn;
   struct quicsocket *qs = conn->quic;
   curl_socket_t sockfd = conn->sock[sockindex];
-  struct HTTP *stream = conn->data->req.protop;
+  struct HTTP *stream = data->req.p.http;
 
   if(!stream->h3req) {
-    CURLcode result = http_request(conn, mem, len);
+    CURLcode result = http_request(data, mem, len);
     if(result) {
       *curlcode = CURLE_SEND_ERROR;
       return -1;
@@ -1652,7 +1634,7 @@ static ssize_t ngh3_stream_send(struct connectdata *conn,
     sent = len;
   }
   else {
-    H3BUGF(infof(conn->data, "ngh3_stream_send() wants to send %zd bytes\n",
+    H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes\n",
                  len));
     if(!stream->upload_len) {
       stream->upload_mem = mem;
@@ -1666,7 +1648,7 @@ static ssize_t ngh3_stream_send(struct connectdata *conn,
     }
   }
 
-  if(ng_flush_egress(conn, sockfd, qs)) {
+  if(ng_flush_egress(data, sockfd, qs)) {
     *curlcode = CURLE_SEND_ERROR;
     return -1;
   }
@@ -1684,13 +1666,13 @@ static void ng_has_connected(struct connectdata *conn, int tempindex)
   conn->httpversion = 30;
   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
   conn->quic = &conn->hequic[tempindex];
-  DEBUGF(infof(conn->data, "ngtcp2 established connection!\n"));
 }
 
 /*
  * There can be multiple connection attempts going on in parallel.
  */
-CURLcode Curl_quic_is_connected(struct connectdata *conn,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 int sockindex,
                                 bool *done)
 {
@@ -1698,11 +1680,11 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn,
   struct quicsocket *qs = &conn->hequic[sockindex];
   curl_socket_t sockfd = conn->tempsock[sockindex];
 
-  result = ng_process_ingress(conn, sockfd, qs);
+  result = ng_process_ingress(data, sockfd, qs);
   if(result)
     goto error;
 
-  result = ng_flush_egress(conn, sockfd, qs);
+  result = ng_flush_egress(data, sockfd, qs);
   if(result)
     goto error;
 
@@ -1718,7 +1700,8 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn,
 
 }
 
-static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
+static CURLcode ng_process_ingress(struct Curl_easy *data,
+                                   curl_socket_t sockfd,
                                    struct quicsocket *qs)
 {
   ssize_t recvd;
@@ -1729,10 +1712,11 @@ static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
   socklen_t remote_addrlen;
   ngtcp2_path path;
   ngtcp2_tstamp ts = timestamp();
+  ngtcp2_pkt_info pi = { 0 };
 
   for(;;) {
     remote_addrlen = sizeof(remote_addr);
-    while((recvd = recvfrom(sockfd, buf, bufsize, 0,
+    while((recvd = recvfrom(sockfd, (char *)buf, bufsize, 0,
                             (struct sockaddr *)&remote_addr,
                             &remote_addrlen)) == -1 &&
           SOCKERRNO == EINTR)
@@ -1741,16 +1725,16 @@ static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
       if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)
         break;
 
-      failf(conn->data, "ngtcp2: recvfrom() unexpectedly returned %d", recvd);
+      failf(data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd);
       return CURLE_RECV_ERROR;
     }
 
-    ngtcp2_addr_init(&path.local, &qs->local_addr,
+    ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
                      qs->local_addrlen, NULL);
     ngtcp2_addr_init(&path.remote, (struct sockaddr *)&remote_addr,
                      remote_addrlen, NULL);
 
-    rv = ngtcp2_conn_read_pkt(qs->qconn, &path, buf, recvd, ts);
+    rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
     if(rv != 0) {
       /* TODO Send CONNECTION_CLOSE if possible */
       return CURLE_RECV_ERROR;
@@ -1760,7 +1744,8 @@ static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
   return CURLE_OK;
 }
 
-static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
+static CURLcode ng_flush_egress(struct Curl_easy *data,
+                                int sockfd,
                                 struct quicsocket *qs)
 {
   int rv;
@@ -1778,8 +1763,9 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
   int fin;
   nghttp3_vec vec[16];
   ssize_t ndatalen;
+  uint32_t flags;
 
-  switch(qs->local_addr.sa_family) {
+  switch(qs->local_addr.ss_family) {
   case AF_INET:
     pktlen = NGTCP2_MAX_PKTLEN_IPV4;
     break;
@@ -1794,7 +1780,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
 
   rv = ngtcp2_conn_handle_expiry(qs->qconn, ts);
   if(rv != 0) {
-    failf(conn->data, "ngtcp2_conn_handle_expiry returned error: %s\n",
+    failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
           ngtcp2_strerror(rv));
     return CURLE_SEND_ERROR;
   }
@@ -1803,75 +1789,68 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
 
   for(;;) {
     outlen = -1;
+    veccnt = 0;
+    stream_id = -1;
+    fin = 0;
+
     if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) {
       veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec,
                                           sizeof(vec) / sizeof(vec[0]));
       if(veccnt < 0) {
-        failf(conn->data, "nghttp3_conn_writev_stream returned error: %s\n",
+        failf(data, "nghttp3_conn_writev_stream returned error: %s",
               nghttp3_strerror((int)veccnt));
         return CURLE_SEND_ERROR;
       }
-      else if(veccnt > 0) {
-        uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
-          (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
-        outlen =
-          ngtcp2_conn_writev_stream(qs->qconn, &ps.path,
-                                    out, pktlen, &ndatalen,
-                                    flags, stream_id,
-                                    (const ngtcp2_vec *)vec, veccnt, ts);
-        if(outlen == 0) {
-          break;
-        }
-        if(outlen < 0) {
-          if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED ||
-             outlen == NGTCP2_ERR_STREAM_SHUT_WR) {
-            assert(ndatalen == -1);
-            rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
-            if(rv != 0) {
-              failf(conn->data,
-                    "nghttp3_conn_block_stream returned error: %s\n",
-                    nghttp3_strerror(rv));
-              return CURLE_SEND_ERROR;
-            }
-            continue;
-          }
-          else if(outlen == NGTCP2_ERR_WRITE_MORE) {
-            assert(ndatalen > 0);
-            rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id,
-                                               ndatalen);
-            if(rv != 0) {
-              failf(conn->data,
-                    "nghttp3_conn_add_write_offset returned error: %s\n",
-                    nghttp3_strerror(rv));
-              return CURLE_SEND_ERROR;
-            }
-            continue;
-          }
-          else {
-            assert(ndatalen == -1);
-            failf(conn->data, "ngtcp2_conn_writev_stream returned error: %s\n",
-                  ngtcp2_strerror((int)outlen));
-            return CURLE_SEND_ERROR;
-          }
+    }
+
+    flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
+            (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
+    outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out, pktlen,
+                                       &ndatalen, flags, stream_id,
+                                       (const ngtcp2_vec *)vec, veccnt, ts);
+    if(outlen == 0) {
+      break;
+    }
+    if(outlen < 0) {
+      if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED ||
+         outlen == NGTCP2_ERR_STREAM_SHUT_WR) {
+        assert(ndatalen == -1);
+        rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
+        if(rv != 0) {
+          failf(data, "nghttp3_conn_block_stream returned error: %s\n",
+                nghttp3_strerror(rv));
+          return CURLE_SEND_ERROR;
         }
-        else {
-          assert(ndatalen == -1);
+        continue;
+      }
+      else if(outlen == NGTCP2_ERR_WRITE_MORE) {
+        assert(ndatalen >= 0);
+        rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
+        if(rv != 0) {
+          failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
+                nghttp3_strerror(rv));
+          return CURLE_SEND_ERROR;
         }
+        continue;
       }
-    }
-    if(outlen < 0) {
-      outlen = ngtcp2_conn_write_pkt(qs->qconn, &ps.path, out, pktlen, ts);
-      if(outlen < 0) {
-        failf(conn->data, "ngtcp2_conn_write_pkt returned error: %s\n",
+      else {
+        assert(ndatalen == -1);
+        failf(data, "ngtcp2_conn_writev_stream returned error: %s",
               ngtcp2_strerror((int)outlen));
         return CURLE_SEND_ERROR;
       }
-      if(outlen == 0)
-        break;
+    }
+    else if(ndatalen >= 0) {
+      rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
+      if(rv != 0) {
+        failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
+              nghttp3_strerror(rv));
+        return CURLE_SEND_ERROR;
+      }
     }
 
     memcpy(&remote_addr, ps.path.remote.addr, ps.path.remote.addrlen);
-    while((sent = send(sockfd, out, outlen, 0)) == -1 &&
+    while((sent = send(sockfd, (const char *)out, outlen, 0)) == -1 &&
           SOCKERRNO == EINTR)
       ;
 
@@ -1881,7 +1860,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
         break;
       }
       else {
-        failf(conn->data, "send() returned %zd (errno %d)\n", sent,
+        failf(data, "send() returned %zd (errno %d)", sent,
               SOCKERRNO);
         return CURLE_SEND_ERROR;
       }
@@ -1896,7 +1875,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
     else {
       timeout = expiry - ts;
     }
-    Curl_expire(conn->data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
+    Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
   }
 
   return CURLE_OK;
@@ -1905,11 +1884,13 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
 /*
  * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
  */
-CURLcode Curl_quic_done_sending(struct connectdata *conn)
+CURLcode Curl_quic_done_sending(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
+  DEBUGASSERT(conn);
   if(conn->handler == &Curl_handler_http3) {
     /* only for HTTP/3 transfers */
-    struct HTTP *stream = conn->data->req.protop;
+    struct HTTP *stream = data->req.p.http;
     struct quicsocket *qs = conn->quic;
     stream->upload_done = TRUE;
     (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
@@ -1926,7 +1907,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature)
   (void)premature;
   if(data->conn->handler == &Curl_handler_http3) {
     /* only for HTTP/3 transfers */
-    struct HTTP *stream = data->req.protop;
+    struct HTTP *stream = data->req.p.http;
     Curl_dyn_free(&stream->overflow);
   }
 }
@@ -1941,7 +1922,7 @@ bool Curl_quic_data_pending(const struct Curl_easy *data)
      buffer and allocated an overflow buffer. Since it's possible that
      there's no more data coming on the socket, we need to keep reading
      until the overflow buffer is empty. */
-  const struct HTTP *stream = data->req.protop;
+  const struct HTTP *stream = data->req.p.http;
   return Curl_dyn_len(&stream->overflow) > 0;
 }
 
index afdd01b..cbede45 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -48,6 +48,7 @@ struct quicsocket {
   ngtcp2_cid scid;
   uint32_t version;
   ngtcp2_settings settings;
+  ngtcp2_transport_params transport_params;
 #ifdef USE_OPENSSL
   SSL_CTX *sslctx;
   SSL *ssl;
@@ -58,11 +59,11 @@ struct quicsocket {
   struct quic_handshake crypto_data[3];
   /* the last TLS alert description generated by the local endpoint */
   uint8_t tls_alert;
-  struct sockaddr local_addr;
+  struct sockaddr_storage local_addr;
   socklen_t local_addrlen;
 
   nghttp3_conn *h3conn;
-  nghttp3_conn_settings h3settings;
+  nghttp3_settings h3settings;
   int qlogfd;
 };
 
index fd9cb8b..d138dd3 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #define QUIC_MAX_DATA (1*1024*1024)
 #define QUIC_IDLE_TIMEOUT (60 * 1000) /* milliseconds */
 
-static CURLcode process_ingress(struct connectdata *conn,
+static CURLcode process_ingress(struct Curl_easy *data,
                                 curl_socket_t sockfd,
                                 struct quicsocket *qs);
 
-static CURLcode flush_egress(struct connectdata *conn, curl_socket_t sockfd,
+static CURLcode flush_egress(struct Curl_easy *data, curl_socket_t sockfd,
                              struct quicsocket *qs);
 
-static CURLcode http_request(struct connectdata *conn, const void *mem,
+static CURLcode http_request(struct Curl_easy *data, const void *mem,
                              size_t len);
 static Curl_recv h3_stream_recv;
 static Curl_send h3_stream_send;
 
-static int quiche_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int quiche_getsock(struct Curl_easy *data,
+                          struct connectdata *conn, curl_socket_t *socks)
 {
-  struct SingleRequest *k = &conn->data->req;
+  struct SingleRequest *k = &data->req;
   int bitmap = GETSOCK_BLANK;
 
   socks[0] = conn->sock[FIRSTSOCKET];
@@ -83,14 +84,18 @@ static int quiche_getsock(struct connectdata *conn, curl_socket_t *socks)
   return bitmap;
 }
 
-static int quiche_perform_getsock(const struct connectdata *conn,
-                                  curl_socket_t *socks)
-{
-  return quiche_getsock((struct connectdata *)conn, socks);
-}
-
-static CURLcode qs_disconnect(struct quicsocket *qs)
+static CURLcode qs_disconnect(struct Curl_easy *data,
+                              struct quicsocket *qs)
 {
+  DEBUGASSERT(qs);
+  if(qs->conn) {
+    (void)quiche_conn_close(qs->conn, TRUE, 0, NULL, 0);
+    /* flushing the egress is not a failsafe way to deliver all the
+       outstanding packets, but we also don't want to get stuck here... */
+    (void)flush_egress(data, qs->sockfd, qs);
+    quiche_conn_free(qs->conn);
+    qs->conn = NULL;
+  }
   if(qs->h3config)
     quiche_h3_config_free(qs->h3config);
   if(qs->h3c)
@@ -99,41 +104,41 @@ static CURLcode qs_disconnect(struct quicsocket *qs)
     quiche_config_free(qs->cfg);
     qs->cfg = NULL;
   }
-  if(qs->conn) {
-    quiche_conn_free(qs->conn);
-    qs->conn = NULL;
-  }
   return CURLE_OK;
 }
 
-static CURLcode quiche_disconnect(struct connectdata *conn,
+static CURLcode quiche_disconnect(struct Curl_easy *data,
+                                  struct connectdata *conn,
                                   bool dead_connection)
 {
   struct quicsocket *qs = conn->quic;
   (void)dead_connection;
-  return qs_disconnect(qs);
+  return qs_disconnect(data, qs);
 }
 
-void Curl_quic_disconnect(struct connectdata *conn,
+void Curl_quic_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn,
                           int tempindex)
 {
   if(conn->transport == TRNSPRT_QUIC)
-    qs_disconnect(&conn->hequic[tempindex]);
+    qs_disconnect(data, &conn->hequic[tempindex]);
 }
 
-static unsigned int quiche_conncheck(struct connectdata *conn,
+static unsigned int quiche_conncheck(struct Curl_easy *data,
+                                     struct connectdata *conn,
                                      unsigned int checks_to_perform)
 {
+  (void)data;
   (void)conn;
   (void)checks_to_perform;
   return CONNRESULT_NONE;
 }
 
-static CURLcode quiche_do(struct connectdata *conn, bool *done)
+static CURLcode quiche_do(struct Curl_easy *data, bool *done)
 {
-  struct HTTP *stream = conn->data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   stream->h3req = FALSE; /* not sent */
-  return Curl_http(conn, done);
+  return Curl_http(data, done);
 }
 
 static const struct Curl_handler Curl_handler_http3 = {
@@ -148,12 +153,13 @@ static const struct Curl_handler Curl_handler_http3 = {
   quiche_getsock,                       /* proto_getsock */
   quiche_getsock,                       /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  quiche_perform_getsock,               /* perform_getsock */
+  quiche_getsock,                       /* perform_getsock */
   quiche_disconnect,                    /* disconnect */
   ZERO_NULL,                            /* readwrite */
   quiche_conncheck,                     /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
+  CURLPROTO_HTTP,                       /* family */
   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
 };
 
@@ -165,14 +171,16 @@ static void quiche_debug_log(const char *line, void *argp)
 }
 #endif
 
-CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+                           struct connectdata *conn, curl_socket_t sockfd,
                            int sockindex,
                            const struct sockaddr *addr, socklen_t addrlen)
 {
   CURLcode result;
   struct quicsocket *qs = &conn->hequic[sockindex];
-  struct Curl_easy *data = conn->data;
   char *keylog_file = NULL;
+  char ipbuf[40];
+  long port;
 
 #ifdef DEBUG_QUICHE
   /* initialize debug log callback only once */
@@ -186,6 +194,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
   (void)addr;
   (void)addrlen;
 
+  qs->sockfd = sockfd;
   qs->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
   if(!qs->cfg) {
     failf(data, "can't create quiche config");
@@ -236,20 +245,22 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
   }
 #endif
 
-  result = flush_egress(conn, sockfd, qs);
+  result = flush_egress(data, sockfd, qs);
   if(result)
     return result;
 
-  /* store the used address as a string */
-  if(!Curl_addr2string((struct sockaddr*)addr, addrlen,
-                       conn->primary_ip, &conn->primary_port)) {
+  /* extract the used address as a string */
+  if(!Curl_addr2string((struct sockaddr*)addr, addrlen, ipbuf, &port)) {
     char buffer[STRERROR_LEN];
     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
           SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
-  memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
-  Curl_persistconninfo(conn);
+
+  infof(data, "Connect socket %d over QUIC to %s:%ld\n",
+        sockfd, ipbuf, port);
+
+  Curl_persistconninfo(data, conn, NULL, -1);
 
   /* for connection reuse purposes: */
   conn->ssl[FIRSTSOCKET].state = ssl_connection_complete;
@@ -313,38 +324,39 @@ static CURLcode quiche_has_connected(struct connectdata *conn,
 /*
  * This function gets polled to check if this QUIC connection has connected.
  */
-CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                int sockindex,
                                 bool *done)
 {
   CURLcode result;
   struct quicsocket *qs = &conn->hequic[sockindex];
   curl_socket_t sockfd = conn->tempsock[sockindex];
 
-  result = process_ingress(conn, sockfd, qs);
+  result = process_ingress(data, sockfd, qs);
   if(result)
     goto error;
 
-  result = flush_egress(conn, sockfd, qs);
+  result = flush_egress(data, sockfd, qs);
   if(result)
     goto error;
 
   if(quiche_conn_is_established(qs->conn)) {
     *done = TRUE;
     result = quiche_has_connected(conn, 0, sockindex);
-    DEBUGF(infof(conn->data, "quiche established connection!\n"));
+    DEBUGF(infof(data, "quiche established connection!\n"));
   }
 
   return result;
   error:
-  qs_disconnect(qs);
+  qs_disconnect(data, qs);
   return result;
 }
 
-static CURLcode process_ingress(struct connectdata *conn, int sockfd,
+static CURLcode process_ingress(struct Curl_easy *data, int sockfd,
                                 struct quicsocket *qs)
 {
   ssize_t recvd;
-  struct Curl_easy *data = conn->data;
   uint8_t *buf = (uint8_t *)data->state.buffer;
   size_t bufsize = data->set.buffer_size;
 
@@ -357,7 +369,7 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd,
       break;
 
     if(recvd < 0) {
-      failf(conn->data, "quiche: recv() unexpectedly returned %d "
+      failf(data, "quiche: recv() unexpectedly returned %zd "
             "(errno: %d, socket %d)", recvd, SOCKERRNO, sockfd);
       return CURLE_RECV_ERROR;
     }
@@ -367,7 +379,7 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd,
       break;
 
     if(recvd < 0) {
-      failf(conn->data, "quiche_conn_recv() == %d", recvd);
+      failf(data, "quiche_conn_recv() == %zd", recvd);
       return CURLE_RECV_ERROR;
     }
   } while(1);
@@ -379,11 +391,11 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd,
  * flush_egress drains the buffers and sends off data.
  * Calls failf() on errors.
  */
-static CURLcode flush_egress(struct connectdata *conn, int sockfd,
+static CURLcode flush_egress(struct Curl_easy *data, int sockfd,
                              struct quicsocket *qs)
 {
   ssize_t sent;
-  static uint8_t out[1200];
+  uint8_t out[1200];
   int64_t timeout_ns;
 
   do {
@@ -392,14 +404,13 @@ static CURLcode flush_egress(struct connectdata *conn, int sockfd,
       break;
 
     if(sent < 0) {
-      failf(conn->data, "quiche_conn_send returned %zd\n",
-            sent);
+      failf(data, "quiche_conn_send returned %zd", sent);
       return CURLE_SEND_ERROR;
     }
 
     sent = send(sockfd, out, sent, 0);
     if(sent < 0) {
-      failf(conn->data, "send() returned %zd\n", sent);
+      failf(data, "send() returned %zd", sent);
       return CURLE_SEND_ERROR;
     }
   } while(1);
@@ -408,7 +419,7 @@ static CURLcode flush_egress(struct connectdata *conn, int sockfd,
   timeout_ns = quiche_conn_timeout_as_nanos(qs->conn);
   if(timeout_ns)
     /* expire uses milliseconds */
-    Curl_expire(conn->data, (timeout_ns + 999999) / 1000000, EXPIRE_QUIC);
+    Curl_expire(data, (timeout_ns + 999999) / 1000000, EXPIRE_QUIC);
 
   return CURLE_OK;
 }
@@ -446,7 +457,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
   return 0;
 }
 
-static ssize_t h3_stream_recv(struct connectdata *conn,
+static ssize_t h3_stream_recv(struct Curl_easy *data,
                               int sockindex,
                               char *buf,
                               size_t buffersize,
@@ -454,18 +465,18 @@ static ssize_t h3_stream_recv(struct connectdata *conn,
 {
   ssize_t recvd = -1;
   ssize_t rcode;
+  struct connectdata *conn = data->conn;
   struct quicsocket *qs = conn->quic;
   curl_socket_t sockfd = conn->sock[sockindex];
   quiche_h3_event *ev;
   int rc;
   struct h3h1header headers;
-  struct Curl_easy *data = conn->data;
-  struct HTTP *stream = data->req.protop;
+  struct HTTP *stream = data->req.p.http;
   headers.dest = buf;
   headers.destlen = buffersize;
   headers.nlen = 0;
 
-  if(process_ingress(conn, sockfd, qs)) {
+  if(process_ingress(data, sockfd, qs)) {
     infof(data, "h3_stream_recv returns on ingress\n");
     *curlcode = CURLE_RECV_ERROR;
     return -1;
@@ -525,7 +536,7 @@ static ssize_t h3_stream_recv(struct connectdata *conn,
 
     quiche_h3_event_free(ev);
   }
-  if(flush_egress(conn, sockfd, qs)) {
+  if(flush_egress(data, sockfd, qs)) {
     *curlcode = CURLE_SEND_ERROR;
     return -1;
   }
@@ -539,19 +550,20 @@ static ssize_t h3_stream_recv(struct connectdata *conn,
   return recvd;
 }
 
-static ssize_t h3_stream_send(struct connectdata *conn,
+static ssize_t h3_stream_send(struct Curl_easy *data,
                               int sockindex,
                               const void *mem,
                               size_t len,
                               CURLcode *curlcode)
 {
   ssize_t sent;
+  struct connectdata *conn = data->conn;
   struct quicsocket *qs = conn->quic;
   curl_socket_t sockfd = conn->sock[sockindex];
-  struct HTTP *stream = conn->data->req.protop;
+  struct HTTP *stream = data->req.p.http;
 
   if(!stream->h3req) {
-    CURLcode result = http_request(conn, mem, len);
+    CURLcode result = http_request(data, mem, len);
     if(result) {
       *curlcode = CURLE_SEND_ERROR;
       return -1;
@@ -559,8 +571,7 @@ static ssize_t h3_stream_send(struct connectdata *conn,
     sent = len;
   }
   else {
-    H3BUGF(infof(conn->data, "Pass on %zd body bytes to quiche\n",
-                 len));
+    H3BUGF(infof(data, "Pass on %zd body bytes to quiche\n", len));
     sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,
                                (uint8_t *)mem, len, FALSE);
     if(sent < 0) {
@@ -569,7 +580,7 @@ static ssize_t h3_stream_send(struct connectdata *conn,
     }
   }
 
-  if(flush_egress(conn, sockfd, qs)) {
+  if(flush_egress(data, sockfd, qs)) {
     *curlcode = CURLE_SEND_ERROR;
     return -1;
   }
@@ -591,12 +602,13 @@ int Curl_quic_ver(char *p, size_t len)
    field list. */
 #define AUTHORITY_DST_IDX 3
 
-static CURLcode http_request(struct connectdata *conn, const void *mem,
+static CURLcode http_request(struct Curl_easy *data, const void *mem,
                              size_t len)
 {
   /*
    */
-  struct HTTP *stream = conn->data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct HTTP *stream = data->req.p.http;
   size_t nheader;
   size_t i;
   size_t authority_idx;
@@ -606,7 +618,6 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
   quiche_h3_header *nva = NULL;
   struct quicsocket *qs = conn->quic;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
   stream->h3req = TRUE; /* senf off! */
 
@@ -761,7 +772,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
 
     if(acc > MAX_ACC) {
       infof(data, "http_request: Warning: The cumulative length of all "
-            "headers exceeds %zu bytes and that could cause the "
+            "headers exceeds %d bytes and that could cause the "
             "stream to be rejected.\n", MAX_ACC);
     }
   }
@@ -819,14 +830,15 @@ fail:
 /*
  * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
  */
-CURLcode Curl_quic_done_sending(struct connectdata *conn)
+CURLcode Curl_quic_done_sending(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
+  DEBUGASSERT(conn);
   if(conn->handler == &Curl_handler_http3) {
     /* only for HTTP/3 transfers */
     ssize_t sent;
-    struct HTTP *stream = conn->data->req.protop;
+    struct HTTP *stream = data->req.p.http;
     struct quicsocket *qs = conn->quic;
-    fprintf(stderr, "!!! Curl_quic_done_sending\n");
     stream->upload_done = TRUE;
     sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,
                                NULL, 0, TRUE);
index c8d1837..d311e99 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -41,6 +41,7 @@ struct quicsocket {
   quiche_h3_conn *h3c;
   quiche_h3_config *h3config;
   uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
+  curl_socket_t sockfd;
   uint32_t version;
 };
 
index aae8e09..7c0cc6d 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index ecff0ed..eb8a893 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 8988e23..08896ab 100644 (file)
@@ -5,14 +5,14 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2017 - 2020 Red Hat, Inc.
+ * Copyright (C) 2017 - 2021 Red Hat, Inc.
  *
  * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
  *          Robert Kolcun, Andreas Schneider
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
 #endif
 
 /* Local functions: */
-static CURLcode myssh_connect(struct connectdata *conn, bool *done);
-static CURLcode myssh_multi_statemach(struct connectdata *conn,
+static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
+static CURLcode myssh_multi_statemach(struct Curl_easy *data,
                                       bool *done);
-static CURLcode myssh_do_it(struct connectdata *conn, bool *done);
+static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
 
-static CURLcode scp_done(struct connectdata *conn,
+static CURLcode scp_done(struct Curl_easy *data,
                          CURLcode, bool premature);
-static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done);
-static CURLcode scp_disconnect(struct connectdata *conn,
+static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
                                bool dead_connection);
 
-static CURLcode sftp_done(struct connectdata *conn,
+static CURLcode sftp_done(struct Curl_easy *data,
                           CURLcode, bool premature);
-static CURLcode sftp_doing(struct connectdata *conn,
+static CURLcode sftp_doing(struct Curl_easy *data,
                            bool *dophase_done);
-static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead);
 static
-CURLcode sftp_perform(struct connectdata *conn,
+CURLcode sftp_perform(struct Curl_easy *data,
                       bool *connected,
                       bool *dophase_done);
 
-static void sftp_quote(struct connectdata *conn);
-static void sftp_quote_stat(struct connectdata *conn);
-static int myssh_getsock(struct connectdata *conn, curl_socket_t *sock);
-static int myssh_perform_getsock(const struct connectdata *conn,
-                                 curl_socket_t *sock);
+static void sftp_quote(struct Curl_easy *data);
+static void sftp_quote_stat(struct Curl_easy *data);
+static int myssh_getsock(struct Curl_easy *data,
+                         struct connectdata *conn, curl_socket_t *sock);
 
-static CURLcode myssh_setup_connection(struct connectdata *conn);
+static CURLcode myssh_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn);
 
 /*
  * SCP protocol handler.
@@ -152,12 +155,13 @@ const struct Curl_handler Curl_handler_scp = {
   myssh_getsock,                /* proto_getsock */
   myssh_getsock,                /* doing_getsock */
   ZERO_NULL,                    /* domore_getsock */
-  myssh_perform_getsock,        /* perform_getsock */
+  myssh_getsock,                /* perform_getsock */
   scp_disconnect,               /* disconnect */
   ZERO_NULL,                    /* readwrite */
   ZERO_NULL,                    /* connection_check */
   PORT_SSH,                     /* defport */
   CURLPROTO_SCP,                /* protocol */
+  CURLPROTO_SCP,                /* family */
   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY    /* flags */
 };
 
@@ -177,12 +181,13 @@ const struct Curl_handler Curl_handler_sftp = {
   myssh_getsock,                        /* proto_getsock */
   myssh_getsock,                        /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  myssh_perform_getsock,                /* perform_getsock */
+  myssh_getsock,                        /* perform_getsock */
   sftp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   PORT_SSH,                             /* defport */
   CURLPROTO_SFTP,                       /* protocol */
+  CURLPROTO_SFTP,                       /* family */
   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
   | PROTOPT_NOURLQUERY                  /* flags */
 };
@@ -221,12 +226,13 @@ static CURLcode sftp_error_to_CURLE(int err)
  * SSH State machine related code
  */
 /* This is the ONLY way to change SSH state! */
-static void mystate(struct connectdata *conn, sshstate nowstate
+static void mystate(struct Curl_easy *data, sshstate nowstate
 #ifdef DEBUGBUILD
                     , int lineno
 #endif
   )
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
@@ -295,7 +301,7 @@ static void mystate(struct connectdata *conn, sshstate nowstate
 
 
   if(sshc->state != nowstate) {
-    infof(conn->data, "SSH %p state change from %s to %s (line %d)\n",
+    infof(data, "SSH %p state change from %s to %s (line %d)\n",
           (void *) sshc, names[sshc->state], names[nowstate],
           lineno);
   }
@@ -314,10 +320,10 @@ static void mystate(struct connectdata *conn, sshstate nowstate
  *
  * Returns SSH_OK or SSH_ERROR.
  */
-static int myssh_is_known(struct connectdata *conn)
+static int myssh_is_known(struct Curl_easy *data)
 {
   int rc;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   ssh_key pubkey;
   size_t hlen;
@@ -527,10 +533,10 @@ static int myssh_is_known(struct connectdata *conn)
 
 cleanup:
   if(found_base64) {
-    free(found_base64);
+    (free)(found_base64);
   }
   if(known_base64) {
-    free(known_base64);
+    (free)(known_base64);
   }
   if(hash)
     ssh_clean_pubkey_hash(&hash);
@@ -544,14 +550,14 @@ cleanup:
 }
 
 #define MOVE_TO_ERROR_STATE(_r) { \
-  state(conn, SSH_SESSION_DISCONNECT); \
+  state(data, SSH_SESSION_DISCONNECT); \
   sshc->actualcode = _r; \
   rc = SSH_ERROR; \
   break; \
 }
 
 #define MOVE_TO_SFTP_CLOSE_STATE() { \
-  state(conn, SSH_SFTP_CLOSE); \
+  state(data, SSH_SFTP_CLOSE); \
   sshc->actualcode = sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
   rc = SSH_ERROR; \
   break; \
@@ -560,7 +566,7 @@ cleanup:
 #define MOVE_TO_LAST_AUTH \
   if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
     rc = SSH_OK; \
-    state(conn, SSH_AUTH_PASS_INIT); \
+    state(data, SSH_AUTH_PASS_INIT); \
     break; \
   } \
   else { \
@@ -570,7 +576,7 @@ cleanup:
 #define MOVE_TO_TERTIARY_AUTH \
   if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
     rc = SSH_OK; \
-    state(conn, SSH_AUTH_KEY_INIT); \
+    state(data, SSH_AUTH_KEY_INIT); \
     break; \
   } \
   else { \
@@ -580,7 +586,7 @@ cleanup:
 #define MOVE_TO_SECONDARY_AUTH \
   if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
     rc = SSH_OK; \
-    state(conn, SSH_AUTH_GSSAPI); \
+    state(data, SSH_AUTH_GSSAPI); \
     break; \
   } \
   else { \
@@ -658,11 +664,11 @@ restart:
  * to will be set to TRUE if the libssh function returns SSH_AGAIN
  * meaning it wants to be called again when the socket is ready
  */
-static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
+static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SSHPROTO *protop = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct SSHPROTO *protop = data->req.p.ssh;
   struct ssh_conn *sshc = &conn->proto.sshc;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   int rc = SSH_NO_ERROR, err;
@@ -687,7 +693,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
          non-blocking */
       ssh_set_blocking(sshc->ssh_session, 0);
 
-      state(conn, SSH_S_STARTUP);
+      state(data, SSH_S_STARTUP);
       /* FALLTHROUGH */
 
     case SSH_S_STARTUP:
@@ -700,17 +706,17 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
       }
 
-      state(conn, SSH_HOSTKEY);
+      state(data, SSH_HOSTKEY);
 
       /* FALLTHROUGH */
     case SSH_HOSTKEY:
 
-      rc = myssh_is_known(conn);
+      rc = myssh_is_known(data);
       if(rc != SSH_OK) {
         MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
       }
 
-      state(conn, SSH_AUTHLIST);
+      state(data, SSH_AUTHLIST);
       /* FALLTHROUGH */
     case SSH_AUTHLIST:{
         sshc->authed = FALSE;
@@ -724,7 +730,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         if(rc == SSH_AUTH_SUCCESS) {
           sshc->authed = TRUE;
           infof(data, "Authenticated with none\n");
-          state(conn, SSH_AUTH_DONE);
+          state(data, SSH_AUTH_DONE);
           break;
         }
         else if(rc == SSH_AUTH_ERROR) {
@@ -733,17 +739,17 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
         sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
         if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
-          state(conn, SSH_AUTH_PKEY_INIT);
+          state(data, SSH_AUTH_PKEY_INIT);
           infof(data, "Authentication using SSH public key file\n");
         }
         else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
-          state(conn, SSH_AUTH_GSSAPI);
+          state(data, SSH_AUTH_GSSAPI);
         }
         else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
-          state(conn, SSH_AUTH_KEY_INIT);
+          state(data, SSH_AUTH_KEY_INIT);
         }
         else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
-          state(conn, SSH_AUTH_PASS_INIT);
+          state(data, SSH_AUTH_PASS_INIT);
         }
         else {                  /* unsupported authentication method */
           MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
@@ -783,7 +789,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
           break;
         }
 
-        state(conn, SSH_AUTH_PKEY);
+        state(data, SSH_AUTH_PKEY);
         break;
 
       }
@@ -798,7 +804,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
           rc = SSH_OK;
           sshc->authed = TRUE;
           infof(data, "Completed public key authentication\n");
-          state(conn, SSH_AUTH_DONE);
+          state(data, SSH_AUTH_DONE);
           break;
         }
 
@@ -815,7 +821,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       if(rc == SSH_AUTH_SUCCESS) {
         sshc->authed = TRUE;
         infof(data, "Completed public key authentication\n");
-        state(conn, SSH_AUTH_DONE);
+        state(data, SSH_AUTH_DONE);
         break;
       }
       else {
@@ -839,7 +845,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         rc = SSH_OK;
         sshc->authed = TRUE;
         infof(data, "Completed gssapi authentication\n");
-        state(conn, SSH_AUTH_DONE);
+        state(data, SSH_AUTH_DONE);
         break;
       }
 
@@ -848,7 +854,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
     case SSH_AUTH_KEY_INIT:
       if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
-        state(conn, SSH_AUTH_KEY);
+        state(data, SSH_AUTH_KEY);
       }
       else {
         MOVE_TO_LAST_AUTH;
@@ -866,7 +872,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         sshc->authed = TRUE;
         infof(data, "completed keyboard interactive authentication\n");
       }
-      state(conn, SSH_AUTH_DONE);
+      state(data, SSH_AUTH_DONE);
       break;
 
     case SSH_AUTH_PASS_INIT:
@@ -874,7 +880,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         /* Host key authentication is intentionally not implemented */
         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
       }
-      state(conn, SSH_AUTH_PASS);
+      state(data, SSH_AUTH_PASS);
       /* FALLTHROUGH */
 
     case SSH_AUTH_PASS:
@@ -887,7 +893,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       if(rc == SSH_AUTH_SUCCESS) {
         sshc->authed = TRUE;
         infof(data, "Completed password authentication\n");
-        state(conn, SSH_AUTH_DONE);
+        state(data, SSH_AUTH_DONE);
       }
       else {
         MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
@@ -906,17 +912,17 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
        */
       infof(data, "Authentication complete\n");
 
-      Curl_pgrsTime(conn->data, TIMER_APPCONNECT);      /* SSH is connected */
+      Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
 
       conn->sockfd = sock;
       conn->writesockfd = CURL_SOCKET_BAD;
 
       if(conn->handler->protocol == CURLPROTO_SFTP) {
-        state(conn, SSH_SFTP_INIT);
+        state(data, SSH_SFTP_INIT);
         break;
       }
       infof(data, "SSH CONNECT phase done\n");
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     case SSH_SFTP_INIT:
@@ -938,7 +944,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(rc));
         break;
       }
-      state(conn, SSH_SFTP_REALPATH);
+      state(data, SSH_SFTP_REALPATH);
       /* FALLTHROUGH */
     case SSH_SFTP_REALPATH:
       /*
@@ -948,32 +954,31 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       if(sshc->homedir == NULL) {
         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
       }
-      conn->data->state.most_recent_ftp_entrypath = sshc->homedir;
+      data->state.most_recent_ftp_entrypath = sshc->homedir;
 
       /* This is the last step in the SFTP connect phase. Do note that while
          we get the homedir here, we get the "workingpath" in the DO action
          since the homedir will remain the same between request but the
          working path will not. */
       DEBUGF(infof(data, "SSH CONNECT phase done\n"));
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     case SSH_SFTP_QUOTE_INIT:
-
-      result = Curl_getworkingpath(conn, sshc->homedir, &protop->path);
+      result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
       if(result) {
         sshc->actualcode = result;
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
 
       if(data->set.quote) {
         infof(data, "Sending quote commands\n");
         sshc->quote_item = data->set.quote;
-        state(conn, SSH_SFTP_QUOTE);
+        state(data, SSH_SFTP_QUOTE);
       }
       else {
-        state(conn, SSH_SFTP_GETINFO);
+        state(data, SSH_SFTP_GETINFO);
       }
       break;
 
@@ -981,16 +986,16 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       if(data->set.postquote) {
         infof(data, "Sending quote commands\n");
         sshc->quote_item = data->set.postquote;
-        state(conn, SSH_SFTP_QUOTE);
+        state(data, SSH_SFTP_QUOTE);
       }
       else {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
       }
       break;
 
     case SSH_SFTP_QUOTE:
       /* Send any quote commands */
-      sftp_quote(conn);
+      sftp_quote(data);
       break;
 
     case SSH_SFTP_NEXT_QUOTE:
@@ -1000,21 +1005,21 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       sshc->quote_item = sshc->quote_item->next;
 
       if(sshc->quote_item) {
-        state(conn, SSH_SFTP_QUOTE);
+        state(data, SSH_SFTP_QUOTE);
       }
       else {
         if(sshc->nextstate != SSH_NO_STATE) {
-          state(conn, sshc->nextstate);
+          state(data, sshc->nextstate);
           sshc->nextstate = SSH_NO_STATE;
         }
         else {
-          state(conn, SSH_SFTP_GETINFO);
+          state(data, SSH_SFTP_GETINFO);
         }
       }
       break;
 
     case SSH_SFTP_QUOTE_STAT:
-      sftp_quote_stat(conn);
+      sftp_quote_stat(data);
       break;
 
     case SSH_SFTP_QUOTE_SETSTAT:
@@ -1025,7 +1030,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path2);
         failf(data, "Attempt to set SFTP stats failed: %s",
               ssh_get_error(sshc->ssh_session));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         /* sshc->actualcode = sftp_error_to_CURLE(err);
@@ -1033,7 +1038,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
          * the error the libssh2 backend is returning */
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_SYMLINK:
@@ -1044,12 +1049,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path2);
         failf(data, "symlink command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_MKDIR:
@@ -1059,12 +1064,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path1);
         failf(data, "mkdir command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_RENAME:
@@ -1075,12 +1080,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path2);
         failf(data, "rename command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_RMDIR:
@@ -1089,12 +1094,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path1);
         failf(data, "rmdir command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_UNLINK:
@@ -1103,12 +1108,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path1);
         failf(data, "rm command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_STATVFS:
@@ -1120,7 +1125,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path1);
         failf(data, "statvfs command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
@@ -1143,29 +1148,29 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
         if(!tmp) {
           result = CURLE_OUT_OF_MEMORY;
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           break;
         }
 
-        result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
         free(tmp);
         if(result) {
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = result;
         }
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
     }
 
     case SSH_SFTP_GETINFO:
       if(data->set.get_filetime) {
-        state(conn, SSH_SFTP_FILETIME);
+        state(data, SSH_SFTP_FILETIME);
       }
       else {
-        state(conn, SSH_SFTP_TRANS_INIT);
+        state(data, SSH_SFTP_TRANS_INIT);
       }
       break;
 
@@ -1179,18 +1184,18 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         sftp_attributes_free(attrs);
       }
 
-      state(conn, SSH_SFTP_TRANS_INIT);
+      state(data, SSH_SFTP_TRANS_INIT);
       break;
     }
 
     case SSH_SFTP_TRANS_INIT:
       if(data->set.upload)
-        state(conn, SSH_SFTP_UPLOAD_INIT);
+        state(data, SSH_SFTP_UPLOAD_INIT);
       else {
         if(protop->path[strlen(protop->path)-1] == '/')
-          state(conn, SSH_SFTP_READDIR_INIT);
+          state(data, SSH_SFTP_READDIR_INIT);
         else
-          state(conn, SSH_SFTP_DOWNLOAD_INIT);
+          state(data, SSH_SFTP_DOWNLOAD_INIT);
       }
       break;
 
@@ -1226,7 +1231,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         /* If we have restart position then open for append */
         flags = O_WRONLY|O_APPEND;
       else
-        /* Clear file before writing (normal behaviour) */
+        /* Clear file before writing (normal behavior) */
         flags = O_WRONLY|O_CREAT|O_TRUNC;
 
       if(sshc->sftp_file)
@@ -1244,7 +1249,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
                /* try to create the path remotely */
                rc = 0;
                sshc->secondCreateDirs = 1;
-               state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+               state(data, SSH_SFTP_CREATE_DIRS_INIT);
                break;
         }
         else {
@@ -1327,17 +1332,17 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
          timeout here */
       Curl_expire(data, 0, EXPIRE_RUN_NOW);
 
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
     }
 
     case SSH_SFTP_CREATE_DIRS_INIT:
       if(strlen(protop->path) > 1) {
         sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
-        state(conn, SSH_SFTP_CREATE_DIRS);
+        state(data, SSH_SFTP_CREATE_DIRS);
       }
       else {
-        state(conn, SSH_SFTP_UPLOAD_INIT);
+        state(data, SSH_SFTP_UPLOAD_INIT);
       }
       break;
 
@@ -1347,10 +1352,10 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         *sshc->slash_pos = 0;
 
         infof(data, "Creating directory '%s'\n", protop->path);
-        state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
+        state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
         break;
       }
-      state(conn, SSH_SFTP_UPLOAD_INIT);
+      state(data, SSH_SFTP_UPLOAD_INIT);
       break;
 
     case SSH_SFTP_CREATE_DIRS_MKDIR:
@@ -1373,13 +1378,13 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         }
         rc = 0; /* clear rc and continue */
       }
-      state(conn, SSH_SFTP_CREATE_DIRS);
+      state(data, SSH_SFTP_CREATE_DIRS);
       break;
 
     case SSH_SFTP_READDIR_INIT:
       Curl_pgrsSetDownloadSize(data, -1);
       if(data->set.opt_no_body) {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
 
@@ -1394,7 +1399,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
               ssh_get_error(sshc->ssh_session));
         MOVE_TO_SFTP_CLOSE_STATE();
       }
-      state(conn, SSH_SFTP_READDIR);
+      state(data, SSH_SFTP_READDIR);
       break;
 
     case SSH_SFTP_READDIR:
@@ -1413,16 +1418,16 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
           tmpLine = aprintf("%s\n", sshc->readdir_filename);
           if(tmpLine == NULL) {
-            state(conn, SSH_SFTP_CLOSE);
+            state(data, SSH_SFTP_CLOSE);
             sshc->actualcode = CURLE_OUT_OF_MEMORY;
             break;
           }
-          result = Curl_client_write(conn, CLIENTWRITE_BODY,
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
                                      tmpLine, sshc->readdir_len + 1);
           free(tmpLine);
 
           if(result) {
-            state(conn, SSH_STOP);
+            state(data, SSH_STOP);
             break;
           }
           /* since this counts what we send to the client, we include the
@@ -1430,18 +1435,15 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
           data->req.bytecount += sshc->readdir_len + 1;
 
           /* output debug output if that is requested */
-          if(data->set.verbose) {
-            Curl_debug(data, CURLINFO_DATA_OUT,
-                       (char *)sshc->readdir_filename,
-                       sshc->readdir_len);
-          }
+          Curl_debug(data, CURLINFO_DATA_OUT, (char *)sshc->readdir_filename,
+                     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(conn, SSH_SFTP_CLOSE);
+            state(data, SSH_SFTP_CLOSE);
             sshc->actualcode = CURLE_OUT_OF_MEMORY;
             break;
           }
@@ -1453,7 +1455,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
               S_IFLNK)) {
             sshc->readdir_linkPath = malloc(PATH_MAX + 1);
             if(sshc->readdir_linkPath == NULL) {
-              state(conn, SSH_SFTP_CLOSE);
+              state(data, SSH_SFTP_CLOSE);
               sshc->actualcode = CURLE_OUT_OF_MEMORY;
               break;
             }
@@ -1461,15 +1463,15 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
             msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path,
                       sshc->readdir_filename);
 
-            state(conn, SSH_SFTP_READDIR_LINK);
+            state(data, SSH_SFTP_READDIR_LINK);
             break;
           }
-          state(conn, SSH_SFTP_READDIR_BOTTOM);
+          state(data, SSH_SFTP_READDIR_BOTTOM);
           break;
         }
       }
       else if(sftp_dir_eof(sshc->sftp_dir)) {
-        state(conn, SSH_SFTP_READDIR_DONE);
+        state(data, SSH_SFTP_READDIR_DONE);
         break;
       }
       else {
@@ -1516,7 +1518,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
                                           sshc->readdir_totalLen);
       if(!new_readdir_line) {
         sshc->readdir_line = NULL;
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_OUT_OF_MEMORY;
         break;
       }
@@ -1534,24 +1536,21 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       sshc->readdir_filename = NULL;
       sshc->readdir_longentry = NULL;
 
-      state(conn, SSH_SFTP_READDIR_BOTTOM);
+      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(conn, CLIENTWRITE_BODY,
+      result = Curl_client_write(data, CLIENTWRITE_BODY,
                                  sshc->readdir_line,
                                  sshc->readdir_currLen);
 
       if(!result) {
-
         /* output debug output if that is requested */
-        if(data->set.verbose) {
-          Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
-                     sshc->readdir_currLen);
-        }
+        Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
+                   sshc->readdir_currLen);
         data->req.bytecount += sshc->readdir_currLen;
       }
       Curl_safefree(sshc->readdir_line);
@@ -1559,10 +1558,10 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       sshc->readdir_tmp = NULL;
 
       if(result) {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
       }
       else
-        state(conn, SSH_SFTP_READDIR);
+        state(data, SSH_SFTP_READDIR);
       break;
 
     case SSH_SFTP_READDIR_DONE:
@@ -1571,7 +1570,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
       /* no data to transfer */
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     case SSH_SFTP_DOWNLOAD_INIT:
@@ -1590,7 +1589,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         MOVE_TO_SFTP_CLOSE_STATE();
       }
 
-      state(conn, SSH_SFTP_DOWNLOAD_STAT);
+      state(data, SSH_SFTP_DOWNLOAD_STAT);
       break;
 
     case SSH_SFTP_DOWNLOAD_STAT:
@@ -1622,14 +1621,14 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
           failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
           return CURLE_BAD_DOWNLOAD_RESUME;
         }
-        if(conn->data->state.use_range) {
+        if(data->state.use_range) {
           curl_off_t from, to;
           char *ptr;
           char *ptr2;
           CURLofft to_t;
           CURLofft from_t;
 
-          from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from);
+          from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
           if(from_t == CURL_OFFT_FLOW) {
             return CURLE_RANGE_ERROR;
           }
@@ -1712,7 +1711,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       /* no data to transfer */
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
       infof(data, "File already completely downloaded\n");
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
     }
     Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
@@ -1728,12 +1727,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
     if(result) {
       /* this should never occur; the close state should be entered
          at the time the error occurs */
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->actualcode = result;
     }
     else {
       sshc->sftp_recv_state = 0;
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
     }
     break;
 
@@ -1751,11 +1750,11 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
          SSH_SFTP_CLOSE to pass the correct result back  */
       if(sshc->nextstate != SSH_NO_STATE &&
          sshc->nextstate != SSH_SFTP_CLOSE) {
-        state(conn, sshc->nextstate);
+        state(data, sshc->nextstate);
         sshc->nextstate = SSH_SFTP_CLOSE;
       }
       else {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         result = sshc->actualcode;
       }
       break;
@@ -1776,17 +1775,16 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       }
 
       SSH_STRING_FREE_CHAR(sshc->homedir);
-      conn->data->state.most_recent_ftp_entrypath = NULL;
+      data->state.most_recent_ftp_entrypath = NULL;
 
-      state(conn, SSH_SESSION_DISCONNECT);
+      state(data, SSH_SESSION_DISCONNECT);
       break;
 
-
     case SSH_SCP_TRANS_INIT:
-      result = Curl_getworkingpath(conn, sshc->homedir, &protop->path);
+      result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
       if(result) {
         sshc->actualcode = result;
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
 
@@ -1802,17 +1800,17 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
         sshc->scp_session =
           ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
-        state(conn, SSH_SCP_UPLOAD_INIT);
+        state(data, SSH_SCP_UPLOAD_INIT);
       }
       else {
         sshc->scp_session =
           ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
-        state(conn, SSH_SCP_DOWNLOAD_INIT);
+        state(data, SSH_SCP_DOWNLOAD_INIT);
       }
 
       if(!sshc->scp_session) {
         err_msg = ssh_get_error(sshc->ssh_session);
-        failf(conn->data, "%s", err_msg);
+        failf(data, "%s", err_msg);
         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
       }
 
@@ -1823,7 +1821,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       rc = ssh_scp_init(sshc->scp_session);
       if(rc != SSH_OK) {
         err_msg = ssh_get_error(sshc->ssh_session);
-        failf(conn->data, "%s", err_msg);
+        failf(data, "%s", err_msg);
         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
       }
 
@@ -1832,7 +1830,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
                              (int)data->set.new_file_perms);
       if(rc != SSH_OK) {
         err_msg = ssh_get_error(sshc->ssh_session);
-        failf(conn->data, "%s", err_msg);
+        failf(data, "%s", err_msg);
         MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
       }
 
@@ -1851,7 +1849,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
          with both accordingly */
       conn->cselect_bits = CURL_CSELECT_OUT;
 
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
 
       break;
 
@@ -1860,10 +1858,10 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       rc = ssh_scp_init(sshc->scp_session);
       if(rc != SSH_OK) {
         err_msg = ssh_get_error(sshc->ssh_session);
-        failf(conn->data, "%s", err_msg);
+        failf(data, "%s", err_msg);
         MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
       }
-      state(conn, SSH_SCP_DOWNLOAD);
+      state(data, SSH_SCP_DOWNLOAD);
       /* FALLTHROUGH */
 
     case SSH_SCP_DOWNLOAD:{
@@ -1872,7 +1870,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         rc = ssh_scp_pull_request(sshc->scp_session);
         if(rc != SSH_SCP_REQUEST_NEWFILE) {
           err_msg = ssh_get_error(sshc->ssh_session);
-          failf(conn->data, "%s", err_msg);
+          failf(data, "%s", err_msg);
           MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
           break;
         }
@@ -1890,14 +1888,14 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
            with both accordingly */
         conn->cselect_bits = CURL_CSELECT_IN;
 
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
     case SSH_SCP_DONE:
       if(data->set.upload)
-        state(conn, SSH_SCP_SEND_EOF);
+        state(data, SSH_SCP_SEND_EOF);
       else
-        state(conn, SSH_SCP_CHANNEL_FREE);
+        state(data, SSH_SCP_CHANNEL_FREE);
       break;
 
     case SSH_SCP_SEND_EOF:
@@ -1915,7 +1913,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
         }
       }
 
-      state(conn, SSH_SCP_CHANNEL_FREE);
+      state(data, SSH_SCP_CHANNEL_FREE);
       break;
 
     case SSH_SCP_CHANNEL_FREE:
@@ -1927,7 +1925,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
       ssh_set_blocking(sshc->ssh_session, 0);
 
-      state(conn, SSH_SESSION_DISCONNECT);
+      state(data, SSH_SESSION_DISCONNECT);
       /* FALLTHROUGH */
 
     case SSH_SESSION_DISCONNECT:
@@ -1942,9 +1940,9 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       ssh_disconnect(sshc->ssh_session);
 
       SSH_STRING_FREE_CHAR(sshc->homedir);
-      conn->data->state.most_recent_ftp_entrypath = NULL;
+      data->state.most_recent_ftp_entrypath = NULL;
 
-      state(conn, SSH_SESSION_FREE);
+      state(data, SSH_SESSION_FREE);
       /* FALLTHROUGH */
     case SSH_SESSION_FREE:
       if(sshc->ssh_session) {
@@ -1992,7 +1990,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
       connclose(conn, "SSH session free");
       sshc->state = SSH_SESSION_FREE;   /* current */
       sshc->nextstate = SSH_NO_STATE;
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     case SSH_QUIT:
@@ -2000,7 +1998,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
     default:
       /* internal error */
       sshc->nextstate = SSH_NO_STATE;
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     }
@@ -2019,10 +2017,12 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
 
 /* called by the multi interface to figure out what socket(s) to wait for and
    for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
-static int myssh_perform_getsock(const struct connectdata *conn,
-                                 curl_socket_t *sock)
+static int myssh_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         curl_socket_t *sock)
 {
   int bitmap = GETSOCK_BLANK;
+  (void)data;
   sock[0] = conn->sock[FIRSTSOCKET];
 
   if(conn->waitfor & KEEP_RECV)
@@ -2034,16 +2034,6 @@ static int myssh_perform_getsock(const struct connectdata *conn,
   return bitmap;
 }
 
-/* Generic function called by the multi interface to figure out what socket(s)
-   to wait for and for what actions during the DOING and PROTOCONNECT states*/
-static int myssh_getsock(struct connectdata *conn,
-                         curl_socket_t *sock)
-{
-  /* if we know the direction we can use the generic *_getsock() function even
-     for the protocol_connect and doing states */
-  return myssh_perform_getsock(conn, sock);
-}
-
 static void myssh_block2waitfor(struct connectdata *conn, bool block)
 {
   struct ssh_conn *sshc = &conn->proto.sshc;
@@ -2065,13 +2055,14 @@ static void myssh_block2waitfor(struct connectdata *conn, bool block)
 }
 
 /* called repeatedly until done from multi.c */
-static CURLcode myssh_multi_statemach(struct connectdata *conn,
+static CURLcode myssh_multi_statemach(struct Curl_easy *data,
                                       bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   bool block;    /* we store the status and use that to provide a ssh_getsock()
                     implementation */
-  CURLcode result = myssh_statemach_act(conn, &block);
+  CURLcode result = myssh_statemach_act(data, &block);
 
   *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
   myssh_block2waitfor(conn, block);
@@ -2079,24 +2070,24 @@ static CURLcode myssh_multi_statemach(struct connectdata *conn,
   return result;
 }
 
-static CURLcode myssh_block_statemach(struct connectdata *conn,
+static CURLcode myssh_block_statemach(struct Curl_easy *data,
                                       bool disconnect)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
   while((sshc->state != SSH_STOP) && !result) {
     bool block;
     timediff_t left = 1000;
     struct curltime now = Curl_now();
 
-    result = myssh_statemach_act(conn, &block);
+    result = myssh_statemach_act(data, &block);
     if(result)
       break;
 
     if(!disconnect) {
-      if(Curl_pgrsUpdate(conn))
+      if(Curl_pgrsUpdate(data))
         return CURLE_ABORTED_BY_CALLBACK;
 
       result = Curl_speedcheck(data, now);
@@ -2125,11 +2116,13 @@ static CURLcode myssh_block_statemach(struct connectdata *conn,
 /*
  * SSH setup connection
  */
-static CURLcode myssh_setup_connection(struct connectdata *conn)
+static CURLcode myssh_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn)
 {
   struct SSHPROTO *ssh;
+  (void)conn;
 
-  conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
+  data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
   if(!ssh)
     return CURLE_OUT_OF_MEMORY;
 
@@ -2143,17 +2136,17 @@ static Curl_send scp_send, sftp_send;
  * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
  * do protocol-specific actions at connect-time.
  */
-static CURLcode myssh_connect(struct connectdata *conn, bool *done)
+static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
 {
   struct ssh_conn *ssh;
   CURLcode result;
+  struct connectdata *conn = data->conn;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data = conn->data;
   int rc;
 
   /* initialize per-handle data if not already */
-  if(!data->req.protop)
-    myssh_setup_connection(conn);
+  if(!data->req.p.ssh)
+    myssh_setup_connection(data, conn);
 
   /* We default to persistent connections. We set this already in this connect
      function to make the re-use checks properly be able to check this bit. */
@@ -2246,22 +2239,22 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
   /* we do not verify here, we do it at the state machine,
    * after connection */
 
-  state(conn, SSH_INIT);
+  state(data, SSH_INIT);
 
-  result = myssh_multi_statemach(conn, done);
+  result = myssh_multi_statemach(data, done);
 
   return result;
 }
 
 /* called from multi.c while DOing */
-static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done)
+static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
 {
   CURLcode result;
 
-  result = myssh_multi_statemach(conn, dophase_done);
+  result = myssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
   return result;
 }
@@ -2276,34 +2269,35 @@ static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done)
  */
 
 static
-CURLcode scp_perform(struct connectdata *conn,
+CURLcode scp_perform(struct Curl_easy *data,
                      bool *connected, bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
   *dophase_done = FALSE;        /* not done yet */
 
   /* start the first command in the DO phase */
-  state(conn, SSH_SCP_TRANS_INIT);
+  state(data, SSH_SCP_TRANS_INIT);
 
-  result = myssh_multi_statemach(conn, dophase_done);
+  result = myssh_multi_statemach(data, dophase_done);
 
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
 }
 
-static CURLcode myssh_do_it(struct connectdata *conn, bool *done)
+static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
   bool connected = 0;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
   *done = FALSE;                /* default to false */
@@ -2320,9 +2314,9 @@ static CURLcode myssh_do_it(struct connectdata *conn, bool *done)
   Curl_pgrsSetDownloadSize(data, -1);
 
   if(conn->handler->protocol & CURLPROTO_SCP)
-    result = scp_perform(conn, &connected, done);
+    result = scp_perform(data, &connected, done);
   else
-    result = sftp_perform(conn, &connected, done);
+    result = sftp_perform(data, &connected, done);
 
   return result;
 }
@@ -2330,7 +2324,8 @@ static CURLcode myssh_do_it(struct connectdata *conn, bool *done)
 /* BLOCKING, but the function is using the state machine so the only reason
    this is still blocking is that the multi interface code has no support for
    disconnecting operations that takes a while */
-static CURLcode scp_disconnect(struct connectdata *conn,
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
                                bool dead_connection)
 {
   CURLcode result = CURLE_OK;
@@ -2340,9 +2335,9 @@ static CURLcode scp_disconnect(struct connectdata *conn,
   if(ssh->ssh_session) {
     /* only if there's a session still around to use! */
 
-    state(conn, SSH_SESSION_DISCONNECT);
+    state(data, SSH_SESSION_DISCONNECT);
 
-    result = myssh_block_statemach(conn, TRUE);
+    result = myssh_block_statemach(data, TRUE);
   }
 
   return result;
@@ -2350,44 +2345,45 @@ static CURLcode scp_disconnect(struct connectdata *conn,
 
 /* generic done function for both SCP and SFTP called from their specific
    done functions */
-static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
+static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
 {
   CURLcode result = CURLE_OK;
-  struct SSHPROTO *protop = conn->data->req.protop;
+  struct SSHPROTO *protop = data->req.p.ssh;
 
   if(!status) {
     /* run the state-machine */
-    result = myssh_block_statemach(conn, FALSE);
+    result = myssh_block_statemach(data, FALSE);
   }
   else
     result = status;
 
   if(protop)
     Curl_safefree(protop->path);
-  if(Curl_pgrsDone(conn))
+  if(Curl_pgrsDone(data))
     return CURLE_ABORTED_BY_CALLBACK;
 
-  conn->data->req.keepon = 0;   /* clear all bits */
+  data->req.keepon = 0;   /* clear all bits */
   return result;
 }
 
 
-static CURLcode scp_done(struct connectdata *conn, CURLcode status,
+static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
                          bool premature)
 {
   (void) premature;             /* not used */
 
   if(!status)
-    state(conn, SSH_SCP_DONE);
+    state(data, SSH_SCP_DONE);
 
-  return myssh_done(conn, status);
+  return myssh_done(data, status);
 
 }
 
-static ssize_t scp_send(struct connectdata *conn, int sockindex,
+static ssize_t scp_send(struct Curl_easy *data, int sockindex,
                         const void *mem, size_t len, CURLcode *err)
 {
   int rc;
+  struct connectdata *conn = data->conn;
   (void) sockindex; /* we only support SCP on the fixed known primary socket */
   (void) err;
 
@@ -2413,10 +2409,11 @@ static ssize_t scp_send(struct connectdata *conn, int sockindex,
   return len;
 }
 
-static ssize_t scp_recv(struct connectdata *conn, int sockindex,
+static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
                         char *mem, size_t len, CURLcode *err)
 {
   ssize_t nread;
+  struct connectdata *conn = data->conn;
   (void) err;
   (void) sockindex; /* we only support SCP on the fixed known primary socket */
 
@@ -2452,38 +2449,39 @@ static ssize_t scp_recv(struct connectdata *conn, int sockindex,
  */
 
 static
-CURLcode sftp_perform(struct connectdata *conn,
+CURLcode sftp_perform(struct Curl_easy *data,
                       bool *connected,
                       bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
   *dophase_done = FALSE; /* not done yet */
 
   /* start the first command in the DO phase */
-  state(conn, SSH_SFTP_QUOTE_INIT);
+  state(data, SSH_SFTP_QUOTE_INIT);
 
   /* run the state-machine */
-  result = myssh_multi_statemach(conn, dophase_done);
+  result = myssh_multi_statemach(data, dophase_done);
 
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
 }
 
 /* called from multi.c while DOing */
-static CURLcode sftp_doing(struct connectdata *conn,
+static CURLcode sftp_doing(struct Curl_easy *data,
                            bool *dophase_done)
 {
-  CURLcode result = myssh_multi_statemach(conn, dophase_done);
+  CURLcode result = myssh_multi_statemach(data, dophase_done);
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
   return result;
 }
@@ -2491,46 +2489,50 @@ static CURLcode sftp_doing(struct connectdata *conn,
 /* BLOCKING, but the function is using the state machine so the only reason
    this is still blocking is that the multi interface code has no support for
    disconnecting operations that takes a while */
-static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
+                                bool dead_connection)
 {
   CURLcode result = CURLE_OK;
   (void) dead_connection;
 
-  DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
 
   if(conn->proto.sshc.ssh_session) {
     /* only if there's a session still around to use! */
-    state(conn, SSH_SFTP_SHUTDOWN);
-    result = myssh_block_statemach(conn, TRUE);
+    state(data, SSH_SFTP_SHUTDOWN);
+    result = myssh_block_statemach(data, TRUE);
   }
 
-  DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
 
   return result;
 
 }
 
-static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
-                               bool premature)
+static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
+                          bool premature)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
   if(!status) {
     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
        errors that could happen due to open file handles during POSTQUOTE
        operation */
-    if(!premature && conn->data->set.postquote && !conn->bits.retry)
+    if(!premature && data->set.postquote && !conn->bits.retry)
       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
-    state(conn, SSH_SFTP_CLOSE);
+    state(data, SSH_SFTP_CLOSE);
   }
-  return myssh_done(conn, status);
+  return myssh_done(data, status);
 }
 
 /* return number of sent bytes */
-static ssize_t sftp_send(struct connectdata *conn, int sockindex,
+static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
                          const void *mem, size_t len, CURLcode *err)
 {
   ssize_t nwrite;
+  struct connectdata *conn = data->conn;
   (void)sockindex;
 
   nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
@@ -2556,10 +2558,11 @@ static ssize_t sftp_send(struct connectdata *conn, int sockindex,
  * Return number of received (decrypted) bytes
  * or <0 on error
  */
-static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
+static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
                          char *mem, size_t len, CURLcode *err)
 {
   ssize_t nread;
+  struct connectdata *conn = data->conn;
   (void)sockindex;
 
   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
@@ -2567,8 +2570,8 @@ static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
   switch(conn->proto.sshc.sftp_recv_state) {
     case 0:
       conn->proto.sshc.sftp_file_index =
-            sftp_async_read_begin(conn->proto.sshc.sftp_file,
-                                  (uint32_t)len);
+        sftp_async_read_begin(conn->proto.sshc.sftp_file,
+                              (uint32_t)len);
       if(conn->proto.sshc.sftp_file_index < 0) {
         *err = CURLE_RECV_ERROR;
         return -1;
@@ -2602,11 +2605,11 @@ static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
   }
 }
 
-static void sftp_quote(struct connectdata *conn)
+static void sftp_quote(struct Curl_easy *data)
 {
   const char *cp;
-  struct Curl_easy *data = conn->data;
-  struct SSHPROTO *protop = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct SSHPROTO *protop = data->req.p.ssh;
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result;
 
@@ -2632,26 +2635,25 @@ static void sftp_quote(struct connectdata *conn)
                         protop->path);
     if(!tmp) {
       sshc->actualcode = CURLE_OUT_OF_MEMORY;
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       return;
     }
-    if(data->set.verbose) {
-      Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
-      Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
-    }
+    Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
+    Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
+
     /* this sends an FTP-like "header" to the header callback so that the
        current directory can be read very similar to how it is read when
        using ordinary FTP. */
-    result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
     free(tmp);
     if(result) {
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       sshc->actualcode = result;
     }
     else
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
     return;
   }
 
@@ -2662,7 +2664,7 @@ static void sftp_quote(struct connectdata *conn)
   cp = strchr(cmd, ' ');
   if(cp == NULL) {
     failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
-    state(conn, SSH_SFTP_CLOSE);
+    state(data, SSH_SFTP_CLOSE);
     sshc->nextstate = SSH_NO_STATE;
     sshc->actualcode = CURLE_QUOTE_ERROR;
     return;
@@ -2678,7 +2680,7 @@ static void sftp_quote(struct connectdata *conn)
       failf(data, "Out of memory");
     else
       failf(data, "Syntax error: Bad first parameter");
-    state(conn, SSH_SFTP_CLOSE);
+    state(data, SSH_SFTP_CLOSE);
     sshc->nextstate = SSH_NO_STATE;
     sshc->actualcode = result;
     return;
@@ -2692,7 +2694,9 @@ static void sftp_quote(struct connectdata *conn)
    */
   if(strncasecompare(cmd, "chgrp ", 6) ||
      strncasecompare(cmd, "chmod ", 6) ||
-     strncasecompare(cmd, "chown ", 6)) {
+     strncasecompare(cmd, "chown ", 6) ||
+     strncasecompare(cmd, "atime ", 6) ||
+     strncasecompare(cmd, "mtime ", 6)) {
     /* attribute change */
 
     /* sshc->quote_path1 contains the mode to set */
@@ -2702,16 +2706,16 @@ static void sftp_quote(struct connectdata *conn)
       if(result == CURLE_OUT_OF_MEMORY)
         failf(data, "Out of memory");
       else
-        failf(data, "Syntax error in chgrp/chmod/chown: "
+        failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
               "Bad second parameter");
       Curl_safefree(sshc->quote_path1);
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       sshc->actualcode = result;
       return;
     }
     sshc->quote_attrs = NULL;
-    state(conn, SSH_SFTP_QUOTE_STAT);
+    state(data, SSH_SFTP_QUOTE_STAT);
     return;
   }
   if(strncasecompare(cmd, "ln ", 3) ||
@@ -2726,17 +2730,17 @@ static void sftp_quote(struct connectdata *conn)
       else
         failf(data, "Syntax error in ln/symlink: Bad second parameter");
       Curl_safefree(sshc->quote_path1);
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       sshc->actualcode = result;
       return;
     }
-    state(conn, SSH_SFTP_QUOTE_SYMLINK);
+    state(data, SSH_SFTP_QUOTE_SYMLINK);
     return;
   }
   else if(strncasecompare(cmd, "mkdir ", 6)) {
     /* create dir */
-    state(conn, SSH_SFTP_QUOTE_MKDIR);
+    state(data, SSH_SFTP_QUOTE_MKDIR);
     return;
   }
   else if(strncasecompare(cmd, "rename ", 7)) {
@@ -2750,26 +2754,26 @@ static void sftp_quote(struct connectdata *conn)
       else
         failf(data, "Syntax error in rename: Bad second parameter");
       Curl_safefree(sshc->quote_path1);
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       sshc->actualcode = result;
       return;
     }
-    state(conn, SSH_SFTP_QUOTE_RENAME);
+    state(data, SSH_SFTP_QUOTE_RENAME);
     return;
   }
   else if(strncasecompare(cmd, "rmdir ", 6)) {
     /* delete dir */
-    state(conn, SSH_SFTP_QUOTE_RMDIR);
+    state(data, SSH_SFTP_QUOTE_RMDIR);
     return;
   }
   else if(strncasecompare(cmd, "rm ", 3)) {
-    state(conn, SSH_SFTP_QUOTE_UNLINK);
+    state(data, SSH_SFTP_QUOTE_UNLINK);
     return;
   }
 #ifdef HAS_STATVFS_SUPPORT
   else if(strncasecompare(cmd, "statvfs ", 8)) {
-    state(conn, SSH_SFTP_QUOTE_STATVFS);
+    state(data, SSH_SFTP_QUOTE_STATVFS);
     return;
   }
 #endif
@@ -2777,14 +2781,14 @@ static void sftp_quote(struct connectdata *conn)
   failf(data, "Unknown SFTP command");
   Curl_safefree(sshc->quote_path1);
   Curl_safefree(sshc->quote_path2);
-  state(conn, SSH_SFTP_CLOSE);
+  state(data, SSH_SFTP_CLOSE);
   sshc->nextstate = SSH_NO_STATE;
   sshc->actualcode = CURLE_QUOTE_ERROR;
 }
 
-static void sftp_quote_stat(struct connectdata *conn)
+static void sftp_quote_stat(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   char *cmd = sshc->quote_item->data;
   sshc->acceptfail = FALSE;
@@ -2812,7 +2816,7 @@ static void sftp_quote_stat(struct connectdata *conn)
     Curl_safefree(sshc->quote_path2);
     failf(data, "Attempt to get SFTP stats failed: %d",
           sftp_get_error(sshc->sftp_session));
-    state(conn, SSH_SFTP_CLOSE);
+    state(data, SSH_SFTP_CLOSE);
     sshc->nextstate = SSH_NO_STATE;
     sshc->actualcode = CURLE_QUOTE_ERROR;
     return;
@@ -2826,7 +2830,7 @@ static void sftp_quote_stat(struct connectdata *conn)
       Curl_safefree(sshc->quote_path1);
       Curl_safefree(sshc->quote_path2);
       failf(data, "Syntax error: chgrp gid not a number");
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       sshc->actualcode = CURLE_QUOTE_ERROR;
       return;
@@ -2841,7 +2845,7 @@ static void sftp_quote_stat(struct connectdata *conn)
       Curl_safefree(sshc->quote_path1);
       Curl_safefree(sshc->quote_path2);
       failf(data, "Syntax error: chmod permissions not a number");
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       sshc->actualcode = CURLE_QUOTE_ERROR;
       return;
@@ -2856,16 +2860,44 @@ static void sftp_quote_stat(struct connectdata *conn)
       Curl_safefree(sshc->quote_path1);
       Curl_safefree(sshc->quote_path2);
       failf(data, "Syntax error: chown uid not a number");
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->nextstate = SSH_NO_STATE;
       sshc->actualcode = CURLE_QUOTE_ERROR;
       return;
     }
     sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
   }
+  else if(strncasecompare(cmd, "atime", 5)) {
+    time_t date = Curl_getdate_capped(sshc->quote_path1);
+    if(date == -1) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: incorrect access date format");
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return;
+    }
+    sshc->quote_attrs->atime = (uint32_t)date;
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
+  }
+  else if(strncasecompare(cmd, "mtime", 5)) {
+    time_t date = Curl_getdate_capped(sshc->quote_path1);
+    if(date == -1) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: incorrect modification date format");
+      state(data, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return;
+    }
+    sshc->quote_attrs->mtime = (uint32_t)date;
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
+  }
 
   /* Now send the completed structure... */
-  state(conn, SSH_SFTP_QUOTE_SETSTAT);
+  state(data, SSH_SFTP_QUOTE_SETSTAT);
   return;
 }
 
index 4f56bb4..3130dcc 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -103,30 +103,24 @@ static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
 static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
 static LIBSSH2_FREE_FUNC(my_libssh2_free);
 
-static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn);
-static CURLcode ssh_connect(struct connectdata *conn, bool *done);
-static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done);
-static CURLcode ssh_do(struct connectdata *conn, bool *done);
-
-static CURLcode scp_done(struct connectdata *conn,
-                         CURLcode, bool premature);
-static CURLcode scp_doing(struct connectdata *conn,
-                          bool *dophase_done);
-static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection);
-
-static CURLcode sftp_done(struct connectdata *conn,
-                          CURLcode, bool premature);
-static CURLcode sftp_doing(struct connectdata *conn,
-                           bool *dophase_done);
-static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
-static
-CURLcode sftp_perform(struct connectdata *conn,
-                      bool *connected,
-                      bool *dophase_done);
-static int ssh_getsock(struct connectdata *conn, curl_socket_t *sock);
-static int ssh_perform_getsock(const struct connectdata *conn,
-                               curl_socket_t *sock);
-static CURLcode ssh_setup_connection(struct connectdata *conn);
+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);
+static CURLcode ssh_do(struct Curl_easy *data, bool *done);
+static CURLcode scp_done(struct Curl_easy *data, CURLcode c, bool premature);
+static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead_connection);
+static CURLcode sftp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode sftp_doing(struct Curl_easy *data, bool *dophase_done);
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static CURLcode sftp_perform(struct Curl_easy *data, bool *connected,
+                             bool *dophase_done);
+static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn,
+                       curl_socket_t *sock);
+static CURLcode ssh_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn);
 
 /*
  * SCP protocol handler.
@@ -144,12 +138,13 @@ const struct Curl_handler Curl_handler_scp = {
   ssh_getsock,                          /* proto_getsock */
   ssh_getsock,                          /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  ssh_perform_getsock,                  /* perform_getsock */
+  ssh_getsock,                          /* perform_getsock */
   scp_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   PORT_SSH,                             /* defport */
   CURLPROTO_SCP,                        /* protocol */
+  CURLPROTO_SCP,                        /* family */
   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
   | PROTOPT_NOURLQUERY                  /* flags */
 };
@@ -171,12 +166,13 @@ const struct Curl_handler Curl_handler_sftp = {
   ssh_getsock,                          /* proto_getsock */
   ssh_getsock,                          /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  ssh_perform_getsock,                  /* perform_getsock */
+  ssh_getsock,                          /* perform_getsock */
   sftp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   PORT_SSH,                             /* defport */
   CURLPROTO_SFTP,                       /* protocol */
+  CURLPROTO_SFTP,                       /* family */
   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
   | PROTOPT_NOURLQUERY                  /* flags */
 };
@@ -306,8 +302,9 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free)
  * SSH State machine related code
  */
 /* This is the ONLY way to change SSH state! */
-static void state(struct connectdata *conn, sshstate nowstate)
+static void state(struct Curl_easy *data, sshstate nowstate)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
@@ -378,7 +375,7 @@ static void state(struct connectdata *conn, sshstate nowstate)
   DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
 
   if(sshc->state != nowstate) {
-    infof(conn->data, "SFTP %p state change from %s to %s\n",
+    infof(data, "SFTP %p state change from %s to %s\n",
           (void *)sshc, names[sshc->state], names[nowstate]);
   }
 #endif
@@ -432,16 +429,16 @@ static int sshkeycallback(struct Curl_easy *easy,
 #define libssh2_session_startup(x,y) libssh2_session_handshake(x,y)
 #endif
 
-static CURLcode ssh_knownhost(struct connectdata *conn)
+static CURLcode ssh_knownhost(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
 
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
-  struct Curl_easy *data = conn->data;
-
   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
     /* we're asked to verify the host against a file */
+    struct connectdata *conn = data->conn;
     struct ssh_conn *sshc = &conn->proto.sshc;
+    struct libssh2_knownhost *host = NULL;
     int rc;
     int keytype;
     size_t keylen;
@@ -456,7 +453,6 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
        * What host name does OpenSSH store in its file if an IDN name is
        * used?
        */
-      struct libssh2_knownhost *host;
       enum curl_khmatch keymatch;
       curl_sshkeycallback func =
         data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
@@ -562,13 +558,19 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
     default: /* unknown return codes will equal reject */
       /* FALLTHROUGH */
     case CURLKHSTAT_REJECT:
-      state(conn, SSH_SESSION_FREE);
+      state(data, SSH_SESSION_FREE);
       /* FALLTHROUGH */
     case CURLKHSTAT_DEFER:
       /* DEFER means bail out but keep the SSH_HOSTKEY state */
       result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
       break;
+    case CURLKHSTAT_FINE_REPLACE:
+      /* remove old host+key that doesn't match */
+      if(host)
+        libssh2_knownhost_del(sshc->kh, host);
+        /*FALLTHROUGH*/
     case CURLKHSTAT_FINE:
+        /*FALLTHROUGH*/
     case CURLKHSTAT_FINE_ADD_TO_FILE:
       /* proceed */
       if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
@@ -583,7 +585,8 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
         if(addrc)
           infof(data, "Warning adding the known host %s failed!\n",
                 conn->host.name);
-        else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
+        else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE ||
+                rc == CURLKHSTAT_FINE_REPLACE) {
           /* now we write the entire in-memory list of known hosts to the
              known_hosts file */
           int wrc =
@@ -600,15 +603,15 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
     }
   }
 #else /* HAVE_LIBSSH2_KNOWNHOST_API */
-  (void)conn;
+  (void)data;
 #endif
   return result;
 }
 
-static CURLcode ssh_check_fingerprint(struct connectdata *conn)
+static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
-  struct Curl_easy *data = conn->data;
   const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
   char md5buffer[33];
 
@@ -635,7 +638,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn)
       else
         failf(data,
             "Denied establishing ssh session: md5 fingerprint not available");
-      state(conn, SSH_SESSION_FREE);
+      state(data, SSH_SESSION_FREE);
       sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
       return sshc->actualcode;
     }
@@ -643,14 +646,14 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn)
     /* as we already matched, we skip the check for known hosts */
     return CURLE_OK;
   }
-  return ssh_knownhost(conn);
+  return ssh_knownhost(data);
 }
 
 /*
  * ssh_force_knownhost_key_type() will check the known hosts file and try to
  * force a specific public key type from the server if an entry is found.
  */
-static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn)
+static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
 
@@ -678,8 +681,8 @@ static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn)
     = "ssh-dss";
 
   const char *hostkey_method = NULL;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
-  struct Curl_easy *data = conn->data;
   struct libssh2_knownhost* store = NULL;
   const char *kh_name_end = NULL;
   size_t kh_name_size = 0;
@@ -754,18 +757,18 @@ static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn)
         hostkey_method = hostkey_method_ssh_dss;
         break;
       case LIBSSH2_KNOWNHOST_KEY_RSA1:
-        failf(data, "Found host key type RSA1 which is not supported\n");
+        failf(data, "Found host key type RSA1 which is not supported");
         return CURLE_SSH;
       default:
-        failf(data, "Unknown host key type: %i\n",
+        failf(data, "Unknown host key type: %i",
               (store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK));
         return CURLE_SSH;
       }
 
       infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method);
       result = libssh2_session_error_to_CURLE(
-          libssh2_session_method_pref(
-              sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
+        libssh2_session_method_pref(
+          sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
     }
     else {
       infof(data, "Did not find host %s in %s\n",
@@ -785,11 +788,11 @@ static CURLcode ssh_force_knownhost_key_type(struct connectdata *conn)
  * meaning it wants to be called again when the socket is ready
  */
 
-static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
+static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-  struct SSHPROTO *sftp_scp = data->req.protop;
+  struct connectdata *conn = data->conn;
+  struct SSHPROTO *sshp = data->req.p.ssh;
   struct ssh_conn *sshc = &conn->proto.sshc;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   int rc = LIBSSH2_ERROR_NONE;
@@ -800,7 +803,6 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
   *block = 0; /* we're not blocking by default */
 
   do {
-
     switch(sshc->state) {
     case SSH_INIT:
       sshc->secondCreateDirs = 0;
@@ -811,13 +813,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
          non-blocking */
       libssh2_session_set_blocking(sshc->ssh_session, 0);
 
-      result = ssh_force_knownhost_key_type(conn);
+      result = ssh_force_knownhost_key_type(data);
       if(result) {
-        state(conn, SSH_SESSION_FREE);
+        state(data, SSH_SESSION_FREE);
+        sshc->actualcode = result;
         break;
       }
 
-      state(conn, SSH_S_STARTUP);
+      state(data, SSH_S_STARTUP);
       /* FALLTHROUGH */
 
     case SSH_S_STARTUP:
@@ -830,12 +833,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
         failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg);
 
-        state(conn, SSH_SESSION_FREE);
+        state(data, SSH_SESSION_FREE);
         sshc->actualcode = CURLE_FAILED_INIT;
         break;
       }
 
-      state(conn, SSH_HOSTKEY);
+      state(data, SSH_HOSTKEY);
 
       /* FALLTHROUGH */
     case SSH_HOSTKEY:
@@ -844,9 +847,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
        * against our known hosts. How that is handled (reading from file,
        * whatever) is up to us.
        */
-      result = ssh_check_fingerprint(conn);
+      result = ssh_check_fingerprint(data);
       if(!result)
-        state(conn, SSH_AUTHLIST);
+        state(data, SSH_AUTHLIST);
       /* ssh_check_fingerprint sets state appropriately on error */
       break;
 
@@ -869,14 +872,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         if(libssh2_userauth_authenticated(sshc->ssh_session)) {
           sshc->authed = TRUE;
           infof(data, "SSH user accepted with no authentication\n");
-          state(conn, SSH_AUTH_DONE);
+          state(data, SSH_AUTH_DONE);
           break;
         }
         ssherr = libssh2_session_last_errno(sshc->ssh_session);
         if(ssherr == LIBSSH2_ERROR_EAGAIN)
           rc = LIBSSH2_ERROR_EAGAIN;
         else {
-          state(conn, SSH_SESSION_FREE);
+          state(data, SSH_SESSION_FREE);
           sshc->actualcode = libssh2_session_error_to_CURLE(ssherr);
         }
         break;
@@ -884,7 +887,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       infof(data, "SSH authentication methods available: %s\n",
             sshc->authlist);
 
-      state(conn, SSH_AUTH_PKEY_INIT);
+      state(data, SSH_AUTH_PKEY_INIT);
       break;
 
     case SSH_AUTH_PKEY_INIT:
@@ -956,7 +959,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         if(out_of_memory || sshc->rsa == NULL) {
           Curl_safefree(sshc->rsa);
           Curl_safefree(sshc->rsa_pub);
-          state(conn, SSH_SESSION_FREE);
+          state(data, SSH_SESSION_FREE);
           sshc->actualcode = CURLE_OUT_OF_MEMORY;
           break;
         }
@@ -969,10 +972,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
         infof(data, "Using SSH private key file '%s'\n", sshc->rsa);
 
-        state(conn, SSH_AUTH_PKEY);
+        state(data, SSH_AUTH_PKEY);
       }
       else {
-        state(conn, SSH_AUTH_PASS_INIT);
+        state(data, SSH_AUTH_PASS_INIT);
       }
       break;
 
@@ -995,14 +998,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       if(rc == 0) {
         sshc->authed = TRUE;
         infof(data, "Initialized SSH public key authentication\n");
-        state(conn, SSH_AUTH_DONE);
+        state(data, SSH_AUTH_DONE);
       }
       else {
         char *err_msg = NULL;
         (void)libssh2_session_last_error(sshc->ssh_session,
                                          &err_msg, NULL, 0);
         infof(data, "SSH public key authentication failed: %s\n", err_msg);
-        state(conn, SSH_AUTH_PASS_INIT);
+        state(data, SSH_AUTH_PASS_INIT);
         rc = 0; /* clear rc and continue */
       }
       break;
@@ -1010,10 +1013,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     case SSH_AUTH_PASS_INIT:
       if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
          (strstr(sshc->authlist, "password") != NULL)) {
-        state(conn, SSH_AUTH_PASS);
+        state(data, SSH_AUTH_PASS);
       }
       else {
-        state(conn, SSH_AUTH_HOST_INIT);
+        state(data, SSH_AUTH_HOST_INIT);
         rc = 0; /* clear rc and continue */
       }
       break;
@@ -1030,10 +1033,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       if(rc == 0) {
         sshc->authed = TRUE;
         infof(data, "Initialized password authentication\n");
-        state(conn, SSH_AUTH_DONE);
+        state(data, SSH_AUTH_DONE);
       }
       else {
-        state(conn, SSH_AUTH_HOST_INIT);
+        state(data, SSH_AUTH_HOST_INIT);
         rc = 0; /* clear rc and continue */
       }
       break;
@@ -1041,15 +1044,15 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     case SSH_AUTH_HOST_INIT:
       if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
          (strstr(sshc->authlist, "hostbased") != NULL)) {
-        state(conn, SSH_AUTH_HOST);
+        state(data, SSH_AUTH_HOST);
       }
       else {
-        state(conn, SSH_AUTH_AGENT_INIT);
+        state(data, SSH_AUTH_AGENT_INIT);
       }
       break;
 
     case SSH_AUTH_HOST:
-      state(conn, SSH_AUTH_AGENT_INIT);
+      state(data, SSH_AUTH_AGENT_INIT);
       break;
 
     case SSH_AUTH_AGENT_INIT:
@@ -1065,7 +1068,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           if(!sshc->ssh_agent) {
             infof(data, "Could not create agent object\n");
 
-            state(conn, SSH_AUTH_KEY_INIT);
+            state(data, SSH_AUTH_KEY_INIT);
             break;
           }
         }
@@ -1075,16 +1078,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           break;
         if(rc < 0) {
           infof(data, "Failure connecting to agent\n");
-          state(conn, SSH_AUTH_KEY_INIT);
+          state(data, SSH_AUTH_KEY_INIT);
           rc = 0; /* clear rc and continue */
         }
         else {
-          state(conn, SSH_AUTH_AGENT_LIST);
+          state(data, SSH_AUTH_AGENT_LIST);
         }
       }
       else
 #endif /* HAVE_LIBSSH2_AGENT_API */
-        state(conn, SSH_AUTH_KEY_INIT);
+        state(data, SSH_AUTH_KEY_INIT);
       break;
 
     case SSH_AUTH_AGENT_LIST:
@@ -1095,11 +1098,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         break;
       if(rc < 0) {
         infof(data, "Failure requesting identities to agent\n");
-        state(conn, SSH_AUTH_KEY_INIT);
+        state(data, SSH_AUTH_KEY_INIT);
         rc = 0; /* clear rc and continue */
       }
       else {
-        state(conn, SSH_AUTH_AGENT);
+        state(data, SSH_AUTH_AGENT);
         sshc->sshagent_prev_identity = NULL;
       }
 #endif
@@ -1137,10 +1140,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       if(rc == LIBSSH2_ERROR_NONE) {
         sshc->authed = TRUE;
         infof(data, "Agent based authentication successful\n");
-        state(conn, SSH_AUTH_DONE);
+        state(data, SSH_AUTH_DONE);
       }
       else {
-        state(conn, SSH_AUTH_KEY_INIT);
+        state(data, SSH_AUTH_KEY_INIT);
         rc = 0; /* clear rc and continue */
       }
 #endif
@@ -1149,10 +1152,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     case SSH_AUTH_KEY_INIT:
       if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
          && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
-        state(conn, SSH_AUTH_KEY);
+        state(data, SSH_AUTH_KEY);
       }
       else {
-        state(conn, SSH_AUTH_DONE);
+        state(data, SSH_AUTH_DONE);
       }
       break;
 
@@ -1170,13 +1173,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         sshc->authed = TRUE;
         infof(data, "Initialized keyboard interactive authentication\n");
       }
-      state(conn, SSH_AUTH_DONE);
+      state(data, SSH_AUTH_DONE);
       break;
 
     case SSH_AUTH_DONE:
       if(!sshc->authed) {
         failf(data, "Authentication failure");
-        state(conn, SSH_SESSION_FREE);
+        state(data, SSH_SESSION_FREE);
         sshc->actualcode = CURLE_LOGIN_DENIED;
         break;
       }
@@ -1186,17 +1189,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
        */
       infof(data, "Authentication complete\n");
 
-      Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
+      Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
 
       conn->sockfd = sock;
       conn->writesockfd = CURL_SOCKET_BAD;
 
       if(conn->handler->protocol == CURLPROTO_SFTP) {
-        state(conn, SSH_SFTP_INIT);
+        state(data, SSH_SFTP_INIT);
         break;
       }
       infof(data, "SSH CONNECT phase done\n");
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     case SSH_SFTP_INIT:
@@ -1215,11 +1218,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         (void)libssh2_session_last_error(sshc->ssh_session,
                                          &err_msg, NULL, 0);
         failf(data, "Failure initializing sftp session: %s", err_msg);
-        state(conn, SSH_SESSION_FREE);
+        state(data, SSH_SESSION_FREE);
         sshc->actualcode = CURLE_FAILED_INIT;
         break;
       }
-      state(conn, SSH_SFTP_REALPATH);
+      state(data, SSH_SFTP_REALPATH);
       break;
 
     case SSH_SFTP_REALPATH:
@@ -1239,11 +1242,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         tempHome[rc] = '\0';
         sshc->homedir = strdup(tempHome);
         if(!sshc->homedir) {
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->actualcode = CURLE_OUT_OF_MEMORY;
           break;
         }
-        conn->data->state.most_recent_ftp_entrypath = sshc->homedir;
+        data->state.most_recent_ftp_entrypath = sshc->homedir;
       }
       else {
         /* Return the error type */
@@ -1255,9 +1258,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
              a time-out or similar */
           result = CURLE_SSH;
         sshc->actualcode = result;
-        DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
+        DEBUGF(infof(data, "error = %lu makes libcurl = %d\n",
                      sftperr, (int)result));
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
     }
@@ -1266,25 +1269,25 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
        since the homedir will remain the same between request but the
        working path will not. */
     DEBUGF(infof(data, "SSH CONNECT phase done\n"));
-    state(conn, SSH_STOP);
+    state(data, SSH_STOP);
     break;
 
     case SSH_SFTP_QUOTE_INIT:
 
-      result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+      result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
       if(result) {
         sshc->actualcode = result;
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
 
       if(data->set.quote) {
         infof(data, "Sending quote commands\n");
         sshc->quote_item = data->set.quote;
-        state(conn, SSH_SFTP_QUOTE);
+        state(data, SSH_SFTP_QUOTE);
       }
       else {
-        state(conn, SSH_SFTP_GETINFO);
+        state(data, SSH_SFTP_GETINFO);
       }
       break;
 
@@ -1292,10 +1295,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       if(data->set.postquote) {
         infof(data, "Sending quote commands\n");
         sshc->quote_item = data->set.postquote;
-        state(conn, SSH_SFTP_QUOTE);
+        state(data, SSH_SFTP_QUOTE);
       }
       else {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
       }
       break;
 
@@ -1326,29 +1329,28 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       if(strcasecompare("pwd", cmd)) {
         /* output debug output if that is requested */
         char *tmp = aprintf("257 \"%s\" is current directory.\n",
-                            sftp_scp->path);
+                            sshp->path);
         if(!tmp) {
           result = CURLE_OUT_OF_MEMORY;
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           break;
         }
-        if(data->set.verbose) {
-          Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
-          Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
-        }
+        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
+        Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
+
         /* this sends an FTP-like "header" to the header callback so that the
            current directory can be read very similar to how it is read when
            using ordinary FTP. */
-        result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
         free(tmp);
         if(result) {
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = result;
         }
         else
-          state(conn, SSH_SFTP_NEXT_QUOTE);
+          state(data, SSH_SFTP_NEXT_QUOTE);
         break;
       }
       {
@@ -1360,7 +1362,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         if(cp == NULL) {
           failf(data, "Syntax error command '%s'. Missing parameter!",
                 cmd);
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = CURLE_QUOTE_ERROR;
           break;
@@ -1376,7 +1378,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
             failf(data, "Out of memory");
           else
             failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = result;
           break;
@@ -1390,7 +1392,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
          */
         if(strncasecompare(cmd, "chgrp ", 6) ||
            strncasecompare(cmd, "chmod ", 6) ||
-           strncasecompare(cmd, "chown ", 6) ) {
+           strncasecompare(cmd, "chown ", 6) ||
+           strncasecompare(cmd, "atime ", 6) ||
+           strncasecompare(cmd, "mtime ", 6)) {
           /* attribute change */
 
           /* sshc->quote_path1 contains the mode to set */
@@ -1402,13 +1406,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
             else
               failf(data, "Syntax error in %s: Bad second parameter", cmd);
             Curl_safefree(sshc->quote_path1);
-            state(conn, SSH_SFTP_CLOSE);
+            state(data, SSH_SFTP_CLOSE);
             sshc->nextstate = SSH_NO_STATE;
             sshc->actualcode = result;
             break;
           }
-          memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
-          state(conn, SSH_SFTP_QUOTE_STAT);
+          memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+          state(data, SSH_SFTP_QUOTE_STAT);
           break;
         }
         if(strncasecompare(cmd, "ln ", 3) ||
@@ -1424,17 +1428,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
               failf(data,
                     "Syntax error in ln/symlink: Bad second parameter");
             Curl_safefree(sshc->quote_path1);
-            state(conn, SSH_SFTP_CLOSE);
+            state(data, SSH_SFTP_CLOSE);
             sshc->nextstate = SSH_NO_STATE;
             sshc->actualcode = result;
             break;
           }
-          state(conn, SSH_SFTP_QUOTE_SYMLINK);
+          state(data, SSH_SFTP_QUOTE_SYMLINK);
           break;
         }
         else if(strncasecompare(cmd, "mkdir ", 6)) {
           /* create dir */
-          state(conn, SSH_SFTP_QUOTE_MKDIR);
+          state(data, SSH_SFTP_QUOTE_MKDIR);
           break;
         }
         else if(strncasecompare(cmd, "rename ", 7)) {
@@ -1448,26 +1452,26 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
             else
               failf(data, "Syntax error in rename: Bad second parameter");
             Curl_safefree(sshc->quote_path1);
-            state(conn, SSH_SFTP_CLOSE);
+            state(data, SSH_SFTP_CLOSE);
             sshc->nextstate = SSH_NO_STATE;
             sshc->actualcode = result;
             break;
           }
-          state(conn, SSH_SFTP_QUOTE_RENAME);
+          state(data, SSH_SFTP_QUOTE_RENAME);
           break;
         }
         else if(strncasecompare(cmd, "rmdir ", 6)) {
           /* delete dir */
-          state(conn, SSH_SFTP_QUOTE_RMDIR);
+          state(data, SSH_SFTP_QUOTE_RMDIR);
           break;
         }
         else if(strncasecompare(cmd, "rm ", 3)) {
-          state(conn, SSH_SFTP_QUOTE_UNLINK);
+          state(data, SSH_SFTP_QUOTE_UNLINK);
           break;
         }
 #ifdef HAS_STATVFS_SUPPORT
         else if(strncasecompare(cmd, "statvfs ", 8)) {
-          state(conn, SSH_SFTP_QUOTE_STATVFS);
+          state(data, SSH_SFTP_QUOTE_STATVFS);
           break;
         }
 #endif
@@ -1475,7 +1479,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         failf(data, "Unknown SFTP command");
         Curl_safefree(sshc->quote_path1);
         Curl_safefree(sshc->quote_path2);
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
@@ -1490,15 +1494,15 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       sshc->quote_item = sshc->quote_item->next;
 
       if(sshc->quote_item) {
-        state(conn, SSH_SFTP_QUOTE);
+        state(data, SSH_SFTP_QUOTE);
       }
       else {
         if(sshc->nextstate != SSH_NO_STATE) {
-          state(conn, sshc->nextstate);
+          state(data, sshc->nextstate);
           sshc->nextstate = SSH_NO_STATE;
         }
         else {
-          state(conn, SSH_SFTP_GETINFO);
+          state(data, SSH_SFTP_GETINFO);
         }
       }
       break;
@@ -1526,7 +1530,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
                                   curlx_uztoui(strlen(sshc->quote_path2)),
                                   LIBSSH2_SFTP_STAT,
-                                  &sshc->quote_attrs);
+                                  &sshp->quote_attrs);
         if(rc == LIBSSH2_ERROR_EAGAIN) {
           break;
         }
@@ -1536,7 +1540,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           Curl_safefree(sshc->quote_path2);
           failf(data, "Attempt to get SFTP stats failed: %s",
                 sftp_libssh2_strerror(sftperr));
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = CURLE_QUOTE_ERROR;
           break;
@@ -1545,51 +1549,79 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
 
       /* Now set the new attributes... */
       if(strncasecompare(cmd, "chgrp", 5)) {
-        sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
-        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
-        if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+        sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
            !sshc->acceptfail) {
           Curl_safefree(sshc->quote_path1);
           Curl_safefree(sshc->quote_path2);
           failf(data, "Syntax error: chgrp gid not a number");
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = CURLE_QUOTE_ERROR;
           break;
         }
       }
       else if(strncasecompare(cmd, "chmod", 5)) {
-        sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
-        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+        sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
         /* permissions are octal */
-        if(sshc->quote_attrs.permissions == 0 &&
+        if(sshp->quote_attrs.permissions == 0 &&
            !ISDIGIT(sshc->quote_path1[0])) {
           Curl_safefree(sshc->quote_path1);
           Curl_safefree(sshc->quote_path2);
           failf(data, "Syntax error: chmod permissions not a number");
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = CURLE_QUOTE_ERROR;
           break;
         }
       }
       else if(strncasecompare(cmd, "chown", 5)) {
-        sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
-        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
-        if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+        sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
            !sshc->acceptfail) {
           Curl_safefree(sshc->quote_path1);
           Curl_safefree(sshc->quote_path2);
           failf(data, "Syntax error: chown uid not a number");
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = CURLE_QUOTE_ERROR;
           break;
         }
       }
+      else if(strncasecompare(cmd, "atime", 5)) {
+        time_t date = Curl_getdate_capped(sshc->quote_path1);
+        if(date == -1) {
+          Curl_safefree(sshc->quote_path1);
+          Curl_safefree(sshc->quote_path2);
+          failf(data, "Syntax error: incorrect access date format");
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+        sshp->quote_attrs.atime = (unsigned long)date;
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
+      }
+      else if(strncasecompare(cmd, "mtime", 5)) {
+        time_t date = Curl_getdate_capped(sshc->quote_path1);
+        if(date == -1) {
+          Curl_safefree(sshc->quote_path1);
+          Curl_safefree(sshc->quote_path2);
+          failf(data, "Syntax error: incorrect modification date format");
+          state(data, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+        sshp->quote_attrs.mtime = (unsigned long)date;
+        sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
+      }
 
       /* Now send the completed structure... */
-      state(conn, SSH_SFTP_QUOTE_SETSTAT);
+      state(data, SSH_SFTP_QUOTE_SETSTAT);
       break;
     }
 
@@ -1597,7 +1629,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
                                 curlx_uztoui(strlen(sshc->quote_path2)),
                                 LIBSSH2_SFTP_SETSTAT,
-                                &sshc->quote_attrs);
+                                &sshp->quote_attrs);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
@@ -1607,12 +1639,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path2);
         failf(data, "Attempt to set SFTP stats failed: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_SYMLINK:
@@ -1630,12 +1662,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path2);
         failf(data, "symlink command failed: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_MKDIR:
@@ -1650,12 +1682,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path1);
         failf(data, "mkdir command failed: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_RENAME:
@@ -1676,12 +1708,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path2);
         failf(data, "rename command failed: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_RMDIR:
@@ -1695,12 +1727,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path1);
         failf(data, "rmdir command failed: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_UNLINK:
@@ -1713,12 +1745,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
 
 #ifdef HAS_STATVFS_SUPPORT
@@ -1737,7 +1769,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         Curl_safefree(sshc->quote_path1);
         failf(data, "statvfs command failed: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
@@ -1758,30 +1790,30 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
                             statvfs.f_namemax);
         if(!tmp) {
           result = CURLE_OUT_OF_MEMORY;
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           break;
         }
 
-        result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
         free(tmp);
         if(result) {
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->nextstate = SSH_NO_STATE;
           sshc->actualcode = result;
         }
       }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
+      state(data, SSH_SFTP_NEXT_QUOTE);
       break;
     }
 #endif
     case SSH_SFTP_GETINFO:
     {
       if(data->set.get_filetime) {
-        state(conn, SSH_SFTP_FILETIME);
+        state(data, SSH_SFTP_FILETIME);
       }
       else {
-        state(conn, SSH_SFTP_TRANS_INIT);
+        state(data, SSH_SFTP_TRANS_INIT);
       }
       break;
     }
@@ -1790,8 +1822,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     {
       LIBSSH2_SFTP_ATTRIBUTES attrs;
 
-      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
-                                curlx_uztoui(strlen(sftp_scp->path)),
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                curlx_uztoui(strlen(sshp->path)),
                                 LIBSSH2_SFTP_STAT, &attrs);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
@@ -1800,18 +1832,18 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         data->info.filetime = attrs.mtime;
       }
 
-      state(conn, SSH_SFTP_TRANS_INIT);
+      state(data, SSH_SFTP_TRANS_INIT);
       break;
     }
 
     case SSH_SFTP_TRANS_INIT:
       if(data->set.upload)
-        state(conn, SSH_SFTP_UPLOAD_INIT);
+        state(data, SSH_SFTP_UPLOAD_INIT);
       else {
-        if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
-          state(conn, SSH_SFTP_READDIR_INIT);
+        if(sshp->path[strlen(sshp->path)-1] == '/')
+          state(data, SSH_SFTP_READDIR_INIT);
         else
-          state(conn, SSH_SFTP_DOWNLOAD_INIT);
+          state(data, SSH_SFTP_DOWNLOAD_INIT);
       }
       break;
 
@@ -1828,8 +1860,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       if(data->state.resume_from != 0) {
         LIBSSH2_SFTP_ATTRIBUTES attrs;
         if(data->state.resume_from < 0) {
-          rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
-                                    curlx_uztoui(strlen(sftp_scp->path)),
+          rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                    curlx_uztoui(strlen(sshp->path)),
                                     LIBSSH2_SFTP_STAT, &attrs);
           if(rc == LIBSSH2_ERROR_EAGAIN) {
             break;
@@ -1855,12 +1887,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         /* If we have restart position then open for append */
         flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
       else
-        /* Clear file before writing (normal behaviour) */
+        /* Clear file before writing (normal behavior) */
         flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
 
       sshc->sftp_handle =
-        libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
-                             curlx_uztoui(strlen(sftp_scp->path)),
+        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
+                             curlx_uztoui(strlen(sshp->path)),
                              flags, data->set.new_file_perms,
                              LIBSSH2_SFTP_OPENFILE);
 
@@ -1878,7 +1910,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */
 
         if(sshc->secondCreateDirs) {
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
             sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
           failf(data, "Creating the dir/file failed: %s",
@@ -1889,14 +1921,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
             (sftperr == LIBSSH2_FX_FAILURE) ||
             (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) &&
            (data->set.ftp_create_missing_dirs &&
-            (strlen(sftp_scp->path) > 1))) {
+            (strlen(sshp->path) > 1))) {
           /* try to create the path remotely */
           rc = 0; /* clear rc and continue */
           sshc->secondCreateDirs = 1;
-          state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+          state(data, SSH_SFTP_CREATE_DIRS_INIT);
           break;
         }
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
           sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
         if(!sshc->actualcode) {
@@ -1906,7 +1938,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           sshc->actualcode = CURLE_SSH;
           sftperr = LIBSSH2_FX_OK;
         }
-        failf(data, "Upload failed: %s (%d/%d)",
+        failf(data, "Upload failed: %s (%lu/%d)",
               sftperr != LIBSSH2_FX_OK ?
               sftp_libssh2_strerror(sftperr):"ssh error",
               sftperr, rc);
@@ -1975,7 +2007,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       conn->sockfd = conn->writesockfd;
 
       if(result) {
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = result;
       }
       else {
@@ -1993,18 +2025,18 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
            timeout here */
         Curl_expire(data, 0, EXPIRE_RUN_NOW);
 
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
       }
       break;
     }
 
     case SSH_SFTP_CREATE_DIRS_INIT:
-      if(strlen(sftp_scp->path) > 1) {
-        sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
-        state(conn, SSH_SFTP_CREATE_DIRS);
+      if(strlen(sshp->path) > 1) {
+        sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
+        state(data, SSH_SFTP_CREATE_DIRS);
       }
       else {
-        state(conn, SSH_SFTP_UPLOAD_INIT);
+        state(data, SSH_SFTP_UPLOAD_INIT);
       }
       break;
 
@@ -2013,17 +2045,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       if(sshc->slash_pos) {
         *sshc->slash_pos = 0;
 
-        infof(data, "Creating directory '%s'\n", sftp_scp->path);
-        state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
+        infof(data, "Creating directory '%s'\n", sshp->path);
+        state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
         break;
       }
-      state(conn, SSH_SFTP_UPLOAD_INIT);
+      state(data, SSH_SFTP_UPLOAD_INIT);
       break;
 
     case SSH_SFTP_CREATE_DIRS_MKDIR:
       /* 'mode' - parameter is preliminary - default to 0644 */
-      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path,
-                                 curlx_uztoui(strlen(sftp_scp->path)),
+      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path,
+                                 curlx_uztoui(strlen(sshp->path)),
                                  data->set.new_directory_perms);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
@@ -2041,19 +2073,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
            (sftperr != LIBSSH2_FX_FAILURE) &&
            (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {
           result = sftp_libssh2_error_to_CURLE(sftperr);
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           sshc->actualcode = result?result:CURLE_SSH;
           break;
         }
         rc = 0; /* clear rc and continue */
       }
-      state(conn, SSH_SFTP_CREATE_DIRS);
+      state(data, SSH_SFTP_CREATE_DIRS);
       break;
 
     case SSH_SFTP_READDIR_INIT:
       Curl_pgrsSetDownloadSize(data, -1);
       if(data->set.opt_no_body) {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
 
@@ -2062,9 +2094,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
        * listing
        */
       sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
-                                               sftp_scp->path,
+                                               sshp->path,
                                                curlx_uztoui(
-                                                 strlen(sftp_scp->path)),
+                                                 strlen(sshp->path)),
                                                0, 0, LIBSSH2_SFTP_OPENDIR);
       if(!sshc->sftp_handle) {
         if(libssh2_session_last_errno(sshc->ssh_session) ==
@@ -2075,51 +2107,51 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         failf(data, "Could not open directory for reading: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         result = sftp_libssh2_error_to_CURLE(sftperr);
         sshc->actualcode = result?result:CURLE_SSH;
         break;
       }
-      sshc->readdir_filename = malloc(PATH_MAX + 1);
-      if(!sshc->readdir_filename) {
-        state(conn, SSH_SFTP_CLOSE);
+      sshp->readdir_filename = malloc(PATH_MAX + 1);
+      if(!sshp->readdir_filename) {
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_OUT_OF_MEMORY;
         break;
       }
-      sshc->readdir_longentry = malloc(PATH_MAX + 1);
-      if(!sshc->readdir_longentry) {
-        Curl_safefree(sshc->readdir_filename);
-        state(conn, SSH_SFTP_CLOSE);
+      sshp->readdir_longentry = malloc(PATH_MAX + 1);
+      if(!sshp->readdir_longentry) {
+        Curl_safefree(sshp->readdir_filename);
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_OUT_OF_MEMORY;
         break;
       }
-      Curl_dyn_init(&sshc->readdir, PATH_MAX * 2);
-      state(conn, SSH_SFTP_READDIR);
+      Curl_dyn_init(&sshp->readdir, PATH_MAX * 2);
+      state(data, SSH_SFTP_READDIR);
       break;
 
     case SSH_SFTP_READDIR:
       rc = libssh2_sftp_readdir_ex(sshc->sftp_handle,
-                                   sshc->readdir_filename,
+                                   sshp->readdir_filename,
                                    PATH_MAX,
-                                   sshc->readdir_longentry,
+                                   sshp->readdir_longentry,
                                    PATH_MAX,
-                                   &sshc->readdir_attrs);
+                                   &sshp->readdir_attrs);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
       if(rc > 0) {
         readdir_len = (size_t) rc;
-        sshc->readdir_filename[readdir_len] = '\0';
+        sshp->readdir_filename[readdir_len] = '\0';
 
         if(data->set.ftp_list_only) {
-          result = Curl_client_write(conn, CLIENTWRITE_BODY,
-                                     sshc->readdir_filename,
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                     sshp->readdir_filename,
                                      readdir_len);
           if(!result)
-            result = Curl_client_write(conn, CLIENTWRITE_BODY,
+            result = Curl_client_write(data, CLIENTWRITE_BODY,
                                        (char *)"\n", 1);
           if(result) {
-            state(conn, SSH_STOP);
+            state(data, SSH_STOP);
             break;
           }
           /* since this counts what we send to the client, we include the
@@ -2127,39 +2159,37 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           data->req.bytecount += readdir_len + 1;
 
           /* output debug output if that is requested */
-          if(data->set.verbose) {
-            Curl_debug(data, CURLINFO_DATA_IN, sshc->readdir_filename,
-                       readdir_len);
-            Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1);
-          }
+          Curl_debug(data, CURLINFO_DATA_IN, sshp->readdir_filename,
+                     readdir_len);
+          Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1);
         }
         else {
-          result = Curl_dyn_add(&sshc->readdir, sshc->readdir_longentry);
+          result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
 
           if(!result) {
-            if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
-               ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+            if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+               ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
                 LIBSSH2_SFTP_S_IFLNK)) {
-              Curl_dyn_init(&sshc->readdir_link, PATH_MAX);
-              result = Curl_dyn_add(&sshc->readdir_link, sftp_scp->path);
-              state(conn, SSH_SFTP_READDIR_LINK);
+              Curl_dyn_init(&sshp->readdir_link, PATH_MAX);
+              result = Curl_dyn_add(&sshp->readdir_link, sshp->path);
+              state(data, SSH_SFTP_READDIR_LINK);
               if(!result)
                 break;
             }
             else {
-              state(conn, SSH_SFTP_READDIR_BOTTOM);
+              state(data, SSH_SFTP_READDIR_BOTTOM);
               break;
             }
           }
           sshc->actualcode = result;
-          state(conn, SSH_SFTP_CLOSE);
+          state(data, SSH_SFTP_CLOSE);
           break;
         }
       }
       else if(rc == 0) {
-        Curl_safefree(sshc->readdir_filename);
-        Curl_safefree(sshc->readdir_longentry);
-        state(conn, SSH_SFTP_READDIR_DONE);
+        Curl_safefree(sshp->readdir_filename);
+        Curl_safefree(sshp->readdir_longentry);
+        state(data, SSH_SFTP_READDIR_DONE);
         break;
       }
       else if(rc < 0) {
@@ -2169,9 +2199,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         failf(data, "Could not open remote file for reading: %s :: %d",
               sftp_libssh2_strerror(sftperr),
               libssh2_session_last_errno(sshc->ssh_session));
-        Curl_safefree(sshc->readdir_filename);
-        Curl_safefree(sshc->readdir_longentry);
-        state(conn, SSH_SFTP_CLOSE);
+        Curl_safefree(sshp->readdir_filename);
+        Curl_safefree(sshp->readdir_longentry);
+        state(data, SSH_SFTP_CLOSE);
         break;
       }
       break;
@@ -2179,55 +2209,51 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     case SSH_SFTP_READDIR_LINK:
       rc =
         libssh2_sftp_symlink_ex(sshc->sftp_session,
-                                Curl_dyn_ptr(&sshc->readdir_link),
-                                (int)Curl_dyn_len(&sshc->readdir_link),
-                                sshc->readdir_filename,
+                                Curl_dyn_ptr(&sshp->readdir_link),
+                                (int)Curl_dyn_len(&sshp->readdir_link),
+                                sshp->readdir_filename,
                                 PATH_MAX, LIBSSH2_SFTP_READLINK);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
-      readdir_len = (size_t) rc;
-      Curl_dyn_free(&sshc->readdir_link);
+      Curl_dyn_free(&sshp->readdir_link);
 
       /* append filename and extra output */
-      result = Curl_dyn_addf(&sshc->readdir, " -> %s", sshc->readdir_filename);
+      result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
 
       if(result) {
         sshc->readdir_line = NULL;
-        Curl_safefree(sshc->readdir_filename);
-        Curl_safefree(sshc->readdir_longentry);
-        state(conn, SSH_SFTP_CLOSE);
+        Curl_safefree(sshp->readdir_filename);
+        Curl_safefree(sshp->readdir_longentry);
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = result;
         break;
       }
 
-      state(conn, SSH_SFTP_READDIR_BOTTOM);
+      state(data, SSH_SFTP_READDIR_BOTTOM);
       break;
 
     case SSH_SFTP_READDIR_BOTTOM:
-      result = Curl_dyn_addn(&sshc->readdir, "\n", 1);
+      result = Curl_dyn_addn(&sshp->readdir, "\n", 1);
       if(!result)
-        result = Curl_client_write(conn, CLIENTWRITE_BODY,
-                                   Curl_dyn_ptr(&sshc->readdir),
-                                   Curl_dyn_len(&sshc->readdir));
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   Curl_dyn_ptr(&sshp->readdir),
+                                   Curl_dyn_len(&sshp->readdir));
 
       if(!result) {
-
         /* output debug output if that is requested */
-        if(data->set.verbose) {
-          Curl_debug(data, CURLINFO_DATA_IN,
-                     Curl_dyn_ptr(&sshc->readdir),
-                     Curl_dyn_len(&sshc->readdir));
-        }
-        data->req.bytecount += Curl_dyn_len(&sshc->readdir);
+        Curl_debug(data, CURLINFO_DATA_IN,
+                   Curl_dyn_ptr(&sshp->readdir),
+                   Curl_dyn_len(&sshp->readdir));
+        data->req.bytecount += Curl_dyn_len(&sshp->readdir);
       }
       if(result) {
-        Curl_dyn_free(&sshc->readdir);
-        state(conn, SSH_STOP);
+        Curl_dyn_free(&sshp->readdir);
+        state(data, SSH_STOP);
       }
       else {
-        Curl_dyn_reset(&sshc->readdir);
-        state(conn, SSH_SFTP_READDIR);
+        Curl_dyn_reset(&sshp->readdir);
+        state(data, SSH_SFTP_READDIR);
       }
       break;
 
@@ -2238,12 +2264,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         break;
       }
       sshc->sftp_handle = NULL;
-      Curl_safefree(sshc->readdir_filename);
-      Curl_safefree(sshc->readdir_longentry);
+      Curl_safefree(sshp->readdir_filename);
+      Curl_safefree(sshp->readdir_longentry);
 
       /* no data to transfer */
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     case SSH_SFTP_DOWNLOAD_INIT:
@@ -2251,8 +2277,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
        * Work on getting the specified file
        */
       sshc->sftp_handle =
-        libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
-                             curlx_uztoui(strlen(sftp_scp->path)),
+        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
+                             curlx_uztoui(strlen(sshp->path)),
                              LIBSSH2_FXF_READ, data->set.new_file_perms,
                              LIBSSH2_SFTP_OPENFILE);
       if(!sshc->sftp_handle) {
@@ -2264,20 +2290,20 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         sftperr = libssh2_sftp_last_error(sshc->sftp_session);
         failf(data, "Could not open remote file for reading: %s",
               sftp_libssh2_strerror(sftperr));
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         result = sftp_libssh2_error_to_CURLE(sftperr);
         sshc->actualcode = result?result:CURLE_SSH;
         break;
       }
-      state(conn, SSH_SFTP_DOWNLOAD_STAT);
+      state(data, SSH_SFTP_DOWNLOAD_STAT);
       break;
 
     case SSH_SFTP_DOWNLOAD_STAT:
     {
       LIBSSH2_SFTP_ATTRIBUTES attrs;
 
-      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
-                                curlx_uztoui(strlen(sftp_scp->path)),
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
+                                curlx_uztoui(strlen(sshp->path)),
                                 LIBSSH2_SFTP_STAT, &attrs);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
@@ -2302,14 +2328,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
           return CURLE_BAD_DOWNLOAD_RESUME;
         }
-        if(conn->data->state.use_range) {
+        if(data->state.use_range) {
           curl_off_t from, to;
           char *ptr;
           char *ptr2;
           CURLofft to_t;
           CURLofft from_t;
 
-          from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from);
+          from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
           if(from_t == CURL_OFFT_FLOW)
             return CURLE_RANGE_ERROR;
           while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
@@ -2340,7 +2366,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
             size = to - from + 1;
           }
 
-          SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
+          SFTP_SEEK(sshc->sftp_handle, from);
         }
         data->req.size = size;
         data->req.maxdownload = size;
@@ -2383,7 +2409,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       /* no data to transfer */
       Curl_setup_transfer(data, -1, -1, FALSE, -1);
       infof(data, "File already completely downloaded\n");
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
     }
     Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
@@ -2399,11 +2425,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     if(result) {
       /* this should never occur; the close state should be entered
          at the time the error occurs */
-      state(conn, SSH_SFTP_CLOSE);
+      state(data, SSH_SFTP_CLOSE);
       sshc->actualcode = result;
     }
     else {
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
     }
     break;
 
@@ -2422,7 +2448,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         sshc->sftp_handle = NULL;
       }
 
-      Curl_safefree(sftp_scp->path);
+      Curl_safefree(sshp->path);
 
       DEBUGF(infof(data, "SFTP DONE done\n"));
 
@@ -2431,11 +2457,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
          SSH_SFTP_CLOSE to pass the correct result back  */
       if(sshc->nextstate != SSH_NO_STATE &&
          sshc->nextstate != SSH_SFTP_CLOSE) {
-        state(conn, sshc->nextstate);
+        state(data, sshc->nextstate);
         sshc->nextstate = SSH_SFTP_CLOSE;
       }
       else {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         result = sshc->actualcode;
       }
       break;
@@ -2470,16 +2496,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       }
 
       Curl_safefree(sshc->homedir);
-      conn->data->state.most_recent_ftp_entrypath = NULL;
+      data->state.most_recent_ftp_entrypath = NULL;
 
-      state(conn, SSH_SESSION_DISCONNECT);
+      state(data, SSH_SESSION_DISCONNECT);
       break;
 
     case SSH_SCP_TRANS_INIT:
-      result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+      result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
       if(result) {
         sshc->actualcode = result;
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
 
@@ -2487,13 +2513,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         if(data->state.infilesize < 0) {
           failf(data, "SCP requires a known file size for upload");
           sshc->actualcode = CURLE_UPLOAD_FAILED;
-          state(conn, SSH_SCP_CHANNEL_FREE);
+          state(data, SSH_SCP_CHANNEL_FREE);
           break;
         }
-        state(conn, SSH_SCP_UPLOAD_INIT);
+        state(data, SSH_SCP_UPLOAD_INIT);
       }
       else {
-        state(conn, SSH_SCP_DOWNLOAD_INIT);
+        state(data, SSH_SCP_DOWNLOAD_INIT);
       }
       break;
 
@@ -2505,7 +2531,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
        * directory in the path.
        */
       sshc->ssh_channel =
-        SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms,
+        SCP_SEND(sshc->ssh_session, sshp->path, data->set.new_file_perms,
                  data->state.infilesize);
       if(!sshc->ssh_channel) {
         int ssh_err;
@@ -2519,8 +2545,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
 
         ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
                                                    &err_msg, NULL, 0));
-        failf(conn->data, "%s", err_msg);
-        state(conn, SSH_SCP_CHANNEL_FREE);
+        failf(data, "%s", err_msg);
+        state(data, SSH_SCP_CHANNEL_FREE);
         sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
         /* Map generic errors to upload failed */
         if(sshc->actualcode == CURLE_SSH ||
@@ -2538,7 +2564,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       conn->sockfd = conn->writesockfd;
 
       if(result) {
-        state(conn, SSH_SCP_CHANNEL_FREE);
+        state(data, SSH_SCP_CHANNEL_FREE);
         sshc->actualcode = result;
       }
       else {
@@ -2551,7 +2577,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
            with both accordingly */
         conn->cselect_bits = CURL_CSELECT_OUT;
 
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
       }
       break;
 
@@ -2573,12 +2599,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       struct stat sb;
       memset(&sb, 0, sizeof(struct stat));
       sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
-                                           sftp_scp->path, &sb);
+                                           sshp->path, &sb);
 #else
       libssh2_struct_stat sb;
       memset(&sb, 0, sizeof(libssh2_struct_stat));
       sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session,
-                                            sftp_scp->path, &sb);
+                                            sshp->path, &sb);
 #endif
 
       if(!sshc->ssh_channel) {
@@ -2594,8 +2620,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
 
         ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
                                                    &err_msg, NULL, 0));
-        failf(conn->data, "%s", err_msg);
-        state(conn, SSH_SCP_CHANNEL_FREE);
+        failf(data, "%s", err_msg);
+        state(data, SSH_SCP_CHANNEL_FREE);
         sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
         break;
       }
@@ -2614,19 +2640,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       conn->cselect_bits = CURL_CSELECT_IN;
 
       if(result) {
-        state(conn, SSH_SCP_CHANNEL_FREE);
+        state(data, SSH_SCP_CHANNEL_FREE);
         sshc->actualcode = result;
       }
       else
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
     }
     break;
 
     case SSH_SCP_DONE:
       if(data->set.upload)
-        state(conn, SSH_SCP_SEND_EOF);
+        state(data, SSH_SCP_SEND_EOF);
       else
-        state(conn, SSH_SCP_CHANNEL_FREE);
+        state(data, SSH_SCP_CHANNEL_FREE);
       break;
 
     case SSH_SCP_SEND_EOF:
@@ -2643,7 +2669,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
                 rc, err_msg);
         }
       }
-      state(conn, SSH_SCP_WAIT_EOF);
+      state(data, SSH_SCP_WAIT_EOF);
       break;
 
     case SSH_SCP_WAIT_EOF:
@@ -2659,7 +2685,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           infof(data, "Failed to get channel EOF: %d %s\n", rc, err_msg);
         }
       }
-      state(conn, SSH_SCP_WAIT_CLOSE);
+      state(data, SSH_SCP_WAIT_CLOSE);
       break;
 
     case SSH_SCP_WAIT_CLOSE:
@@ -2675,7 +2701,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           infof(data, "Channel failed to close: %d %s\n", rc, err_msg);
         }
       }
-      state(conn, SSH_SCP_CHANNEL_FREE);
+      state(data, SSH_SCP_CHANNEL_FREE);
       break;
 
     case SSH_SCP_CHANNEL_FREE:
@@ -2695,9 +2721,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       }
       DEBUGF(infof(data, "SCP DONE phase complete\n"));
 #if 0 /* PREV */
-      state(conn, SSH_SESSION_DISCONNECT);
+      state(data, SSH_SESSION_DISCONNECT);
 #endif
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       result = sshc->actualcode;
       break;
 
@@ -2735,9 +2761,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       }
 
       Curl_safefree(sshc->homedir);
-      conn->data->state.most_recent_ftp_entrypath = NULL;
+      data->state.most_recent_ftp_entrypath = NULL;
 
-      state(conn, SSH_SESSION_FREE);
+      state(data, SSH_SESSION_FREE);
       break;
 
     case SSH_SESSION_FREE:
@@ -2805,11 +2831,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       Curl_safefree(sshc->quote_path2);
 
       Curl_safefree(sshc->homedir);
-
-      Curl_safefree(sshc->readdir_filename);
-      Curl_safefree(sshc->readdir_longentry);
       Curl_safefree(sshc->readdir_line);
-      Curl_dyn_free(&sshc->readdir);
 
       /* the code we are about to return */
       result = sshc->actualcode;
@@ -2819,7 +2841,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       connclose(conn, "SSH session free");
       sshc->state = SSH_SESSION_FREE; /* current */
       sshc->nextstate = SSH_NO_STATE;
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
 
     case SSH_QUIT:
@@ -2827,7 +2849,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     default:
       /* internal error */
       sshc->nextstate = SSH_NO_STATE;
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
     }
 
@@ -2844,11 +2866,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
 
 /* called by the multi interface to figure out what socket(s) to wait for and
    for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
-static int ssh_perform_getsock(const struct connectdata *conn,
-                               curl_socket_t *sock)
+static int ssh_getsock(struct Curl_easy *data,
+                       struct connectdata *conn,
+                       curl_socket_t *sock)
 {
-#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
   int bitmap = GETSOCK_BLANK;
+  (void)data;
 
   sock[0] = conn->sock[FIRSTSOCKET];
 
@@ -2859,32 +2882,8 @@ static int ssh_perform_getsock(const struct connectdata *conn,
     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
 
   return bitmap;
-#else
-  /* if we don't know the direction we can use the generic *_getsock()
-     function even for the protocol_connect and doing states */
-  return Curl_single_getsock(conn, sock);
-#endif
-}
-
-/* Generic function called by the multi interface to figure out what socket(s)
-   to wait for and for what actions during the DOING and PROTOCONNECT states*/
-static int ssh_getsock(struct connectdata *conn,
-                       curl_socket_t *sock)
-{
-#ifndef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
-  (void)conn;
-  (void)sock;
-  /* if we don't know any direction we can just play along as we used to and
-     not provide any sensible info */
-  return GETSOCK_BLANK;
-#else
-  /* if we know the direction we can use the generic *_getsock() function even
-     for the protocol_connect and doing states */
-  return ssh_perform_getsock(conn, sock);
-#endif
 }
 
-#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
 /*
  * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
  * function is used to figure out in what direction and stores this info so
@@ -2892,8 +2891,9 @@ static int ssh_getsock(struct connectdata *conn,
  * function in all cases so that when it _doesn't_ return EAGAIN we can
  * restore the default wait bits.
  */
-static void ssh_block2waitfor(struct connectdata *conn, bool block)
+static void ssh_block2waitfor(struct Curl_easy *data, bool block)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   int dir = 0;
   if(block) {
@@ -2909,46 +2909,43 @@ static void ssh_block2waitfor(struct connectdata *conn, bool block)
        the original set */
     conn->waitfor = sshc->orig_waitfor;
 }
-#else
-  /* no libssh2 directional support so we simply don't know */
-#define ssh_block2waitfor(x,y) Curl_nop_stmt
-#endif
 
 /* called repeatedly until done from multi.c */
-static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
+static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result = CURLE_OK;
   bool block; /* we store the status and use that to provide a ssh_getsock()
                  implementation */
   do {
-    result = ssh_statemach_act(conn, &block);
+    result = ssh_statemach_act(data, &block);
     *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
     /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
        try again */
   } while(!result && !*done && !block);
-  ssh_block2waitfor(conn, block);
+  ssh_block2waitfor(data, block);
 
   return result;
 }
 
-static CURLcode ssh_block_statemach(struct connectdata *conn,
-                                   bool duringconnect)
+static CURLcode ssh_block_statemach(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    bool duringconnect)
 {
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
   while((sshc->state != SSH_STOP) && !result) {
     bool block;
     timediff_t left = 1000;
     struct curltime now = Curl_now();
 
-    result = ssh_statemach_act(conn, &block);
+    result = ssh_statemach_act(data, &block);
     if(result)
       break;
 
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       return CURLE_ABORTED_BY_CALLBACK;
 
     result = Curl_speedcheck(data, now);
@@ -2961,7 +2958,6 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
       return CURLE_OPERATION_TIMEDOUT;
     }
 
-#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
     if(block) {
       int dir = libssh2_session_block_directions(sshc->ssh_session);
       curl_socket_t sock = conn->sock[FIRSTSOCKET];
@@ -2975,8 +2971,6 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
       (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
                               left>1000?1000:left);
     }
-#endif
-
   }
 
   return result;
@@ -2985,11 +2979,13 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
 /*
  * SSH setup and connection
  */
-static CURLcode ssh_setup_connection(struct connectdata *conn)
+static CURLcode ssh_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn)
 {
   struct SSHPROTO *ssh;
+  (void)conn;
 
-  conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
+  data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
   if(!ssh)
     return CURLE_OUT_OF_MEMORY;
 
@@ -2999,36 +2995,83 @@ static CURLcode ssh_setup_connection(struct connectdata *conn)
 static Curl_recv scp_recv, sftp_recv;
 static Curl_send scp_send, sftp_send;
 
+#ifndef CURL_DISABLE_PROXY
+static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer,
+                            size_t length, int flags, void **abstract)
+{
+  struct Curl_easy *data = (struct Curl_easy *)*abstract;
+  ssize_t nread;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+  Curl_recv *backup = conn->recv[0];
+  struct ssh_conn *ssh = &conn->proto.sshc;
+  (void)flags;
+
+  /* swap in the TLS reader function for this call only, and then swap back
+     the SSH one again */
+  conn->recv[0] = ssh->tls_recv;
+  result = Curl_read(data, sock, buffer, length, &nread);
+  conn->recv[0] = backup;
+  if(result == CURLE_AGAIN)
+    return -EAGAIN; /* magic return code for libssh2 */
+  else if(result)
+    return -1; /* generic error */
+  Curl_debug(data, CURLINFO_DATA_IN, (char *)buffer, (size_t)nread);
+  return nread;
+}
+
+static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer,
+                            size_t length, int flags, void **abstract)
+{
+  struct Curl_easy *data = (struct Curl_easy *)*abstract;
+  ssize_t nwrite;
+  CURLcode result;
+  struct connectdata *conn = data->conn;
+  Curl_send *backup = conn->send[0];
+  struct ssh_conn *ssh = &conn->proto.sshc;
+  (void)flags;
+
+  /* swap in the TLS writer function for this call only, and then swap back
+     the SSH one again */
+  conn->send[0] = ssh->tls_send;
+  result = Curl_write(data, sock, buffer, length, &nwrite);
+  conn->send[0] = backup;
+  if(result == CURLE_AGAIN)
+    return -EAGAIN; /* magic return code for libssh2 */
+  else if(result)
+    return -1; /* error */
+  Curl_debug(data, CURLINFO_DATA_OUT, (char *)buffer, (size_t)nwrite);
+  return nwrite;
+}
+#endif
+
 /*
  * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
  * do protocol-specific actions at connect-time.
  */
-static CURLcode ssh_connect(struct connectdata *conn, bool *done)
+static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
 {
 #ifdef CURL_LIBSSH2_DEBUG
   curl_socket_t sock;
 #endif
-  struct ssh_conn *ssh;
+  struct SSHPROTO *sshp = data->req.p.ssh;
+  struct ssh_conn *sshc;
   CURLcode result;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   /* initialize per-handle data if not already */
-  if(!data->req.protop)
-    ssh_setup_connection(conn);
+  if(!sshp) {
+    result = ssh_setup_connection(data, conn);
+    if(result)
+      return result;
+    sshp = data->req.p.ssh;
+  }
 
   /* We default to persistent connections. We set this already in this connect
      function to make the re-use checks properly be able to check this bit. */
   connkeep(conn, "SSH default");
 
-  if(conn->handler->protocol & CURLPROTO_SCP) {
-    conn->recv[FIRSTSOCKET] = scp_recv;
-    conn->send[FIRSTSOCKET] = scp_send;
-  }
-  else {
-    conn->recv[FIRSTSOCKET] = sftp_recv;
-    conn->send[FIRSTSOCKET] = sftp_send;
-  }
-  ssh = &conn->proto.sshc;
+  sshc = &conn->proto.sshc;
 
 #ifdef CURL_LIBSSH2_DEBUG
   if(conn->user) {
@@ -3040,17 +3083,72 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
   sock = conn->sock[FIRSTSOCKET];
 #endif /* CURL_LIBSSH2_DEBUG */
 
-  ssh->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
-                                             my_libssh2_free,
-                                             my_libssh2_realloc, conn);
-  if(ssh->ssh_session == NULL) {
+  sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
+                                              my_libssh2_free,
+                                              my_libssh2_realloc, data);
+  if(sshc->ssh_session == NULL) {
     failf(data, "Failure initialising ssh session");
     return CURLE_FAILED_INIT;
   }
 
+#ifndef CURL_DISABLE_PROXY
+  if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
+    /*
+     * This crazy union dance is here to avoid assigning a void pointer a
+     * function pointer as it is invalid C. The problem is of course that
+     * libssh2 has such an API...
+     */
+    union receive {
+      void *recvp;
+      ssize_t (*recvptr)(libssh2_socket_t, void *, size_t, int, void **);
+    };
+    union transfer {
+      void *sendp;
+      ssize_t (*sendptr)(libssh2_socket_t, const void *, size_t, int, void **);
+    };
+    union receive sshrecv;
+    union transfer sshsend;
+
+    sshrecv.recvptr = ssh_tls_recv;
+    sshsend.sendptr = ssh_tls_send;
+
+    infof(data, "Uses HTTPS proxy!\n");
+    /*
+      Setup libssh2 callbacks to make it read/write TLS from the socket.
+
+      ssize_t
+      recvcb(libssh2_socket_t sock, void *buffer, size_t length,
+      int flags, void **abstract);
+
+      ssize_t
+      sendcb(libssh2_socket_t sock, const void *buffer, size_t length,
+      int flags, void **abstract);
+
+    */
+    libssh2_session_callback_set(sshc->ssh_session,
+                                 LIBSSH2_CALLBACK_RECV, sshrecv.recvp);
+    libssh2_session_callback_set(sshc->ssh_session,
+                                 LIBSSH2_CALLBACK_SEND, sshsend.sendp);
+
+    /* Store the underlying TLS recv/send function pointers to be used when
+       reading from the proxy */
+    sshc->tls_recv = conn->recv[FIRSTSOCKET];
+    sshc->tls_send = conn->send[FIRSTSOCKET];
+  }
+
+#endif /* CURL_DISABLE_PROXY */
+  if(conn->handler->protocol & CURLPROTO_SCP) {
+    conn->recv[FIRSTSOCKET] = scp_recv;
+    conn->send[FIRSTSOCKET] = scp_send;
+  }
+  else {
+    conn->recv[FIRSTSOCKET] = sftp_recv;
+    conn->send[FIRSTSOCKET] = sftp_send;
+  }
+
   if(data->set.ssh_compression) {
 #if LIBSSH2_VERSION_NUM >= 0x010208
-    if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
+    if(libssh2_session_flag(sshc->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
 #endif
       infof(data, "Failed to enable compression for ssh session\n");
   }
@@ -3058,14 +3156,14 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
     int rc;
-    ssh->kh = libssh2_knownhost_init(ssh->ssh_session);
-    if(!ssh->kh) {
-      libssh2_session_free(ssh->ssh_session);
+    sshc->kh = libssh2_knownhost_init(sshc->ssh_session);
+    if(!sshc->kh) {
+      libssh2_session_free(sshc->ssh_session);
       return CURLE_FAILED_INIT;
     }
 
     /* read all known hosts from there */
-    rc = libssh2_knownhost_readfile(ssh->kh,
+    rc = libssh2_knownhost_readfile(sshc->kh,
                                     data->set.str[STRING_SSH_KNOWNHOSTS],
                                     LIBSSH2_KNOWNHOST_FILE_OPENSSH);
     if(rc < 0)
@@ -3075,13 +3173,13 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
 #endif /* HAVE_LIBSSH2_KNOWNHOST_API */
 
 #ifdef CURL_LIBSSH2_DEBUG
-  libssh2_trace(ssh->ssh_session, ~0);
+  libssh2_trace(sshc->ssh_session, ~0);
   infof(data, "SSH socket: %d\n", (int)sock);
 #endif /* CURL_LIBSSH2_DEBUG */
 
-  state(conn, SSH_INIT);
+  state(data, SSH_INIT);
 
-  result = ssh_multi_statemach(conn, done);
+  result = ssh_multi_statemach(data, done);
 
   return result;
 }
@@ -3096,40 +3194,41 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
  */
 
 static
-CURLcode scp_perform(struct connectdata *conn,
-                      bool *connected,
-                      bool *dophase_done)
+CURLcode scp_perform(struct Curl_easy *data,
+                     bool *connected,
+                     bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
   *dophase_done = FALSE; /* not done yet */
 
   /* start the first command in the DO phase */
-  state(conn, SSH_SCP_TRANS_INIT);
+  state(data, SSH_SCP_TRANS_INIT);
 
   /* run the state-machine */
-  result = ssh_multi_statemach(conn, dophase_done);
+  result = ssh_multi_statemach(data, dophase_done);
 
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
 }
 
 /* called from multi.c while DOing */
-static CURLcode scp_doing(struct connectdata *conn,
-                               bool *dophase_done)
+static CURLcode scp_doing(struct Curl_easy *data,
+                          bool *dophase_done)
 {
   CURLcode result;
-  result = ssh_multi_statemach(conn, dophase_done);
+  result = ssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
   return result;
 }
@@ -3139,11 +3238,11 @@ static CURLcode scp_doing(struct connectdata *conn,
  * separate ones but this way means less duplicated code.
  */
 
-static CURLcode ssh_do(struct connectdata *conn, bool *done)
+static CURLcode ssh_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
   bool connected = 0;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
   *done = FALSE; /* default to false */
@@ -3160,9 +3259,9 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done)
   Curl_pgrsSetDownloadSize(data, -1);
 
   if(conn->handler->protocol & CURLPROTO_SCP)
-    result = scp_perform(conn, &connected,  done);
+    result = scp_perform(data, &connected,  done);
   else
-    result = sftp_perform(conn, &connected,  done);
+    result = sftp_perform(data, &connected,  done);
 
   return result;
 }
@@ -3170,18 +3269,20 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done)
 /* BLOCKING, but the function is using the state machine so the only reason
    this is still blocking is that the multi interface code has no support for
    disconnecting operations that takes a while */
-static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode scp_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool dead_connection)
 {
   CURLcode result = CURLE_OK;
-  struct ssh_conn *ssh = &conn->proto.sshc;
+  struct ssh_conn *sshc = &conn->proto.sshc;
   (void) dead_connection;
 
-  if(ssh->ssh_session) {
+  if(sshc->ssh_session) {
     /* only if there's a session still around to use! */
 
-    state(conn, SSH_SESSION_DISCONNECT);
+    state(data, SSH_SESSION_DISCONNECT);
 
-    result = ssh_block_statemach(conn, FALSE);
+    result = ssh_block_statemach(data, conn, FALSE);
   }
 
   return result;
@@ -3189,51 +3290,56 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
 
 /* generic done function for both SCP and SFTP called from their specific
    done functions */
-static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
+static CURLcode ssh_done(struct Curl_easy *data, CURLcode status)
 {
   CURLcode result = CURLE_OK;
-  struct SSHPROTO *sftp_scp = conn->data->req.protop;
+  struct SSHPROTO *sshp = data->req.p.ssh;
+  struct connectdata *conn = data->conn;
 
   if(!status) {
     /* run the state-machine */
-    result = ssh_block_statemach(conn, FALSE);
+    result = ssh_block_statemach(data, conn, FALSE);
   }
   else
     result = status;
 
-  if(sftp_scp)
-    Curl_safefree(sftp_scp->path);
-  if(Curl_pgrsDone(conn))
+  Curl_safefree(sshp->path);
+  Curl_safefree(sshp->readdir_filename);
+  Curl_safefree(sshp->readdir_longentry);
+  Curl_dyn_free(&sshp->readdir);
+
+  if(Curl_pgrsDone(data))
     return CURLE_ABORTED_BY_CALLBACK;
 
-  conn->data->req.keepon = 0; /* clear all bits */
+  data->req.keepon = 0; /* clear all bits */
   return result;
 }
 
 
-static CURLcode scp_done(struct connectdata *conn, CURLcode status,
+static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
                          bool premature)
 {
   (void)premature; /* not used */
 
   if(!status)
-    state(conn, SSH_SCP_DONE);
+    state(data, SSH_SCP_DONE);
 
-  return ssh_done(conn, status);
+  return ssh_done(data, status);
 
 }
 
-static ssize_t scp_send(struct connectdata *conn, int sockindex,
+static ssize_t scp_send(struct Curl_easy *data, int sockindex,
                         const void *mem, size_t len, CURLcode *err)
 {
   ssize_t nwrite;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
   (void)sockindex; /* we only support SCP on the fixed known primary socket */
 
   /* libssh2_channel_write() returns int! */
-  nwrite = (ssize_t)
-    libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len);
+  nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
 
-  ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
 
   if(nwrite == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
@@ -3247,17 +3353,18 @@ static ssize_t scp_send(struct connectdata *conn, int sockindex,
   return nwrite;
 }
 
-static ssize_t scp_recv(struct connectdata *conn, int sockindex,
+static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
                         char *mem, size_t len, CURLcode *err)
 {
   ssize_t nread;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
   (void)sockindex; /* we only support SCP on the fixed known primary socket */
 
   /* libssh2_channel_read() returns int */
-  nread = (ssize_t)
-    libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
+  nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len);
 
-  ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
   if(nread == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
     nread = -1;
@@ -3280,39 +3387,39 @@ static ssize_t scp_recv(struct connectdata *conn, int sockindex,
  */
 
 static
-CURLcode sftp_perform(struct connectdata *conn,
+CURLcode sftp_perform(struct Curl_easy *data,
                       bool *connected,
                       bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
   *dophase_done = FALSE; /* not done yet */
 
   /* start the first command in the DO phase */
-  state(conn, SSH_SFTP_QUOTE_INIT);
+  state(data, SSH_SFTP_QUOTE_INIT);
 
   /* run the state-machine */
-  result = ssh_multi_statemach(conn, dophase_done);
+  result = ssh_multi_statemach(data, dophase_done);
 
-  *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+  *connected = data->conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
 }
 
 /* called from multi.c while DOing */
-static CURLcode sftp_doing(struct connectdata *conn,
+static CURLcode sftp_doing(struct Curl_easy *data,
                            bool *dophase_done)
 {
-  CURLcode result = ssh_multi_statemach(conn, dophase_done);
+  CURLcode result = ssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
   return result;
 }
@@ -3320,53 +3427,56 @@ static CURLcode sftp_doing(struct connectdata *conn,
 /* BLOCKING, but the function is using the state machine so the only reason
    this is still blocking is that the multi interface code has no support for
    disconnecting operations that takes a while */
-static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode sftp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
 {
   CURLcode result = CURLE_OK;
+  struct ssh_conn *sshc = &conn->proto.sshc;
   (void) dead_connection;
 
-  DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
 
-  if(conn->proto.sshc.ssh_session) {
+  if(sshc->ssh_session) {
     /* only if there's a session still around to use! */
-    state(conn, SSH_SFTP_SHUTDOWN);
-    result = ssh_block_statemach(conn, FALSE);
+    state(data, SSH_SFTP_SHUTDOWN);
+    result = ssh_block_statemach(data, conn, FALSE);
   }
 
-  DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
 
   return result;
 
 }
 
-static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
+static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
                                bool premature)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
   if(!status) {
     /* Post quote commands are executed after the SFTP_CLOSE state to avoid
        errors that could happen due to open file handles during POSTQUOTE
        operation */
-    if(!premature && conn->data->set.postquote && !conn->bits.retry)
+    if(!premature && data->set.postquote && !conn->bits.retry)
       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
-    state(conn, SSH_SFTP_CLOSE);
+    state(data, SSH_SFTP_CLOSE);
   }
-  return ssh_done(conn, status);
+  return ssh_done(data, status);
 }
 
 /* return number of sent bytes */
-static ssize_t sftp_send(struct connectdata *conn, int sockindex,
+static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
                          const void *mem, size_t len, CURLcode *err)
 {
-  ssize_t nwrite;   /* libssh2_sftp_write() used to return size_t in 0.14
-                       but is changed to ssize_t in 0.15. These days we don't
-                       support libssh2 0.15*/
+  ssize_t nwrite;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
   (void)sockindex;
 
-  nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len);
+  nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
 
-  ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
 
   if(nwrite == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
@@ -3384,15 +3494,17 @@ static ssize_t sftp_send(struct connectdata *conn, int sockindex,
  * Return number of received (decrypted) bytes
  * or <0 on error
  */
-static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
+static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
                          char *mem, size_t len, CURLcode *err)
 {
   ssize_t nread;
+  struct connectdata *conn = data->conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
   (void)sockindex;
 
-  nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len);
+  nread = libssh2_sftp_read(sshc->sftp_handle, mem, len);
 
-  ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+  ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
 
   if(nread == LIBSSH2_ERROR_EAGAIN) {
     *err = CURLE_AGAIN;
index 9e49993..52e1ee6 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -111,6 +111,17 @@ typedef enum {
    struct. */
 struct SSHPROTO {
   char *path;                  /* the path we operate on */
+#ifdef USE_LIBSSH2
+  struct dynbuf readdir_link;
+  struct dynbuf readdir;
+  char *readdir_filename;
+  char *readdir_longentry;
+
+  LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
+
+  /* Here's a set of struct members used by the SFTP_READDIR state */
+  LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
+#endif
 };
 
 /* ssh_conn is used for struct connection-oriented data in the connectdata
@@ -123,6 +134,8 @@ struct ssh_conn {
   char *rsa_pub;              /* path name */
   char *rsa;                  /* path name */
   bool authed;                /* the connection has been authenticated fine */
+  bool acceptfail;            /* used by the SFTP_QUOTE (continue if
+                                 quote command fails) */
   sshstate state;             /* always use ssh.c:state() to change state! */
   sshstate nextstate;         /* the state to goto after stopping */
   CURLcode actualcode;        /* the actual error code */
@@ -130,8 +143,6 @@ struct ssh_conn {
   char *quote_path1;          /* two generic pointers for the QUOTE stuff */
   char *quote_path2;
 
-  bool acceptfail;            /* used by the SFTP_QUOTE (continue if
-                                 quote command fails) */
   char *homedir;              /* when doing SFTP we figure out home dir in the
                                  connect phase */
   char *readdir_line;
@@ -140,9 +151,8 @@ struct ssh_conn {
   int secondCreateDirs;         /* counter use by the code to see if the
                                    second attempt has been made to change
                                    to/create a directory */
-  char *slash_pos;              /* used by the SFTP_CREATE_DIRS state */
-
   int orig_waitfor;             /* default READ/WRITE bits wait for */
+  char *slash_pos;              /* used by the SFTP_CREATE_DIRS state */
 
 #if defined(USE_LIBSSH)
   char *readdir_linkPath;
@@ -168,20 +178,17 @@ struct ssh_conn {
   const char *readdir_longentry;
   char *readdir_tmp;
 #elif defined(USE_LIBSSH2)
-  struct dynbuf readdir_link;
-  struct dynbuf readdir;
-  char *readdir_filename;
-  char *readdir_longentry;
-
-  LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
-
-  /* Here's a set of struct members used by the SFTP_READDIR state */
-  LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
   LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
   LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
   LIBSSH2_SFTP *sftp_session;   /* SFTP handle */
   LIBSSH2_SFTP_HANDLE *sftp_handle;
 
+#ifndef CURL_DISABLE_PROXY
+  /* for HTTPS proxy storage */
+  Curl_recv *tls_recv;
+  Curl_send *tls_send;
+#endif
+
 #ifdef HAVE_LIBSSH2_AGENT_API
   LIBSSH2_AGENT *ssh_agent;     /* proxy to ssh-agent/pageant */
   struct libssh2_agent_publickey *sshagent_identity,
index dcbbab6..6020180 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 #include "curl_memory.h"
 #include "memdebug.h"
 
-static CURLcode wssh_connect(struct connectdata *conn, bool *done);
-static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done);
-static CURLcode wssh_do(struct connectdata *conn, bool *done);
+static CURLcode wssh_connect(struct Curl_easy *data, bool *done);
+static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done);
+static CURLcode wssh_do(struct Curl_easy *data, bool *done);
 #if 0
-static CURLcode wscp_done(struct connectdata *conn,
+static CURLcode wscp_done(struct Curl_easy *data,
                           CURLcode, bool premature);
-static CURLcode wscp_doing(struct connectdata *conn,
+static CURLcode wscp_doing(struct Curl_easy *data,
                            bool *dophase_done);
-static CURLcode wscp_disconnect(struct connectdata *conn,
+static CURLcode wscp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection);
 #endif
-static CURLcode wsftp_done(struct connectdata *conn,
+static CURLcode wsftp_done(struct Curl_easy *data,
                            CURLcode, bool premature);
-static CURLcode wsftp_doing(struct connectdata *conn,
+static CURLcode wsftp_doing(struct Curl_easy *data,
                             bool *dophase_done);
-static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead);
-static int wssh_getsock(struct connectdata *conn,
+static CURLcode wsftp_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
+                                 bool dead);
+static int wssh_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
                         curl_socket_t *sock);
-static int wssh_perform_getsock(const struct connectdata *conn,
-                                curl_socket_t *sock);
-static CURLcode wssh_setup_connection(struct connectdata *conn);
+static CURLcode wssh_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
 
 #if 0
 /*
@@ -84,7 +87,7 @@ const struct Curl_handler Curl_handler_scp = {
   wssh_getsock,                         /* proto_getsock */
   wssh_getsock,                         /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  wssh_perform_getsock,                 /* perform_getsock */
+  wssh_getsock,                         /* perform_getsock */
   wscp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
@@ -112,12 +115,13 @@ const struct Curl_handler Curl_handler_sftp = {
   wssh_getsock,                         /* proto_getsock */
   wssh_getsock,                         /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  wssh_perform_getsock,                 /* perform_getsock */
+  wssh_getsock,                         /* perform_getsock */
   wsftp_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   PORT_SSH,                             /* defport */
   CURLPROTO_SFTP,                       /* protocol */
+  CURLPROTO_SFTP,                       /* family */
   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
   | PROTOPT_NOURLQUERY                  /* flags */
 };
@@ -126,8 +130,9 @@ const struct Curl_handler Curl_handler_sftp = {
  * SSH State machine related code
  */
 /* This is the ONLY way to change SSH state! */
-static void state(struct connectdata *conn, sshstate nowstate)
+static void state(struct Curl_easy *data, sshstate nowstate)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
@@ -198,7 +203,7 @@ static void state(struct connectdata *conn, sshstate nowstate)
   DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
 
   if(sshc->state != nowstate) {
-    infof(conn->data, "wolfssh %p state change from %s to %s\n",
+    infof(data, "wolfssh %p state change from %s to %s\n",
           (void *)sshc, names[sshc->state], names[nowstate]);
   }
 #endif
@@ -206,11 +211,11 @@ static void state(struct connectdata *conn, sshstate nowstate)
   sshc->state = nowstate;
 }
 
-static ssize_t wscp_send(struct connectdata *conn, int sockindex,
+static ssize_t wscp_send(struct Curl_easy *data, int sockindex,
                          const void *mem, size_t len, CURLcode *err)
 {
   ssize_t nwrite = 0;
-  (void)conn;
+  (void)data;
   (void)sockindex; /* we only support SCP on the fixed known primary socket */
   (void)mem;
   (void)len;
@@ -219,11 +224,11 @@ static ssize_t wscp_send(struct connectdata *conn, int sockindex,
   return nwrite;
 }
 
-static ssize_t wscp_recv(struct connectdata *conn, int sockindex,
+static ssize_t wscp_recv(struct Curl_easy *data, int sockindex,
                          char *mem, size_t len, CURLcode *err)
 {
   ssize_t nread = 0;
-  (void)conn;
+  (void)data;
   (void)sockindex; /* we only support SCP on the fixed known primary socket */
   (void)mem;
   (void)len;
@@ -233,9 +238,10 @@ static ssize_t wscp_recv(struct connectdata *conn, int sockindex,
 }
 
 /* return number of sent bytes */
-static ssize_t wsftp_send(struct connectdata *conn, int sockindex,
+static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
                           const void *mem, size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   word32 offset[2];
   int rc;
@@ -262,11 +268,11 @@ static ssize_t wsftp_send(struct connectdata *conn, int sockindex,
     return -1;
   }
   if(rc < 0) {
-    failf(conn->data, "wolfSSH_SFTP_SendWritePacket returned %d\n", rc);
+    failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc);
     return -1;
   }
   DEBUGASSERT(rc == (int)len);
-  infof(conn->data, "sent %zd bytes SFTP from offset %zd\n",
+  infof(data, "sent %zd bytes SFTP from offset %zd\n",
         len, sshc->offset);
   sshc->offset += len;
   return (ssize_t)rc;
@@ -276,10 +282,11 @@ static ssize_t wsftp_send(struct connectdata *conn, int sockindex,
  * Return number of received (decrypted) bytes
  * or <0 on error
  */
-static ssize_t wsftp_recv(struct connectdata *conn, int sockindex,
+static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex,
                           char *mem, size_t len, CURLcode *err)
 {
   int rc;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   word32 offset[2];
   (void)sockindex;
@@ -307,7 +314,7 @@ static ssize_t wsftp_recv(struct connectdata *conn, int sockindex,
   DEBUGASSERT(rc <= (int)len);
 
   if(rc < 0) {
-    failf(conn->data, "wolfSSH_SFTP_SendReadPacket returned %d\n", rc);
+    failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc);
     return -1;
   }
   sshc->offset += len;
@@ -318,11 +325,13 @@ static ssize_t wsftp_recv(struct connectdata *conn, int sockindex,
 /*
  * SSH setup and connection
  */
-static CURLcode wssh_setup_connection(struct connectdata *conn)
+static CURLcode wssh_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   struct SSHPROTO *ssh;
+  (void)conn;
 
-  conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
+  data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
   if(!ssh)
     return CURLE_OUT_OF_MEMORY;
 
@@ -336,28 +345,28 @@ static int userauth(byte authtype,
                     WS_UserAuthData* authdata,
                     void *ctx)
 {
-  struct connectdata *conn = ctx;
-  DEBUGF(infof(conn->data, "wolfssh callback: type %s\n",
+  struct Curl_easy *data = ctx;
+  DEBUGF(infof(data, "wolfssh callback: type %s\n",
                authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" :
                "PUBLICCKEY"));
   if(authtype == WOLFSSH_USERAUTH_PASSWORD) {
-    authdata->sf.password.password = (byte *)conn->passwd;
-    authdata->sf.password.passwordSz = (word32) strlen(conn->passwd);
+    authdata->sf.password.password = (byte *)data->conn->passwd;
+    authdata->sf.password.passwordSz = (word32) strlen(data->conn->passwd);
   }
 
   return 0;
 }
 
-static CURLcode wssh_connect(struct connectdata *conn, bool *done)
+static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   int rc;
 
   /* initialize per-handle data if not already */
-  if(!data->req.protop)
-    wssh_setup_connection(conn);
+  if(!data->req.p.ssh)
+    wssh_setup_connection(data, conn);
 
   /* We default to persistent connections. We set this already in this connect
      function to make the re-use checks properly be able to check this bit. */
@@ -392,7 +401,7 @@ static CURLcode wssh_connect(struct connectdata *conn, bool *done)
 
   /* set callback for authentication */
   wolfSSH_SetUserAuth(sshc->ctx, userauth);
-  wolfSSH_SetUserAuthCtx(sshc->ssh_session, conn);
+  wolfSSH_SetUserAuthCtx(sshc->ssh_session, data);
 
   rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock);
   if(rc) {
@@ -406,11 +415,11 @@ static CURLcode wssh_connect(struct connectdata *conn, bool *done)
 
   *done = TRUE;
   if(conn->handler->protocol & CURLPROTO_SCP)
-    state(conn, SSH_INIT);
+    state(data, SSH_INIT);
   else
-    state(conn, SSH_SFTP_INIT);
+    state(data, SSH_SFTP_INIT);
 
-  return wssh_multi_statemach(conn, done);
+  return wssh_multi_statemach(data, done);
   error:
   wolfSSH_free(sshc->ssh_session);
   wolfSSH_CTX_free(sshc->ctx);
@@ -424,12 +433,12 @@ static CURLcode wssh_connect(struct connectdata *conn, bool *done)
  * wants to be called again when the socket is ready
  */
 
-static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
+static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
-  struct Curl_easy *data = conn->data;
-  struct SSHPROTO *sftp_scp = data->req.protop;
+  struct SSHPROTO *sftp_scp = data->req.p.ssh;
   WS_SFTPNAME *name;
   int rc = 0;
   *block = FALSE; /* we're not blocking by default */
@@ -437,7 +446,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
   do {
     switch(sshc->state) {
     case SSH_INIT:
-      state(conn, SSH_S_STARTUP);
+      state(data, SSH_S_STARTUP);
       /* FALLTHROUGH */
     case SSH_S_STARTUP:
       rc = wolfSSH_connect(sshc->ssh_session);
@@ -454,11 +463,11 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
         return CURLE_OK;
       }
       else if(rc != WS_SUCCESS) {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         return CURLE_SSH;
       }
       infof(data, "wolfssh connected!\n");
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       break;
     case SSH_STOP:
       break;
@@ -479,7 +488,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
       }
       else if(rc == WS_SUCCESS) {
         infof(data, "wolfssh SFTP connected!\n");
-        state(conn, SSH_SFTP_REALPATH);
+        state(data, SSH_SFTP_REALPATH);
       }
       else {
         failf(data, "wolfssh SFTP connect error %d", rc);
@@ -510,45 +519,45 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
           infof(data, "wolfssh SFTP realpath succeeded!\n");
         }
         wolfSSH_SFTPNAME_list_free(name);
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         return CURLE_OK;
       }
       failf(data, "wolfssh SFTP realpath %d", rc);
       return CURLE_SSH;
 
     case SSH_SFTP_QUOTE_INIT:
-      result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+      result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path);
       if(result) {
         sshc->actualcode = result;
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
 
       if(data->set.quote) {
         infof(data, "Sending quote commands\n");
         sshc->quote_item = data->set.quote;
-        state(conn, SSH_SFTP_QUOTE);
+        state(data, SSH_SFTP_QUOTE);
       }
       else {
-        state(conn, SSH_SFTP_GETINFO);
+        state(data, SSH_SFTP_GETINFO);
       }
       break;
     case SSH_SFTP_GETINFO:
       if(data->set.get_filetime) {
-        state(conn, SSH_SFTP_FILETIME);
+        state(data, SSH_SFTP_FILETIME);
       }
       else {
-        state(conn, SSH_SFTP_TRANS_INIT);
+        state(data, SSH_SFTP_TRANS_INIT);
       }
       break;
     case SSH_SFTP_TRANS_INIT:
       if(data->set.upload)
-        state(conn, SSH_SFTP_UPLOAD_INIT);
+        state(data, SSH_SFTP_UPLOAD_INIT);
       else {
         if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
-          state(conn, SSH_SFTP_READDIR_INIT);
+          state(data, SSH_SFTP_READDIR_INIT);
         else
-          state(conn, SSH_SFTP_DOWNLOAD_INIT);
+          state(data, SSH_SFTP_DOWNLOAD_INIT);
       }
       break;
     case SSH_SFTP_UPLOAD_INIT: {
@@ -583,7 +592,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
         /* If we have restart position then open for append */
         flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND;
       else
-        /* Clear file before writing (normal behaviour) */
+        /* Clear file before writing (normal behavior) */
         flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC;
 
       memset(&createattrs, 0, sizeof(createattrs));
@@ -611,7 +620,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
         failf(data, "wolfssh SFTP upload open failed: %d", rc);
         return CURLE_SSH;
       }
-      state(conn, SSH_SFTP_DOWNLOAD_STAT);
+      state(data, SSH_SFTP_DOWNLOAD_STAT);
 
       /* If we have a restart point then we need to seek to the correct
          position. */
@@ -676,7 +685,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
       conn->sockfd = conn->writesockfd;
 
       if(result) {
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = result;
       }
       else {
@@ -694,7 +703,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
            timeout here */
         Curl_expire(data, 0, EXPIRE_RUN_NOW);
 
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
       }
       break;
     }
@@ -717,7 +726,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
       }
       else if(rc == WS_SUCCESS) {
         infof(data, "wolfssh SFTP open succeeded!\n");
-        state(conn, SSH_SFTP_DOWNLOAD_STAT);
+        state(data, SSH_SFTP_DOWNLOAD_STAT);
         return CURLE_OK;
       }
 
@@ -762,7 +771,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
 
       /* We cannot seek with wolfSSH so resuming and range requests are not
          possible */
-      if(conn->data->state.use_range || data->state.resume_from) {
+      if(data->state.use_range || data->state.resume_from) {
         infof(data, "wolfSSH cannot do range/seek on SFTP\n");
         return CURLE_BAD_DOWNLOAD_RESUME;
       }
@@ -772,7 +781,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
         /* no data to transfer */
         Curl_setup_transfer(data, -1, -1, FALSE, -1);
         infof(data, "File already completely downloaded\n");
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
       Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
@@ -788,11 +797,11 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
       if(result) {
         /* this should never occur; the close state should be entered
            at the time the error occurs */
-        state(conn, SSH_SFTP_CLOSE);
+        state(data, SSH_SFTP_CLOSE);
         sshc->actualcode = result;
       }
       else {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
       }
       break;
     }
@@ -813,7 +822,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
         return CURLE_OK;
       }
       else if(rc == WS_SUCCESS) {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         return CURLE_OK;
       }
 
@@ -823,10 +832,10 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
     case SSH_SFTP_READDIR_INIT:
       Curl_pgrsSetDownloadSize(data, -1);
       if(data->set.opt_no_body) {
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         break;
       }
-      state(conn, SSH_SFTP_READDIR);
+      state(data, SSH_SFTP_READDIR);
       /* FALLTHROUGH */
     case SSH_SFTP_READDIR:
       name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
@@ -853,11 +862,11 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
                                data->set.ftp_list_only ?
                                name->fName : name->lName);
           if(line == NULL) {
-            state(conn, SSH_SFTP_CLOSE);
+            state(data, SSH_SFTP_CLOSE);
             sshc->actualcode = CURLE_OUT_OF_MEMORY;
             break;
           }
-          result = Curl_client_write(conn, CLIENTWRITE_BODY,
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
                                      line, strlen(line));
           free(line);
           if(result) {
@@ -867,7 +876,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
           name = name->next;
         }
         wolfSSH_SFTPNAME_list_free(origname);
-        state(conn, SSH_STOP);
+        state(data, SSH_STOP);
         return result;
       }
       failf(data, "wolfssh SFTP ls failed: %d", rc);
@@ -877,7 +886,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
       Curl_safefree(sshc->homedir);
       wolfSSH_free(sshc->ssh_session);
       wolfSSH_CTX_free(sshc->ctx);
-      state(conn, SSH_STOP);
+      state(data, SSH_STOP);
       return CURLE_OK;
     default:
       break;
@@ -887,19 +896,20 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
 }
 
 /* called repeatedly until done from multi.c */
-static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done)
+static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result = CURLE_OK;
   bool block; /* we store the status and use that to provide a ssh_getsock()
                  implementation */
   do {
-    result = wssh_statemach_act(conn, &block);
+    result = wssh_statemach_act(data, &block);
     *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
     /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
        try again */
     if(*done) {
-      DEBUGF(infof(conn->data, "wssh_statemach_act says DONE\n"));
+      DEBUGF(infof(data, "wssh_statemach_act says DONE\n"));
     }
   } while(!result && !*done && !block);
 
@@ -907,37 +917,38 @@ static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done)
 }
 
 static
-CURLcode wscp_perform(struct connectdata *conn,
+CURLcode wscp_perform(struct Curl_easy *data,
                       bool *connected,
                       bool *dophase_done)
 {
-  (void)conn;
+  (void)data;
   (void)connected;
   (void)dophase_done;
   return CURLE_OK;
 }
 
 static
-CURLcode wsftp_perform(struct connectdata *conn,
+CURLcode wsftp_perform(struct Curl_easy *data,
                        bool *connected,
                        bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
-  DEBUGF(infof(conn->data, "DO phase starts\n"));
+  DEBUGF(infof(data, "DO phase starts\n"));
 
   *dophase_done = FALSE; /* not done yet */
 
   /* start the first command in the DO phase */
-  state(conn, SSH_SFTP_QUOTE_INIT);
+  state(data, SSH_SFTP_QUOTE_INIT);
 
   /* run the state-machine */
-  result = wssh_multi_statemach(conn, dophase_done);
+  result = wssh_multi_statemach(data, dophase_done);
 
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
 
   return result;
@@ -946,11 +957,11 @@ CURLcode wsftp_perform(struct connectdata *conn,
 /*
  * The DO function is generic for both protocols.
  */
-static CURLcode wssh_do(struct connectdata *conn, bool *done)
+static CURLcode wssh_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result;
   bool connected = 0;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
   *done = FALSE; /* default to false */
@@ -965,31 +976,31 @@ static CURLcode wssh_do(struct connectdata *conn, bool *done)
   Curl_pgrsSetDownloadSize(data, -1);
 
   if(conn->handler->protocol & CURLPROTO_SCP)
-    result = wscp_perform(conn, &connected,  done);
+    result = wscp_perform(data, &connected,  done);
   else
-    result = wsftp_perform(conn, &connected,  done);
+    result = wsftp_perform(data, &connected,  done);
 
   return result;
 }
 
-static CURLcode wssh_block_statemach(struct connectdata *conn,
+static CURLcode wssh_block_statemach(struct Curl_easy *data,
                                     bool disconnect)
 {
+  struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
 
   while((sshc->state != SSH_STOP) && !result) {
     bool block;
     timediff_t left = 1000;
     struct curltime now = Curl_now();
 
-    result = wssh_statemach_act(conn, &block);
+    result = wssh_statemach_act(data, &block);
     if(result)
       break;
 
     if(!disconnect) {
-      if(Curl_pgrsUpdate(conn))
+      if(Curl_pgrsUpdate(data))
         return CURLE_ABORTED_BY_CALLBACK;
 
       result = Curl_speedcheck(data, now);
@@ -1024,29 +1035,29 @@ static CURLcode wssh_block_statemach(struct connectdata *conn,
 
 /* generic done function for both SCP and SFTP called from their specific
    done functions */
-static CURLcode wssh_done(struct connectdata *conn, CURLcode status)
+static CURLcode wssh_done(struct Curl_easy *data, CURLcode status)
 {
   CURLcode result = CURLE_OK;
-  struct SSHPROTO *sftp_scp = conn->data->req.protop;
+  struct SSHPROTO *sftp_scp = data->req.p.ssh;
 
   if(!status) {
     /* run the state-machine */
-    result = wssh_block_statemach(conn, FALSE);
+    result = wssh_block_statemach(data, FALSE);
   }
   else
     result = status;
 
   if(sftp_scp)
     Curl_safefree(sftp_scp->path);
-  if(Curl_pgrsDone(conn))
+  if(Curl_pgrsDone(data))
     return CURLE_ABORTED_BY_CALLBACK;
 
-  conn->data->req.keepon = 0; /* clear all bits */
+  data->req.keepon = 0; /* clear all bits */
   return result;
 }
 
 #if 0
-static CURLcode wscp_done(struct connectdata *conn,
+static CURLcode wscp_done(struct Curl_easy *data,
                          CURLcode code, bool premature)
 {
   CURLcode result = CURLE_OK;
@@ -1057,7 +1068,7 @@ static CURLcode wscp_done(struct connectdata *conn,
   return result;
 }
 
-static CURLcode wscp_doing(struct connectdata *conn,
+static CURLcode wscp_doing(struct Curl_easy *data,
                           bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
@@ -1067,9 +1078,11 @@ static CURLcode wscp_doing(struct connectdata *conn,
   return result;
 }
 
-static CURLcode wscp_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode wscp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
 {
   CURLcode result = CURLE_OK;
+  (void)data;
   (void)conn;
   (void)dead_connection;
 
@@ -1077,54 +1090,52 @@ static CURLcode wscp_disconnect(struct connectdata *conn, bool dead_connection)
 }
 #endif
 
-static CURLcode wsftp_done(struct connectdata *conn,
+static CURLcode wsftp_done(struct Curl_easy *data,
                           CURLcode code, bool premature)
 {
   (void)premature;
-  state(conn, SSH_SFTP_CLOSE);
+  state(data, SSH_SFTP_CLOSE);
 
-  return wssh_done(conn, code);
+  return wssh_done(data, code);
 }
 
-static CURLcode wsftp_doing(struct connectdata *conn,
+static CURLcode wsftp_doing(struct Curl_easy *data,
                            bool *dophase_done)
 {
-  CURLcode result = wssh_multi_statemach(conn, dophase_done);
+  CURLcode result = wssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(data, "DO phase is complete\n"));
   }
   return result;
 }
 
-static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead)
+static CURLcode wsftp_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
+                                 bool dead)
 {
   CURLcode result = CURLE_OK;
   (void)dead;
 
-  DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
 
   if(conn->proto.sshc.ssh_session) {
     /* only if there's a session still around to use! */
-    state(conn, SSH_SFTP_SHUTDOWN);
-    result = wssh_block_statemach(conn, TRUE);
+    state(data, SSH_SFTP_SHUTDOWN);
+    result = wssh_block_statemach(data, TRUE);
   }
 
-  DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
+  DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
   return result;
 }
 
-static int wssh_getsock(struct connectdata *conn,
+static int wssh_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
                         curl_socket_t *sock)
 {
-  return wssh_perform_getsock(conn, sock);
-}
-
-static int wssh_perform_getsock(const struct connectdata *conn,
-                                curl_socket_t *sock)
-{
   int bitmap = GETSOCK_BLANK;
   int dir = conn->waitfor;
+  (void)data;
   sock[0] = conn->sock[FIRSTSOCKET];
 
   if(dir == KEEP_RECV)
index a9b9a3b..7b6ac48 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 44e7406..29b08c0 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019 - 2020, Michael Forney, <mforney@mforney.org>
+ * Copyright (C) 2019 - 2021, Michael Forney, <mforney@mforney.org>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
@@ -294,9 +294,9 @@ static const br_x509_class x509_vtable = {
   x509_get_pkey
 };
 
-static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step1(struct Curl_easy *data,
+                                      struct connectdata *conn, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
@@ -349,8 +349,8 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
     ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len);
     if(ret != CURLE_OK) {
       if(verifypeer) {
-        failf(data, "error setting certificate verify locations:\n"
-              "  CAfile: %s\n", ssl_cafile);
+        failf(data, "error setting certificate verify locations."
+              " CAfile: %s", ssl_cafile);
         return ret;
       }
       infof(data, "error setting certificate verify locations,"
@@ -374,12 +374,12 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
   if(SSL_SET_OPTION(primary.sessionid)) {
     void *session;
 
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn, &session, NULL, sockindex)) {
       br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
       infof(data, "BearSSL: re-using session ID\n");
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   if(conn->bits.tls_enable_alpn) {
@@ -429,10 +429,10 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex,
+static CURLcode bearssl_run_until(struct Curl_easy *data,
+                                  struct connectdata *conn, int sockindex,
                                   unsigned target)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   curl_socket_t sockfd = conn->sock[sockindex];
@@ -507,14 +507,15 @@ static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex,
   }
 }
 
-static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step2(struct Curl_easy *data,
+                                      struct connectdata *conn, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   CURLcode ret;
 
-  ret = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+  ret = bearssl_run_until(data, conn, sockindex,
+                          BR_SSL_SENDAPP | BR_SSL_RECVAPP);
   if(ret == CURLE_AGAIN)
     return CURLE_OK;
   if(ret == CURLE_OK) {
@@ -527,9 +528,9 @@ static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex)
   return ret;
 }
 
-static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step3(struct Curl_easy *data,
+                                      struct connectdata *conn, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   CURLcode ret;
@@ -552,7 +553,7 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
         conn->negnpn = CURL_HTTP_VERSION_1_1;
       else
         infof(data, "ALPN, unrecognized protocol %s\n", protocol);
-      Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+      Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
     }
     else
@@ -568,12 +569,13 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
     if(!session)
       return CURLE_OUT_OF_MEMORY;
     br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
-    Curl_ssl_sessionid_lock(conn);
-    incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex));
+    Curl_ssl_sessionid_lock(data);
+    incache = !(Curl_ssl_getsessionid(data, conn,
+                                      &oldsession, NULL, sockindex));
     if(incache)
-      Curl_ssl_delsessionid(conn, oldsession);
-    ret = Curl_ssl_addsessionid(conn, session, 0, sockindex);
-    Curl_ssl_sessionid_unlock(conn);
+      Curl_ssl_delsessionid(data, oldsession);
+    ret = Curl_ssl_addsessionid(data, conn, session, 0, sockindex);
+    Curl_ssl_sessionid_unlock(data);
     if(ret) {
       free(session);
       return CURLE_OUT_OF_MEMORY;
@@ -585,17 +587,17 @@ static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static ssize_t bearssl_send(struct connectdata *conn, int sockindex,
+static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
                             const void *buf, size_t len, CURLcode *err)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   unsigned char *app;
   size_t applen;
 
   for(;;) {
-    *err = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP);
+    *err = bearssl_run_until(data, conn, sockindex, BR_SSL_SENDAPP);
     if (*err != CURLE_OK)
       return -1;
     app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
@@ -618,15 +620,16 @@ static ssize_t bearssl_send(struct connectdata *conn, int sockindex,
   }
 }
 
-static ssize_t bearssl_recv(struct connectdata *conn, int sockindex,
+static ssize_t bearssl_recv(struct Curl_easy *data, int sockindex,
                             char *buf, size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   unsigned char *app;
   size_t applen;
 
-  *err = bearssl_run_until(conn, sockindex, BR_SSL_RECVAPP);
+  *err = bearssl_run_until(data, conn, sockindex, BR_SSL_RECVAPP);
   if(*err != CURLE_OK)
     return -1;
   app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
@@ -640,13 +643,13 @@ static ssize_t bearssl_recv(struct connectdata *conn, int sockindex,
   return applen;
 }
 
-static CURLcode bearssl_connect_common(struct connectdata *conn,
+static CURLcode bearssl_connect_common(struct Curl_easy *data,
+                                       struct connectdata *conn,
                                        int sockindex,
                                        bool nonblocking,
                                        bool *done)
 {
   CURLcode ret;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   timediff_t timeout_ms;
@@ -659,7 +662,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
   }
 
   if(ssl_connect_1 == connssl->connecting_state) {
-    ret = bearssl_connect_step1(conn, sockindex);
+    ret = bearssl_connect_step1(data, conn, sockindex);
     if(ret)
       return ret;
   }
@@ -712,7 +715,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
      * before step2 has completed while ensuring that a client using select()
      * or epoll() will always have a valid fdset to wait on.
      */
-    ret = bearssl_connect_step2(conn, sockindex);
+    ret = bearssl_connect_step2(data, conn, sockindex);
     if(ret || (nonblocking &&
                (ssl_connect_2 == connssl->connecting_state ||
                 ssl_connect_2_reading == connssl->connecting_state ||
@@ -721,7 +724,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
   }
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    ret = bearssl_connect_step3(conn, sockindex);
+    ret = bearssl_connect_step3(data, conn, sockindex);
     if(ret)
       return ret;
   }
@@ -741,21 +744,21 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static size_t Curl_bearssl_version(char *buffer, size_t size)
+static size_t bearssl_version(char *buffer, size_t size)
 {
   return msnprintf(buffer, size, "BearSSL");
 }
 
-static bool Curl_bearssl_data_pending(const struct connectdata *conn,
-                                      int connindex)
+static bool bearssl_data_pending(const struct connectdata *conn,
+                                 int connindex)
 {
   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
   struct ssl_backend_data *backend = connssl->backend;
   return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
 }
 
-static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM,
-                                    unsigned char *entropy, size_t length)
+static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
+                               unsigned char *entropy, size_t length)
 {
   static br_hmac_drbg_context ctx;
   static bool seeded = FALSE;
@@ -774,12 +777,13 @@ static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM,
   return CURLE_OK;
 }
 
-static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect(struct Curl_easy *data,
+                                struct connectdata *conn, int sockindex)
 {
   CURLcode ret;
   bool done = FALSE;
 
-  ret = bearssl_connect_common(conn, sockindex, FALSE, &done);
+  ret = bearssl_connect_common(data, conn, sockindex, FALSE, &done);
   if(ret)
     return ret;
 
@@ -788,20 +792,22 @@ static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn,
-                                                 int sockindex, bool *done)
+static CURLcode bearssl_connect_nonblocking(struct Curl_easy *data,
+                                            struct connectdata *conn,
+                                            int sockindex, bool *done)
 {
-  return bearssl_connect_common(conn, sockindex, TRUE, done);
+  return bearssl_connect_common(data, conn, sockindex, TRUE, done);
 }
 
-static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl,
-                                        CURLINFO info UNUSED_PARAM)
+static void *bearssl_get_internals(struct ssl_connect_data *connssl,
+                                   CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
   return &backend->ctx;
 }
 
-static void Curl_bearssl_close(struct connectdata *conn, int sockindex)
+static void bearssl_close(struct Curl_easy *data,
+                          struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
@@ -809,35 +815,22 @@ static void Curl_bearssl_close(struct connectdata *conn, int sockindex)
 
   if(backend->active) {
     br_ssl_engine_close(&backend->ctx.eng);
-    (void)bearssl_run_until(conn, sockindex, BR_SSL_CLOSED);
+    (void)bearssl_run_until(data, conn, sockindex, BR_SSL_CLOSED);
   }
   for(i = 0; i < backend->anchors_len; ++i)
     free(backend->anchors[i].dn.data);
   free(backend->anchors);
 }
 
-static void Curl_bearssl_session_free(void *ptr)
+static void bearssl_session_free(void *ptr)
 {
   free(ptr);
 }
 
-static CURLcode Curl_bearssl_md5sum(unsigned char *input,
-                                    size_t inputlen,
-                                    unsigned char *md5sum,
-                                    size_t md5len UNUSED_PARAM)
-{
-  br_md5_context ctx;
-
-  br_md5_init(&ctx);
-  br_md5_update(&ctx, input, inputlen);
-  br_md5_out(&ctx, md5sum);
-  return CURLE_OK;
-}
-
-static CURLcode Curl_bearssl_sha256sum(const unsigned char *input,
-                                       size_t inputlen,
-                                       unsigned char *sha256sum,
-                                       size_t sha256len UNUSED_PARAM)
+static CURLcode bearssl_sha256sum(const unsigned char *input,
+                                  size_t inputlen,
+                                  unsigned char *sha256sum,
+                                  size_t sha256len UNUSED_PARAM)
 {
   br_sha256_context ctx;
 
@@ -854,24 +847,23 @@ const struct Curl_ssl Curl_ssl_bearssl = {
 
   Curl_none_init,
   Curl_none_cleanup,
-  Curl_bearssl_version,
+  bearssl_version,
   Curl_none_check_cxn,
   Curl_none_shutdown,
-  Curl_bearssl_data_pending,
-  Curl_bearssl_random,
+  bearssl_data_pending,
+  bearssl_random,
   Curl_none_cert_status_request,
-  Curl_bearssl_connect,
-  Curl_bearssl_connect_nonblocking,
-  Curl_bearssl_get_internals,
-  Curl_bearssl_close,
+  bearssl_connect,
+  bearssl_connect_nonblocking,
+  bearssl_get_internals,
+  bearssl_close,
   Curl_none_close_all,
-  Curl_bearssl_session_free,
+  bearssl_session_free,
   Curl_none_set_engine,
   Curl_none_set_engine_default,
   Curl_none_engines_list,
   Curl_none_false_start,
-  Curl_bearssl_md5sum,
-  Curl_bearssl_sha256sum
+  bearssl_sha256sum
 };
 
 #endif /* USE_BEARSSL */
index 5f94922..d72b7d0 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019, Michael Forney, <mforney@mforney.org>
+ * Copyright (C) 2019 - 2020, Michael Forney, <mforney@mforney.org>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 0538e4a..9b5f649 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -301,10 +301,9 @@ static CURLcode set_callback(struct Curl_easy *data,
 }
 
 
-static CURLcode set_ciphers(struct connectdata *conn,
+static CURLcode set_ciphers(struct Curl_easy *data,
                                         gsk_handle h, unsigned int *protoflags)
 {
-  struct Curl_easy *data = conn->data;
   const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
   const char *clp;
   const struct gskit_cipher *ctp;
@@ -435,7 +434,7 @@ static CURLcode set_ciphers(struct connectdata *conn,
 }
 
 
-static int Curl_gskit_init(void)
+static int gskit_init(void)
 {
   /* No initialisation needed. */
 
@@ -443,7 +442,7 @@ static int Curl_gskit_init(void)
 }
 
 
-static void Curl_gskit_cleanup(void)
+static void gskit_cleanup(void)
 {
   /* Nothing to do. */
 }
@@ -587,11 +586,11 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
 }
 
 
-static void close_one(struct ssl_connect_data *connssl,
+static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
                       struct connectdata *conn, int sockindex)
 {
   if(BACKEND->handle) {
-    gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle),
+    gskit_status(data, gsk_secure_soc_close(&BACKEND->handle),
               "gsk_secure_soc_close()", 0);
     /* Last chance to drain output. */
     while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
@@ -612,10 +611,10 @@ static void close_one(struct ssl_connect_data *connssl,
 
 
 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
-                           const void *mem, size_t len, CURLcode *curlcode)
+                          const void *mem, size_t len, CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct Curl_easy *data = conn->data;
   CURLcode cc = CURLE_SEND_ERROR;
   int written;
 
@@ -636,11 +635,11 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex,
 }
 
 
-static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
-                           size_t buffersize, CURLcode *curlcode)
+static ssize_t gskit_recv(struct Curl_easy *data, int num, char *buf,
+                               size_t buffersize, CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
-  struct Curl_easy *data = conn->data;
   int nread;
   CURLcode cc = CURLE_RECV_ERROR;
 
@@ -664,9 +663,8 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
 }
 
 static CURLcode
-set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
+set_ssl_version_min_max(unsigned int *protoflags, struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   long ssl_version = SSL_CONN_CONFIG(version);
   long ssl_version_max = SSL_CONN_CONFIG(version_max);
   long i = ssl_version;
@@ -696,16 +694,16 @@ set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
   return CURLE_OK;
 }
 
-static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect_step1(struct Curl_easy *data,
+                                    struct connectdata *conn, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   gsk_handle envir;
   CURLcode result;
   int rc;
   const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
   const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
-  const char * const keyringlabel = SSL_SET_OPTION(cert);
+  const char * const keyringlabel = SSL_SET_OPTION(primary.clientcert);
   const long int ssl_version = SSL_CONN_CONFIG(version);
   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
   const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
@@ -798,7 +796,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
   case CURL_SSLVERSION_TLSv1_1:
   case CURL_SSLVERSION_TLSv1_2:
   case CURL_SSLVERSION_TLSv1_3:
-    result = set_ssl_version_min_max(&protoflags, conn);
+    result = set_ssl_version_min_max(&protoflags, data);
     if(result != CURLE_OK)
       return result;
     break;
@@ -832,7 +830,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
     result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
                          BACKEND->localfd: conn->sock[sockindex]);
   if(!result)
-    result = set_ciphers(conn, BACKEND->handle, &protoflags);
+    result = set_ciphers(data, BACKEND->handle, &protoflags);
   if(!protoflags) {
     failf(data, "No SSL protocol/cipher combination enabled");
     result = CURLE_SSL_CIPHER;
@@ -915,15 +913,15 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
   }
 
   /* Error: rollback. */
-  close_one(connssl, conn, sockindex);
+  close_one(connssl, data, conn, sockindex);
   return result;
 }
 
 
-static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
+static CURLcode gskit_connect_step2(struct Curl_easy *data,
+                                    struct connectdata *conn, int sockindex,
                                     bool nonblocking)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   Qso_OverlappedIO_t cstat;
   struct timeval stmv;
@@ -971,9 +969,9 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
 }
 
 
-static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect_step3(struct Curl_easy *data,
+                                    struct connectdata *conn, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   const gsk_cert_data_elem *cdev;
   int cdec;
@@ -1016,7 +1014,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
   }
 
   /* Verify host. */
-  result = Curl_verifyhost(conn, cert, certend);
+  result = Curl_verifyhost(data, conn, cert, certend);
   if(result)
     return result;
 
@@ -1031,7 +1029,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
       return result;
 
     if(cert) {
-      result = Curl_extract_certinfo(conn, 0, cert, certend);
+      result = Curl_extract_certinfo(data, 0, cert, certend);
       if(result)
         return result;
     }
@@ -1059,10 +1057,10 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
 }
 
 
-static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
+static CURLcode gskit_connect_common(struct Curl_easy *data,
+                                     struct connectdata *conn, int sockindex,
                                      bool nonblocking, bool *done)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   timediff_t timeout_ms;
   CURLcode result = CURLE_OK;
@@ -1082,7 +1080,7 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
       result = CURLE_OPERATION_TIMEDOUT;
     }
     else
-      result = gskit_connect_step1(conn, sockindex);
+      result = gskit_connect_step1(data, conn, sockindex);
   }
 
   /* Handle handshake pipelining. */
@@ -1101,7 +1099,7 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
       result = CURLE_OPERATION_TIMEDOUT;
     }
     else
-      result = gskit_connect_step2(conn, sockindex, nonblocking);
+      result = gskit_connect_step2(data, conn, sockindex, nonblocking);
   }
 
   /* Handle handshake pipelining. */
@@ -1111,10 +1109,10 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
 
   /* Step 3: gather certificate info, verify host. */
   if(!result && connssl->connecting_state == ssl_connect_3)
-    result = gskit_connect_step3(conn, sockindex);
+    result = gskit_connect_step3(data, conn, sockindex);
 
   if(result)
-    close_one(connssl, conn, sockindex);
+    close_one(connssl, data, conn, sockindex);
   else if(connssl->connecting_state == ssl_connect_done) {
     connssl->state = ssl_connection_complete;
     connssl->connecting_state = ssl_connect_1;
@@ -1127,25 +1125,27 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
 }
 
 
-static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
-                                               int sockindex, bool *done)
+static CURLcode gskit_connect_nonblocking(struct Curl_easy *data,
+                                          struct connectdata *conn,
+                                          int sockindex, bool *done)
 {
   CURLcode result;
 
-  result = gskit_connect_common(conn, sockindex, TRUE, done);
+  result = gskit_connect_common(data, conn, sockindex, TRUE, done);
   if(*done || result)
     conn->ssl[sockindex].connecting_state = ssl_connect_1;
   return result;
 }
 
 
-static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect(struct Curl_easy *data,
+                              struct connectdata *conn, int sockindex)
 {
   CURLcode result;
   bool done;
 
   conn->ssl[sockindex].connecting_state = ssl_connect_1;
-  result = gskit_connect_common(conn, sockindex, FALSE, &done);
+  result = gskit_connect_common(data, conn, sockindex, FALSE, &done);
   if(result)
     return result;
 
@@ -1155,17 +1155,18 @@ static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
 }
 
 
-static void Curl_gskit_close(struct connectdata *conn, int sockindex)
+static void gskit_close(struct Curl_easy *data, struct connectdata *conn,
+                        int sockindex)
 {
-  close_one(&conn->ssl[sockindex], conn, sockindex);
-  close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
+  close_one(&conn->ssl[sockindex], data, conn, sockindex);
+  close_one(&conn->proxy_ssl[sockindex], data, conn, sockindex);
 }
 
 
-static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
+static int gskit_shutdown(struct Curl_easy *data,
+                          struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct Curl_easy *data = conn->data;
   int what;
   int rc;
   char buf[120];
@@ -1178,7 +1179,7 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
     return 0;
 #endif
 
-  close_one(connssl, conn, sockindex);
+  close_one(connssl, data, conn, sockindex);
   rc = 0;
   what = SOCKET_READABLE(conn->sock[sockindex],
                          SSL_SHUTDOWN_TIMEOUT);
@@ -1219,13 +1220,13 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
 }
 
 
-static size_t Curl_gskit_version(char *buffer, size_t size)
+static size_t gskit_version(char *buffer, size_t size)
 {
   return msnprintf(buffer, size, "GSKit");
 }
 
 
-static int Curl_gskit_check_cxn(struct connectdata *cxn)
+static int gskit_check_cxn(struct connectdata *cxn)
 {
   struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
   int err;
@@ -1247,8 +1248,8 @@ static int Curl_gskit_check_cxn(struct connectdata *cxn)
   return -1;  /* connection status unknown */
 }
 
-static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl,
-                                      CURLINFO info UNUSED_PARAM)
+static void *gskit_get_internals(struct ssl_connect_data *connssl,
+                                 CURLINFO info UNUSED_PARAM)
 {
   (void)info;
   return BACKEND->handle;
@@ -1262,18 +1263,18 @@ const struct Curl_ssl Curl_ssl_gskit = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_gskit_init,                /* init */
-  Curl_gskit_cleanup,             /* cleanup */
-  Curl_gskit_version,             /* version */
-  Curl_gskit_check_cxn,           /* check_cxn */
-  Curl_gskit_shutdown,            /* shutdown */
+  gskit_init,                     /* init */
+  gskit_cleanup,                  /* cleanup */
+  gskit_version,                  /* version */
+  gskit_check_cxn,                /* check_cxn */
+  gskit_shutdown,                 /* shutdown */
   Curl_none_data_pending,         /* data_pending */
   Curl_none_random,               /* random */
   Curl_none_cert_status_request,  /* cert_status_request */
-  Curl_gskit_connect,             /* connect */
-  Curl_gskit_connect_nonblocking, /* connect_nonblocking */
-  Curl_gskit_get_internals,       /* get_internals */
-  Curl_gskit_close,               /* close_one */
+  gskit_connect,                  /* connect */
+  gskit_connect_nonblocking,      /* connect_nonblocking */
+  gskit_get_internals,            /* get_internals */
+  gskit_close,                    /* close_one */
   Curl_none_close_all,            /* close_all */
   /* No session handling for GSKit */
   Curl_none_session_free,         /* session_free */
@@ -1281,7 +1282,6 @@ const struct Curl_ssl Curl_ssl_gskit = {
   Curl_none_set_engine_default,   /* set_engine_default */
   Curl_none_engines_list,         /* engines_list */
   Curl_none_false_start,          /* false_start */
-  Curl_none_md5sum,               /* md5sum */
   NULL                            /* sha256sum */
 };
 
index b06b5e1..202df7e 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 16b0bd6..3ddee19 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -81,43 +81,43 @@ static bool gtls_inited = FALSE;
 struct ssl_backend_data {
   gnutls_session_t session;
   gnutls_certificate_credentials_t cred;
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
   gnutls_srp_client_credentials_t srp_client_cred;
 #endif
 };
 
-static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
+static ssize_t gtls_push(void *s, const void *buf, size_t len)
 {
   curl_socket_t sock = *(curl_socket_t *)s;
   ssize_t ret = swrite(sock, buf, len);
   return ret;
 }
 
-static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
+static ssize_t gtls_pull(void *s, void *buf, size_t len)
 {
   curl_socket_t sock = *(curl_socket_t *)s;
   ssize_t ret = sread(sock, buf, len);
   return ret;
 }
 
-static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len)
+static ssize_t gtls_push_ssl(void *s, const void *buf, size_t len)
 {
   return gnutls_record_send((gnutls_session_t) s, buf, len);
 }
 
-static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
+static ssize_t gtls_pull_ssl(void *s, void *buf, size_t len)
 {
   return gnutls_record_recv((gnutls_session_t) s, buf, len);
 }
 
-/* Curl_gtls_init()
+/* gtls_init()
  *
  * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
  * are not thread-safe and thus this function itself is not thread-safe and
  * must only be called from within curl_global_init() to keep the thread
  * situation under control!
  */
-static int Curl_gtls_init(void)
+static int gtls_init(void)
 {
   int ret = 1;
   if(!gtls_inited) {
@@ -131,7 +131,7 @@ static int Curl_gtls_init(void)
   return ret;
 }
 
-static void Curl_gtls_cleanup(void)
+static void gtls_cleanup(void)
 {
   if(gtls_inited) {
     gnutls_global_deinit();
@@ -200,12 +200,12 @@ static void unload_file(gnutls_datum_t data)
 
 
 /* this function does a SSL/TLS (re-)handshake */
-static CURLcode handshake(struct connectdata *conn,
+static CURLcode handshake(struct Curl_easy *data,
+                          struct connectdata *conn,
                           int sockindex,
                           bool duringconnect,
                           bool nonblocking)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   gnutls_session_t session = backend->session;
@@ -304,7 +304,7 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
     return GNUTLS_X509_FMT_PEM;
   if(strcasecompare(type, "DER"))
     return GNUTLS_X509_FMT_DER;
-  return -1;
+  return GNUTLS_X509_FMT_PEM; /* default to PEM */
 }
 
 #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
@@ -314,9 +314,9 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
 #define GNUTLS_SRP "+SRP"
 
 static CURLcode
-set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
+set_ssl_version_min_max(const char **prioritylist, struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   long ssl_version = SSL_CONN_CONFIG(version);
   long ssl_version_max = SSL_CONN_CONFIG(version_max);
 
@@ -379,10 +379,10 @@ set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
 }
 
 static CURLcode
-gtls_connect_step1(struct connectdata *conn,
+gtls_connect_step1(struct Curl_easy *data,
+                   struct connectdata *conn,
                    int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   unsigned int init_flags;
@@ -399,15 +399,8 @@ gtls_connect_step1(struct connectdata *conn,
 #endif
   const char *prioritylist;
   const char *err = NULL;
-#ifndef CURL_DISABLE_PROXY
-  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
-    conn->host.name;
-  long * const certverifyresult = SSL_IS_PROXY() ?
-    &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
-#else
-  const char * const hostname = conn->host.name;
-  long * const certverifyresult = &data->set.ssl.certverifyresult;
-#endif
+  const char * const hostname = SSL_HOST_NAME();
+  long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
 
   if(connssl->state == ssl_connection_complete)
     /* to make us tolerant against being called more than once for the
@@ -415,7 +408,7 @@ gtls_connect_step1(struct connectdata *conn,
     return CURLE_OK;
 
   if(!gtls_inited)
-    Curl_gtls_init();
+    gtls_init();
 
   /* Initialize certverifyresult to OK */
   *certverifyresult = 0;
@@ -434,7 +427,7 @@ gtls_connect_step1(struct connectdata *conn,
     return CURLE_SSL_CONNECT_ERROR;
   }
 
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
     infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
 
@@ -575,7 +568,7 @@ gtls_connect_step1(struct connectdata *conn,
     case CURL_SSLVERSION_TLSv1_2:
     case CURL_SSLVERSION_TLSv1_3:
       {
-        CURLcode result = set_ssl_version_min_max(&prioritylist, conn);
+        CURLcode result = set_ssl_version_min_max(&prioritylist, data);
         if(result != CURLE_OK)
           return result;
         break;
@@ -588,7 +581,7 @@ gtls_connect_step1(struct connectdata *conn,
       return CURLE_SSL_CONNECT_ERROR;
   }
 
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
   /* Only add SRP to the cipher list if SRP is requested. Otherwise
    * GnuTLS will disable TLS 1.3 support. */
   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
@@ -610,7 +603,7 @@ gtls_connect_step1(struct connectdata *conn,
   else {
 #endif
     rc = gnutls_priority_set_direct(session, prioritylist, &err);
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
   }
 #endif
 
@@ -645,7 +638,7 @@ gtls_connect_step1(struct connectdata *conn,
     gnutls_alpn_set_protocols(session, protocols, cur, 0);
   }
 
-  if(SSL_SET_OPTION(cert)) {
+  if(SSL_SET_OPTION(primary.clientcert)) {
     if(SSL_SET_OPTION(key_passwd)) {
       const unsigned int supported_key_encryption_algorithms =
         GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
@@ -654,9 +647,9 @@ gtls_connect_step1(struct connectdata *conn,
         GNUTLS_PKCS_USE_PBES2_AES_256;
       rc = gnutls_certificate_set_x509_key_file2(
            backend->cred,
-           SSL_SET_OPTION(cert),
+           SSL_SET_OPTION(primary.clientcert),
            SSL_SET_OPTION(key) ?
-           SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
+           SSL_SET_OPTION(key) : SSL_SET_OPTION(primary.clientcert),
            do_file_type(SSL_SET_OPTION(cert_type)),
            SSL_SET_OPTION(key_passwd),
            supported_key_encryption_algorithms);
@@ -670,9 +663,9 @@ gtls_connect_step1(struct connectdata *conn,
     else {
       if(gnutls_certificate_set_x509_key_file(
            backend->cred,
-           SSL_SET_OPTION(cert),
+           SSL_SET_OPTION(primary.clientcert),
            SSL_SET_OPTION(key) ?
-           SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
+           SSL_SET_OPTION(key) : SSL_SET_OPTION(primary.clientcert),
            do_file_type(SSL_SET_OPTION(cert_type)) ) !=
          GNUTLS_E_SUCCESS) {
         failf(data, "error reading X.509 key or certificate file");
@@ -681,7 +674,7 @@ gtls_connect_step1(struct connectdata *conn,
     }
   }
 
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
   /* put the credentials to the current session */
   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
     rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
@@ -705,16 +698,16 @@ gtls_connect_step1(struct connectdata *conn,
 #ifndef CURL_DISABLE_PROXY
   if(conn->proxy_ssl[sockindex].use) {
     transport_ptr = conn->proxy_ssl[sockindex].backend->session;
-    gnutls_transport_push = Curl_gtls_push_ssl;
-    gnutls_transport_pull = Curl_gtls_pull_ssl;
+    gnutls_transport_push = gtls_push_ssl;
+    gnutls_transport_pull = gtls_pull_ssl;
   }
   else
 #endif
   {
     /* file descriptor for the socket */
     transport_ptr = &conn->sock[sockindex];
-    gnutls_transport_push = Curl_gtls_push;
-    gnutls_transport_pull = Curl_gtls_pull;
+    gnutls_transport_push = gtls_push;
+    gnutls_transport_pull = gtls_pull;
   }
 
   /* set the connection handle */
@@ -738,15 +731,16 @@ gtls_connect_step1(struct connectdata *conn,
     void *ssl_sessionid;
     size_t ssl_idsize;
 
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn,
+                              &ssl_sessionid, &ssl_idsize, sockindex)) {
       /* we got a session id, use it! */
       gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
 
       /* Informational message */
       infof(data, "SSL re-using session ID\n");
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   return CURLE_OK;
@@ -814,7 +808,8 @@ static Curl_recv gtls_recv;
 static Curl_send gtls_send;
 
 static CURLcode
-gtls_connect_step3(struct connectdata *conn,
+gtls_connect_step3(struct Curl_easy *data,
+                   struct connectdata *conn,
                    int sockindex)
 {
   unsigned int cert_list_size;
@@ -827,7 +822,6 @@ gtls_connect_step3(struct connectdata *conn,
   size_t size;
   time_t certclock;
   const char *ptr;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   gnutls_session_t session = backend->session;
@@ -839,15 +833,8 @@ gtls_connect_step3(struct connectdata *conn,
   unsigned int bits;
   gnutls_protocol_t version = gnutls_protocol_get_version(session);
 #endif
-#ifndef CURL_DISABLE_PROXY
-  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
-    conn->host.name;
-  long * const certverifyresult = SSL_IS_PROXY() ?
-    &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
-#else
-  const char * const hostname = conn->host.name;
-  long * const certverifyresult = &data->set.ssl.certverifyresult;
-#endif
+  const char * const hostname = SSL_HOST_NAME();
+  long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
 
   /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
   ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
@@ -868,7 +855,7 @@ gtls_connect_step3(struct connectdata *conn,
     if(SSL_CONN_CONFIG(verifypeer) ||
        SSL_CONN_CONFIG(verifyhost) ||
        SSL_SET_OPTION(issuercert)) {
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
       if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
          && SSL_SET_OPTION(username) != NULL
          && !SSL_CONN_CONFIG(verifypeer)
@@ -881,7 +868,7 @@ gtls_connect_step3(struct connectdata *conn,
         failf(data, "failed to get server cert");
         *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND;
         return CURLE_PEER_FAILED_VERIFICATION;
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
       }
 #endif
     }
@@ -899,7 +886,7 @@ gtls_connect_step3(struct connectdata *conn,
       const char *beg = (const char *) chainp[i].data;
       const char *end = beg + chainp[i].size;
 
-      result = Curl_extract_certinfo(conn, i, beg, end);
+      result = Curl_extract_certinfo(data, i, beg, end);
       if(result)
         return result;
     }
@@ -1128,22 +1115,15 @@ gtls_connect_step3(struct connectdata *conn,
   }
 #endif
   if(!rc) {
-#ifndef CURL_DISABLE_PROXY
-    const char * const dispname = SSL_IS_PROXY() ?
-      conn->http_proxy.host.dispname : conn->host.dispname;
-#else
-    const char * const dispname = conn->host.dispname;
-#endif
-
     if(SSL_CONN_CONFIG(verifyhost)) {
       failf(data, "SSL: certificate subject name (%s) does not match "
-            "target host name '%s'", certname, dispname);
+            "target host name '%s'", certname, SSL_HOST_DISPNAME());
       gnutls_x509_crt_deinit(x509_cert);
       return CURLE_PEER_FAILED_VERIFICATION;
     }
     else
       infof(data, "\t common name: %s (does not match '%s')\n",
-            certname, dispname);
+            certname, SSL_HOST_DISPNAME());
   }
   else
     infof(data, "\t common name: %s (matched)\n", certname);
@@ -1246,13 +1226,18 @@ gtls_connect_step3(struct connectdata *conn,
 
     certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
     showtime(data, "expire date", certclock);
+
+    gnutls_free(certfields.data);
   }
 
   rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields);
   if(rc)
     infof(data, "Failed to get certificate issuer\n");
-  else
+  else {
     infof(data, "\t issuer: %s\n", certfields.data);
+
+    gnutls_free(certfields.data);
+  }
 #endif
 
   gnutls_x509_crt_deinit(x509_cert);
@@ -1279,7 +1264,7 @@ gtls_connect_step3(struct connectdata *conn,
     else
       infof(data, "ALPN, server did not agree to a protocol\n");
 
-    Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+    Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
   }
 
@@ -1306,19 +1291,19 @@ gtls_connect_step3(struct connectdata *conn,
       /* extract session ID to the allocated buffer */
       gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
 
-      Curl_ssl_sessionid_lock(conn);
-      incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL,
+      Curl_ssl_sessionid_lock(data);
+      incache = !(Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL,
                                         sockindex));
       if(incache) {
         /* there was one before in the cache, so instead of risking that the
            previous one was rejected, we just kill that and store the new */
-        Curl_ssl_delsessionid(conn, ssl_sessionid);
+        Curl_ssl_delsessionid(data, ssl_sessionid);
       }
 
       /* store this session id */
-      result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize,
-                                     sockindex);
-      Curl_ssl_sessionid_unlock(conn);
+      result = Curl_ssl_addsessionid(data, conn, connect_sessionid,
+                                     connect_idsize, sockindex);
+      Curl_ssl_sessionid_unlock(data);
       if(result) {
         free(connect_sessionid);
         result = CURLE_OUT_OF_MEMORY;
@@ -1342,7 +1327,8 @@ gtls_connect_step3(struct connectdata *conn,
    'ssl_connect_2_writing' (waiting to be able to write).
  */
 static CURLcode
-gtls_connect_common(struct connectdata *conn,
+gtls_connect_common(struct Curl_easy *data,
+                    struct connectdata *conn,
                     int sockindex,
                     bool nonblocking,
                     bool *done)
@@ -1352,19 +1338,19 @@ gtls_connect_common(struct connectdata *conn,
 
   /* Initiate the connection, if not already done */
   if(ssl_connect_1 == connssl->connecting_state) {
-    rc = gtls_connect_step1(conn, sockindex);
+    rc = gtls_connect_step1(data, conn, sockindex);
     if(rc)
       return rc;
   }
 
-  rc = handshake(conn, sockindex, TRUE, nonblocking);
+  rc = handshake(data, conn, sockindex, TRUE, nonblocking);
   if(rc)
     /* handshake() sets its own error message with failf() */
     return rc;
 
   /* Finish connecting once the handshake is done */
   if(ssl_connect_1 == connssl->connecting_state) {
-    rc = gtls_connect_step3(conn, sockindex);
+    rc = gtls_connect_step3(data, conn, sockindex);
     if(rc)
       return rc;
   }
@@ -1374,18 +1360,20 @@ gtls_connect_common(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
-                                              int sockindex, bool *done)
+static CURLcode gtls_connect_nonblocking(struct Curl_easy *data,
+                                         struct connectdata *conn,
+                                         int sockindex, bool *done)
 {
-  return gtls_connect_common(conn, sockindex, TRUE, done);
+  return gtls_connect_common(data, conn, sockindex, TRUE, done);
 }
 
-static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex)
+static CURLcode gtls_connect(struct Curl_easy *data, struct connectdata *conn,
+                             int sockindex)
 {
   CURLcode result;
   bool done = FALSE;
 
-  result = gtls_connect_common(conn, sockindex, FALSE, &done);
+  result = gtls_connect_common(data, conn, sockindex, FALSE, &done);
   if(result)
     return result;
 
@@ -1394,8 +1382,8 @@ static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static bool Curl_gtls_data_pending(const struct connectdata *conn,
-                                   int connindex)
+static bool gtls_data_pending(const struct connectdata *conn,
+                              int connindex)
 {
   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
   bool res = FALSE;
@@ -1415,12 +1403,13 @@ static bool Curl_gtls_data_pending(const struct connectdata *conn,
   return res;
 }
 
-static ssize_t gtls_send(struct connectdata *conn,
+static ssize_t gtls_send(struct Curl_easy *data,
                          int sockindex,
                          const void *mem,
                          size_t len,
                          CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   ssize_t rc = gnutls_record_send(backend->session, mem, len);
@@ -1448,7 +1437,7 @@ static void close_one(struct ssl_connect_data *connssl)
     gnutls_certificate_free_credentials(backend->cred);
     backend->cred = NULL;
   }
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
   if(backend->srp_client_cred) {
     gnutls_srp_free_client_credentials(backend->srp_client_cred);
     backend->srp_client_cred = NULL;
@@ -1456,8 +1445,10 @@ static void close_one(struct ssl_connect_data *connssl)
 #endif
 }
 
-static void Curl_gtls_close(struct connectdata *conn, int sockindex)
+static void gtls_close(struct Curl_easy *data, struct connectdata *conn,
+                       int sockindex)
 {
+  (void) data;
   close_one(&conn->ssl[sockindex]);
 #ifndef CURL_DISABLE_PROXY
   close_one(&conn->proxy_ssl[sockindex]);
@@ -1468,12 +1459,12 @@ static void Curl_gtls_close(struct connectdata *conn, int sockindex)
  * This function is called to shut down the SSL layer but keep the
  * socket open (CCC - Clear Command Channel)
  */
-static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
+static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
+                         int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   int retval = 0;
-  struct Curl_easy *data = conn->data;
 
 #ifndef CURL_DISABLE_FTP
   /* This has only been tested on the proftpd server, and the mod_tls code
@@ -1530,7 +1521,7 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
   }
   gnutls_certificate_free_credentials(backend->cred);
 
-#ifdef USE_TLS_SRP
+#ifdef HAVE_GNUTLS_SRP
   if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
      && SSL_SET_OPTION(username) != NULL)
     gnutls_srp_free_client_credentials(backend->srp_client_cred);
@@ -1542,12 +1533,13 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
   return retval;
 }
 
-static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
+static ssize_t gtls_recv(struct Curl_easy *data, /* connection data */
                          int num,                  /* socketindex */
                          char *buf,                /* store read data here */
                          size_t buffersize,        /* max amount to read */
                          CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
   struct ssl_backend_data *backend = connssl->backend;
   ssize_t ret;
@@ -1561,7 +1553,7 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
   if(ret == GNUTLS_E_REHANDSHAKE) {
     /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
        proper way" takes a whole lot of work. */
-    CURLcode result = handshake(conn, num, FALSE, FALSE);
+    CURLcode result = handshake(data, conn, num, FALSE, FALSE);
     if(result)
       /* handshake() writes error message on its own */
       *curlcode = result;
@@ -1571,7 +1563,7 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
   }
 
   if(ret < 0) {
-    failf(conn->data, "GnuTLS recv error (%d): %s",
+    failf(data, "GnuTLS recv error (%d): %s",
 
           (int)ret, gnutls_strerror((int)ret));
     *curlcode = CURLE_RECV_ERROR;
@@ -1581,18 +1573,18 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
   return ret;
 }
 
-static void Curl_gtls_session_free(void *ptr)
+static void gtls_session_free(void *ptr)
 {
   free(ptr);
 }
 
-static size_t Curl_gtls_version(char *buffer, size_t size)
+static size_t gtls_version(char *buffer, size_t size)
 {
   return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
 }
 
 #ifndef USE_GNUTLS_NETTLE
-static int Curl_gtls_seed(struct Curl_easy *data)
+static int gtls_seed(struct Curl_easy *data)
 {
   /* we have the "SSL is seeded" boolean static to prevent multiple
      time-consuming seedings in vain */
@@ -1610,8 +1602,8 @@ static int Curl_gtls_seed(struct Curl_easy *data)
 #endif
 
 /* data might be NULL! */
-static CURLcode Curl_gtls_random(struct Curl_easy *data,
-                                 unsigned char *entropy, size_t length)
+static CURLcode gtls_random(struct Curl_easy *data,
+                            unsigned char *entropy, size_t length)
 {
 #if defined(USE_GNUTLS_NETTLE)
   int rc;
@@ -1620,36 +1612,16 @@ static CURLcode Curl_gtls_random(struct Curl_easy *data,
   return rc?CURLE_FAILED_INIT:CURLE_OK;
 #elif defined(USE_GNUTLS)
   if(data)
-    Curl_gtls_seed(data); /* Initiate the seed if not already done */
+    gtls_seed(data); /* Initiate the seed if not already done */
   gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
 #endif
   return CURLE_OK;
 }
 
-static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */
-                                 size_t tmplen,
-                                 unsigned char *md5sum, /* output */
-                                 size_t md5len)
-{
-#if defined(USE_GNUTLS_NETTLE)
-  struct md5_ctx MD5pw;
-  md5_init(&MD5pw);
-  md5_update(&MD5pw, (unsigned int)tmplen, tmp);
-  md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
-#elif defined(USE_GNUTLS)
-  gcry_md_hd_t MD5pw;
-  gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
-  gcry_md_write(MD5pw, tmp, tmplen);
-  memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len);
-  gcry_md_close(MD5pw);
-#endif
-  return CURLE_OK;
-}
-
-static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
-                                size_t tmplen,
-                                unsigned char *sha256sum, /* output */
-                                size_t sha256len)
+static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */
+                               size_t tmplen,
+                               unsigned char *sha256sum, /* output */
+                               size_t sha256len)
 {
 #if defined(USE_GNUTLS_NETTLE)
   struct sha256_ctx SHA256pw;
@@ -1666,12 +1638,12 @@ static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
   return CURLE_OK;
 }
 
-static bool Curl_gtls_cert_status_request(void)
+static bool gtls_cert_status_request(void)
 {
   return TRUE;
 }
 
-static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl,
+static void *gtls_get_internals(struct ssl_connect_data *connssl,
                                      CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
@@ -1689,26 +1661,25 @@ const struct Curl_ssl Curl_ssl_gnutls = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_gtls_init,                /* init */
-  Curl_gtls_cleanup,             /* cleanup */
-  Curl_gtls_version,             /* version */
+  gtls_init,                     /* init */
+  gtls_cleanup,                  /* cleanup */
+  gtls_version,                  /* version */
   Curl_none_check_cxn,           /* check_cxn */
-  Curl_gtls_shutdown,            /* shutdown */
-  Curl_gtls_data_pending,        /* data_pending */
-  Curl_gtls_random,              /* random */
-  Curl_gtls_cert_status_request, /* cert_status_request */
-  Curl_gtls_connect,             /* connect */
-  Curl_gtls_connect_nonblocking, /* connect_nonblocking */
-  Curl_gtls_get_internals,       /* get_internals */
-  Curl_gtls_close,               /* close_one */
+  gtls_shutdown,                 /* shutdown */
+  gtls_data_pending,             /* data_pending */
+  gtls_random,                   /* random */
+  gtls_cert_status_request,      /* cert_status_request */
+  gtls_connect,                  /* connect */
+  gtls_connect_nonblocking,      /* connect_nonblocking */
+  gtls_get_internals,            /* get_internals */
+  gtls_close,                    /* close_one */
   Curl_none_close_all,           /* close_all */
-  Curl_gtls_session_free,        /* session_free */
+  gtls_session_free,             /* session_free */
   Curl_none_set_engine,          /* set_engine */
   Curl_none_set_engine_default,  /* set_engine_default */
   Curl_none_engines_list,        /* engines_list */
   Curl_none_false_start,         /* false_start */
-  Curl_gtls_md5sum,              /* md5sum */
-  Curl_gtls_sha256sum            /* sha256sum */
+  gtls_sha256sum                 /* sha256sum */
 };
 
 #endif /* USE_GNUTLS */
index 780fc10..1a146a3 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 70d22ec..a45945f 100644 (file)
@@ -9,7 +9,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index c6b99db..63626da 100644 (file)
@@ -11,7 +11,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 545f824..fc3a948 100644 (file)
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2012 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -31,6 +31,9 @@
 
 #ifdef USE_MBEDTLS
 
+/* Define this to enable lots of debugging for mbedTLS */
+/* #define MBEDTLS_DEBUG */
+
 #include <mbedtls/version.h>
 #if MBEDTLS_VERSION_NUMBER >= 0x02040000
 #include <mbedtls/net_sockets.h>
 #include <mbedtls/ctr_drbg.h>
 #include <mbedtls/sha256.h>
 
+#if MBEDTLS_VERSION_MAJOR >= 2
+#  ifdef MBEDTLS_DEBUG
+#    include <mbedtls/debug.h>
+#  endif
+#endif
+
 #include "urldata.h"
 #include "sendf.h"
 #include "inet_pton.h"
@@ -113,9 +122,6 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
 
 #endif /* THREADING_SUPPORT */
 
-/* Define this to enable lots of debugging for mbedTLS */
-#undef MBEDTLS_DEBUG
-
 #ifdef MBEDTLS_DEBUG
 static void mbed_debug(void *context, int level, const char *f_name,
                        int line_nb, const char *line)
@@ -190,9 +196,9 @@ static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
 }
 
 static CURLcode
-set_ssl_version_min_max(struct connectdata *conn, int sockindex)
+set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
+                        int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
@@ -235,16 +241,15 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
 }
 
 static CURLcode
-mbed_connect_step1(struct connectdata *conn,
+mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
                    int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
   const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
-  char * const ssl_cert = SSL_SET_OPTION(cert);
+  char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
   const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
 #ifndef CURL_DISABLE_PROXY
   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
@@ -274,7 +279,7 @@ mbed_connect_step1(struct connectdata *conn,
 #ifdef MBEDTLS_ERROR_C
     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
 #endif /* MBEDTLS_ERROR_C */
-    failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+    failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s",
           -ret, errorbuf);
   }
 #else
@@ -287,7 +292,7 @@ mbed_connect_step1(struct connectdata *conn,
 #ifdef MBEDTLS_ERROR_C
     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
 #endif /* MBEDTLS_ERROR_C */
-    failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+    failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s",
           -ret, errorbuf);
   }
 #endif /* THREADING_SUPPORT */
@@ -421,7 +426,7 @@ mbed_connect_step1(struct connectdata *conn,
   case CURL_SSLVERSION_TLSv1_2:
   case CURL_SSLVERSION_TLSv1_3:
     {
-      CURLcode result = set_ssl_version_min_max(conn, sockindex);
+      CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
       if(result != CURLE_OK)
         return result;
       break;
@@ -457,17 +462,17 @@ mbed_connect_step1(struct connectdata *conn,
   if(SSL_SET_OPTION(primary.sessionid)) {
     void *old_session = NULL;
 
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn, &old_session, NULL, sockindex)) {
       ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
       if(ret) {
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
         return CURLE_SSL_CONNECT_ERROR;
       }
       infof(data, "mbedTLS re-using session\n");
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   mbedtls_ssl_conf_ca_chain(&backend->config,
@@ -535,11 +540,10 @@ mbed_connect_step1(struct connectdata *conn,
 }
 
 static CURLcode
-mbed_connect_step2(struct connectdata *conn,
+mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
                    int sockindex)
 {
   int ret;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   const mbedtls_x509_crt *peercert;
@@ -695,7 +699,7 @@ mbed_connect_step2(struct connectdata *conn,
     else {
       infof(data, "ALPN, server did not agree to a protocol\n");
     }
-    Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+    Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
   }
 #endif
@@ -707,13 +711,12 @@ mbed_connect_step2(struct connectdata *conn,
 }
 
 static CURLcode
-mbed_connect_step3(struct connectdata *conn,
+mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
                    int sockindex)
 {
   CURLcode retcode = CURLE_OK;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
-  struct Curl_easy *data = conn->data;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
@@ -738,12 +741,13 @@ mbed_connect_step3(struct connectdata *conn,
     }
 
     /* If there's already a matching session in the cache, delete it */
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex))
-      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL, sockindex))
+      Curl_ssl_delsessionid(data, old_ssl_sessionid);
 
-    retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
-    Curl_ssl_sessionid_unlock(conn);
+    retcode = Curl_ssl_addsessionid(data, conn,
+                                    our_ssl_sessionid, 0, sockindex);
+    Curl_ssl_sessionid_unlock(data);
     if(retcode) {
       mbedtls_ssl_session_free(our_ssl_sessionid);
       free(our_ssl_sessionid);
@@ -757,16 +761,16 @@ mbed_connect_step3(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static ssize_t mbed_send(struct connectdata *conn, int sockindex,
+static ssize_t mbed_send(struct Curl_easy *data, int sockindex,
                          const void *mem, size_t len,
                          CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   int ret = -1;
 
-  ret = mbedtls_ssl_write(&backend->ssl,
-                          (unsigned char *)mem, len);
+  ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
 
   if(ret < 0) {
     *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
@@ -777,15 +781,18 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex,
   return ret;
 }
 
-static void Curl_mbedtls_close_all(struct Curl_easy *data)
+static void mbedtls_close_all(struct Curl_easy *data)
 {
   (void)data;
 }
 
-static void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
+static void mbedtls_close(struct Curl_easy *data,
+                          struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
+
+  (void) data;
   mbedtls_pk_free(&backend->pk);
   mbedtls_x509_crt_free(&backend->clicert);
   mbedtls_x509_crt_free(&backend->cacert);
@@ -798,16 +805,16 @@ static void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
 #endif /* THREADING_SUPPORT */
 }
 
-static ssize_t mbed_recv(struct connectdata *conn, int num,
+static ssize_t mbed_recv(struct Curl_easy *data, int num,
                          char *buf, size_t buffersize,
                          CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
   struct ssl_backend_data *backend = connssl->backend;
   int ret = -1;
   ssize_t len = -1;
 
-  memset(buf, 0, buffersize);
   ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
                          buffersize);
 
@@ -825,13 +832,13 @@ static ssize_t mbed_recv(struct connectdata *conn, int num,
   return len;
 }
 
-static void Curl_mbedtls_session_free(void *ptr)
+static void mbedtls_session_free(void *ptr)
 {
   mbedtls_ssl_session_free(ptr);
   free(ptr);
 }
 
-static size_t Curl_mbedtls_version(char *buffer, size_t size)
+static size_t mbedtls_version(char *buffer, size_t size)
 {
 #ifdef MBEDTLS_VERSION_C
   /* if mbedtls_version_get_number() is available it is better */
@@ -843,8 +850,8 @@ static size_t Curl_mbedtls_version(char *buffer, size_t size)
 #endif
 }
 
-static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
-                                    unsigned char *entropy, size_t length)
+static CURLcode mbedtls_random(struct Curl_easy *data,
+                               unsigned char *entropy, size_t length)
 {
 #if defined(MBEDTLS_CTR_DRBG_C)
   int ret = -1;
@@ -862,7 +869,7 @@ static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
 #ifdef MBEDTLS_ERROR_C
     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
 #endif /* MBEDTLS_ERROR_C */
-    failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s\n",
+    failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s",
           -ret, errorbuf);
   }
   else {
@@ -872,7 +879,7 @@ static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
 #ifdef MBEDTLS_ERROR_C
       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
 #endif /* MBEDTLS_ERROR_C */
-      failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+      failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s",
             -ret, errorbuf);
     }
   }
@@ -893,13 +900,13 @@ static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
 }
 
 static CURLcode
-mbed_connect_common(struct connectdata *conn,
+mbed_connect_common(struct Curl_easy *data,
+                    struct connectdata *conn,
                     int sockindex,
                     bool nonblocking,
                     bool *done)
 {
   CURLcode retcode;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   timediff_t timeout_ms;
@@ -920,7 +927,7 @@ mbed_connect_common(struct connectdata *conn,
       failf(data, "SSL connection timeout");
       return CURLE_OPERATION_TIMEDOUT;
     }
-    retcode = mbed_connect_step1(conn, sockindex);
+    retcode = mbed_connect_step1(data, conn, sockindex);
     if(retcode)
       return retcode;
   }
@@ -975,7 +982,7 @@ mbed_connect_common(struct connectdata *conn,
      * ensuring that a client using select() or epoll() will always
      * have a valid fdset to wait on.
      */
-    retcode = mbed_connect_step2(conn, sockindex);
+    retcode = mbed_connect_step2(data, conn, sockindex);
     if(retcode || (nonblocking &&
                    (ssl_connect_2 == connssl->connecting_state ||
                     ssl_connect_2_reading == connssl->connecting_state ||
@@ -985,7 +992,7 @@ mbed_connect_common(struct connectdata *conn,
   } /* repeat step2 until all transactions are done. */
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    retcode = mbed_connect_step3(conn, sockindex);
+    retcode = mbed_connect_step3(data, conn, sockindex);
     if(retcode)
       return retcode;
   }
@@ -1005,19 +1012,21 @@ mbed_connect_common(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
-                                                 int sockindex, bool *done)
+static CURLcode mbedtls_connect_nonblocking(struct Curl_easy *data,
+                                            struct connectdata *conn,
+                                            int sockindex, bool *done)
 {
-  return mbed_connect_common(conn, sockindex, TRUE, done);
+  return mbed_connect_common(data, conn, sockindex, TRUE, done);
 }
 
 
-static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex)
+static CURLcode mbedtls_connect(struct Curl_easy *data,
+                                struct connectdata *conn, int sockindex)
 {
   CURLcode retcode;
   bool done = FALSE;
 
-  retcode = mbed_connect_common(conn, sockindex, FALSE, &done);
+  retcode = mbed_connect_common(data, conn, sockindex, FALSE, &done);
   if(retcode)
     return retcode;
 
@@ -1030,28 +1039,28 @@ static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex)
  * return 0 error initializing SSL
  * return 1 SSL initialized successfully
  */
-static int Curl_mbedtls_init(void)
+static int mbedtls_init(void)
 {
   return Curl_mbedtlsthreadlock_thread_setup();
 }
 
-static void Curl_mbedtls_cleanup(void)
+static void mbedtls_cleanup(void)
 {
   (void)Curl_mbedtlsthreadlock_thread_cleanup();
 }
 
-static bool Curl_mbedtls_data_pending(const struct connectdata *conn,
-                                      int sockindex)
+static bool mbedtls_data_pending(const struct connectdata *conn,
+                                 int sockindex)
 {
   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0;
 }
 
-static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input,
-                                    size_t inputlen,
-                                    unsigned char *sha256sum,
-                                    size_t sha256len UNUSED_PARAM)
+static CURLcode mbedtls_sha256sum(const unsigned char *input,
+                                  size_t inputlen,
+                                  unsigned char *sha256sum,
+                                  size_t sha256len UNUSED_PARAM)
 {
   (void)sha256len;
 #if MBEDTLS_VERSION_NUMBER < 0x02070000
@@ -1064,8 +1073,8 @@ static CURLcode Curl_mbedtls_sha256sum(const unsigned char *input,
   return CURLE_OK;
 }
 
-static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
-                                        CURLINFO info UNUSED_PARAM)
+static void *mbedtls_get_internals(struct ssl_connect_data *connssl,
+                                   CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
   (void)info;
@@ -1081,26 +1090,25 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_mbedtls_init,                /* init */
-  Curl_mbedtls_cleanup,             /* cleanup */
-  Curl_mbedtls_version,             /* version */
+  mbedtls_init,                     /* init */
+  mbedtls_cleanup,                  /* cleanup */
+  mbedtls_version,                  /* version */
   Curl_none_check_cxn,              /* check_cxn */
   Curl_none_shutdown,               /* shutdown */
-  Curl_mbedtls_data_pending,        /* data_pending */
-  Curl_mbedtls_random,              /* random */
+  mbedtls_data_pending,             /* data_pending */
+  mbedtls_random,                   /* random */
   Curl_none_cert_status_request,    /* cert_status_request */
-  Curl_mbedtls_connect,             /* connect */
-  Curl_mbedtls_connect_nonblocking, /* connect_nonblocking */
-  Curl_mbedtls_get_internals,       /* get_internals */
-  Curl_mbedtls_close,               /* close_one */
-  Curl_mbedtls_close_all,           /* close_all */
-  Curl_mbedtls_session_free,        /* session_free */
+  mbedtls_connect,                  /* connect */
+  mbedtls_connect_nonblocking,      /* connect_nonblocking */
+  mbedtls_get_internals,            /* get_internals */
+  mbedtls_close,                    /* close_one */
+  mbedtls_close_all,                /* close_all */
+  mbedtls_session_free,             /* session_free */
   Curl_none_set_engine,             /* set_engine */
   Curl_none_set_engine_default,     /* set_engine_default */
   Curl_none_engines_list,           /* engines_list */
   Curl_none_false_start,            /* false_start */
-  Curl_none_md5sum,                 /* md5sum */
-  Curl_mbedtls_sha256sum            /* sha256sum */
+  mbedtls_sha256sum                 /* sha256sum */
 };
 
 #endif /* USE_MBEDTLS */
index 0cc64b3..1abd331 100644 (file)
@@ -7,12 +7,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 4d672f1..473f517 100644 (file)
@@ -10,7 +10,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 96a787d..e40dfc8 100644 (file)
@@ -12,7 +12,7 @@
  *
  * 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.haxx.se/docs/copyright.html.
+ * 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
index 7132bdf..b6d1005 100644 (file)
@@ -6,11 +6,11 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2017 - 2018, Yiming Jing, <jingyiming@baidu.com>
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -89,10 +89,10 @@ static int do_file_type(const char *type)
  * layer and do all necessary magic.
  */
 static CURLcode
-mesalink_connect_step1(struct connectdata *conn, int sockindex)
+mesalink_connect_step1(struct Curl_easy *data,
+                       struct connectdata *conn, int sockindex)
 {
   char *ciphers;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct in_addr addr4;
 #ifdef ENABLE_IPV6
@@ -158,8 +158,8 @@ mesalink_connect_step1(struct connectdata *conn, int sockindex)
                                                     SSL_CONN_CONFIG(CApath))) {
       if(SSL_CONN_CONFIG(verifypeer)) {
         failf(data,
-              "error setting certificate verify locations:\n"
-              "  CAfile: %s\n  CApath: %s",
+              "error setting certificate verify locations: "
+              " CAfile: %s CApath: %s",
               SSL_CONN_CONFIG(CAfile) ?
               SSL_CONN_CONFIG(CAfile) : "none",
               SSL_CONN_CONFIG(CApath) ?
@@ -173,20 +173,18 @@ mesalink_connect_step1(struct connectdata *conn, int sockindex)
     else {
       infof(data, "successfully set certificate verify locations:\n");
     }
-    infof(data,
-          "  CAfile: %s\n"
-          "  CApath: %s\n",
-          SSL_CONN_CONFIG(CAfile)?
-          SSL_CONN_CONFIG(CAfile): "none",
-          SSL_CONN_CONFIG(CApath)?
-          SSL_CONN_CONFIG(CApath): "none");
+    infof(data, " CAfile: %s\n",
+          SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none");
+    infof(data, " CApath: %s\n",
+          SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none");
   }
 
-  if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
+  if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
     int file_type = do_file_type(SSL_SET_OPTION(cert_type));
 
-    if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx, SSL_SET_OPTION(cert),
-                                     file_type) != 1) {
+    if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx,
+                                          SSL_SET_OPTION(primary.clientcert),
+                                          file_type) != 1) {
       failf(data, "unable to use client certificate (no key or wrong pass"
             " phrase?)");
       return CURLE_SSL_CONNECT_ERROR;
@@ -262,11 +260,11 @@ mesalink_connect_step1(struct connectdata *conn, int sockindex)
   if(SSL_SET_OPTION(primary.sessionid)) {
     void *ssl_sessionid = NULL;
 
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
       /* we got a session id, use it! */
       if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(
           data,
           "SSL: SSL_set_session failed: %s",
@@ -276,7 +274,7 @@ mesalink_connect_step1(struct connectdata *conn, int sockindex)
       /* Informational message */
       infof(data, "SSL re-using session ID\n");
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 #endif /* MESALINK_HAVE_SESSION */
 
@@ -290,10 +288,10 @@ mesalink_connect_step1(struct connectdata *conn, int sockindex)
 }
 
 static CURLcode
-mesalink_connect_step2(struct connectdata *conn, int sockindex)
+mesalink_connect_step2(struct Curl_easy *data,
+                       struct connectdata *conn, int sockindex)
 {
   int ret = -1;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   conn->recv[sockindex] = mesalink_recv;
@@ -350,27 +348,28 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
 
     our_ssl_sessionid = SSL_get_session(BACKEND->handle);
 
-    Curl_ssl_sessionid_lock(conn);
+    Curl_ssl_sessionid_lock(data);
     incache =
-      !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex));
+      !(Curl_ssl_getsessionid(data, conn,
+                              &old_ssl_sessionid, NULL, sockindex));
     if(incache) {
       if(old_ssl_sessionid != our_ssl_sessionid) {
         infof(data, "old SSL session ID is stale, removing\n");
-        Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+        Curl_ssl_delsessionid(data, old_ssl_sessionid);
         incache = FALSE;
       }
     }
 
     if(!incache) {
       result = Curl_ssl_addsessionid(
-        conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
+        data, conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
       if(result) {
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(data, "failed to store ssl session");
         return result;
       }
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 #endif /* MESALINK_HAVE_SESSION */
 
@@ -380,9 +379,10 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
 }
 
 static ssize_t
-mesalink_send(struct connectdata *conn, int sockindex, const void *mem,
+mesalink_send(struct Curl_easy *data, int sockindex, const void *mem,
               size_t len, CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   char error_buffer[MESALINK_MAX_ERROR_SZ];
   int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
@@ -397,7 +397,7 @@ mesalink_send(struct connectdata *conn, int sockindex, const void *mem,
       *curlcode = CURLE_AGAIN;
       return -1;
     default:
-      failf(conn->data,
+      failf(data,
             "SSL write: %s, errno %d",
             ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
             SOCKERRNO);
@@ -409,10 +409,12 @@ mesalink_send(struct connectdata *conn, int sockindex, const void *mem,
 }
 
 static void
-Curl_mesalink_close(struct connectdata *conn, int sockindex)
+mesalink_close(struct Curl_easy *data, struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
+  (void) data;
+
   if(BACKEND->handle) {
     (void)SSL_shutdown(BACKEND->handle);
     SSL_free(BACKEND->handle);
@@ -425,9 +427,10 @@ Curl_mesalink_close(struct connectdata *conn, int sockindex)
 }
 
 static ssize_t
-mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
+mesalink_recv(struct Curl_easy *data, int num, char *buf, size_t buffersize,
               CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
   char error_buffer[MESALINK_MAX_ERROR_SZ];
   int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
@@ -446,7 +449,7 @@ mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
       *curlcode = CURLE_AGAIN;
       return -1;
     default:
-      failf(conn->data,
+      failf(data,
             "SSL read: %s, errno %d",
             ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
             SOCKERRNO);
@@ -458,13 +461,13 @@ mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
 }
 
 static size_t
-Curl_mesalink_version(char *buffer, size_t size)
+mesalink_version(char *buffer, size_t size)
 {
   return msnprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING);
 }
 
 static int
-Curl_mesalink_init(void)
+mesalink_init(void)
 {
   return (SSL_library_init() == SSL_SUCCESS);
 }
@@ -474,11 +477,14 @@ Curl_mesalink_init(void)
  * socket open (CCC - Clear Command Channel)
  */
 static int
-Curl_mesalink_shutdown(struct connectdata *conn, int sockindex)
+mesalink_shutdown(struct Curl_easy *data,
+                  struct connectdata *conn, int sockindex)
 {
   int retval = 0;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
+  (void) data;
+
   if(BACKEND->handle) {
     SSL_free(BACKEND->handle);
     BACKEND->handle = NULL;
@@ -487,11 +493,10 @@ Curl_mesalink_shutdown(struct connectdata *conn, int sockindex)
 }
 
 static CURLcode
-mesalink_connect_common(struct connectdata *conn, int sockindex,
-                        bool nonblocking, bool *done)
+mesalink_connect_common(struct Curl_easy *data, struct connectdata *conn,
+                        int sockindex, bool nonblocking, bool *done)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   timediff_t timeout_ms;
@@ -513,7 +518,7 @@ mesalink_connect_common(struct connectdata *conn, int sockindex,
       return CURLE_OPERATION_TIMEDOUT;
     }
 
-    result = mesalink_connect_step1(conn, sockindex);
+    result = mesalink_connect_step1(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -570,7 +575,7 @@ mesalink_connect_common(struct connectdata *conn, int sockindex,
      * ensuring that a client using select() or epoll() will always
      * have a valid fdset to wait on.
      */
-    result = mesalink_connect_step2(conn, sockindex);
+    result = mesalink_connect_step2(data, conn, sockindex);
 
     if(result ||
        (nonblocking && (ssl_connect_2 == connssl->connecting_state ||
@@ -602,19 +607,20 @@ mesalink_connect_common(struct connectdata *conn, int sockindex,
 }
 
 static CURLcode
-Curl_mesalink_connect_nonblocking(struct connectdata *conn, int sockindex,
-                                  bool *done)
+mesalink_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
+                             int sockindex, bool *done)
 {
-  return mesalink_connect_common(conn, sockindex, TRUE, done);
+  return mesalink_connect_common(data, conn, sockindex, TRUE, done);
 }
 
 static CURLcode
-Curl_mesalink_connect(struct connectdata *conn, int sockindex)
+mesalink_connect(struct Curl_easy *data, struct connectdata *conn,
+                 int sockindex)
 {
   CURLcode result;
   bool done = FALSE;
 
-  result = mesalink_connect_common(conn, sockindex, FALSE, &done);
+  result = mesalink_connect_common(data, conn, sockindex, FALSE, &done);
   if(result)
     return result;
 
@@ -624,8 +630,8 @@ Curl_mesalink_connect(struct connectdata *conn, int sockindex)
 }
 
 static void *
-Curl_mesalink_get_internals(struct ssl_connect_data *connssl,
-                            CURLINFO info UNUSED_PARAM)
+mesalink_get_internals(struct ssl_connect_data *connssl,
+                       CURLINFO info UNUSED_PARAM)
 {
   (void)info;
   return BACKEND->handle;
@@ -638,26 +644,25 @@ const struct Curl_ssl Curl_ssl_mesalink = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_mesalink_init, /* init */
-  Curl_none_cleanup, /* cleanup */
-  Curl_mesalink_version, /* version */
-  Curl_none_check_cxn, /* check_cxn */
-  Curl_mesalink_shutdown, /* shutdown */
-  Curl_none_data_pending, /* data_pending */
-  Curl_none_random, /* random */
+  mesalink_init,                 /* init */
+  Curl_none_cleanup,             /* cleanup */
+  mesalink_version,              /* version */
+  Curl_none_check_cxn,           /* check_cxn */
+  mesalink_shutdown,             /* shutdown */
+  Curl_none_data_pending,        /* data_pending */
+  Curl_none_random,              /* random */
   Curl_none_cert_status_request, /* cert_status_request */
-  Curl_mesalink_connect, /* connect */
-  Curl_mesalink_connect_nonblocking, /* connect_nonblocking */
-  Curl_mesalink_get_internals, /* get_internals */
-  Curl_mesalink_close, /* close_one */
-  Curl_none_close_all, /* close_all */
-  Curl_none_session_free, /* session_free */
-  Curl_none_set_engine, /* set_engine */
-  Curl_none_set_engine_default, /* set_engine_default */
-  Curl_none_engines_list, /* engines_list */
-  Curl_none_false_start, /* false_start */
-  Curl_none_md5sum, /* md5sum */
-  NULL /* sha256sum */
+  mesalink_connect,              /* connect */
+  mesalink_connect_nonblocking,  /* connect_nonblocking */
+  mesalink_get_internals,        /* get_internals */
+  mesalink_close,                /* close_one */
+  Curl_none_close_all,           /* close_all */
+  Curl_none_session_free,        /* session_free */
+  Curl_none_set_engine,          /* set_engine */
+  Curl_none_set_engine_default,  /* set_engine_default */
+  Curl_none_engines_list,        /* engines_list */
+  Curl_none_false_start,         /* false_start */
+  NULL                           /* sha256sum */
 };
 
 #endif
index 54cb94a..03f520c 100644 (file)
@@ -7,12 +7,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2017-2018, Yiming Jing, <jingyiming@baidu.com>
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2017 - 2018, Yiming Jing, <jingyiming@baidu.com>
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 0f0d1ee..e5ab71c 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -83,7 +83,7 @@ struct ssl_backend_data {
   PRFileDesc *handle;
   char *client_nickname;
   struct Curl_easy *data;
-  struct curl_llist obj_list;
+  struct Curl_llist obj_list;
   PK11GenericObject *obj_clicert;
 };
 
@@ -91,14 +91,14 @@ static PRLock *nss_initlock = NULL;
 static PRLock *nss_crllock = NULL;
 static PRLock *nss_findslot_lock = NULL;
 static PRLock *nss_trustload_lock = NULL;
-static struct curl_llist nss_crl_list;
+static struct Curl_llist nss_crl_list;
 static NSSInitContext *nss_context = NULL;
 static volatile int initialized = 0;
 
 /* type used to wrap pointers as list nodes */
 struct ptr_list_wrap {
   void *ptr;
-  struct curl_llist_element node;
+  struct Curl_llist_element node;
 };
 
 struct cipher_s {
@@ -430,7 +430,7 @@ static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
 }
 
 /* wrap 'ptr' as list node and tail-insert into 'list' */
-static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr)
+static CURLcode insert_wrapped_ptr(struct Curl_llist *list, void *ptr)
 {
   struct ptr_list_wrap *wrap = malloc(sizeof(*wrap));
   if(!wrap)
@@ -443,7 +443,7 @@ static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr)
 
 /* Call PK11_CreateGenericObject() with the given obj_class and filename.  If
  * the call succeeds, append the object handle to the list of objects so that
- * the object can be destroyed in Curl_nss_close(). */
+ * the object can be destroyed in nss_close(). */
 static CURLcode nss_create_object(struct ssl_connect_data *connssl,
                                   CK_OBJECT_CLASS obj_class,
                                   const char *filename, bool cacert)
@@ -508,7 +508,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *connssl,
 
 /* Destroy the NSS object whose handle is given by ptr.  This function is
  * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
- * NSS objects in Curl_nss_close() */
+ * NSS objects in nss_close() */
 static void nss_destroy_object(void *user, void *ptr)
 {
   struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
@@ -587,7 +587,7 @@ static CURLcode nss_cache_crl(SECItem *crl_der)
     return CURLE_SSL_CRL_BADFILE;
   }
 
-  /* store the CRL item so that we can free it in Curl_nss_cleanup() */
+  /* store the CRL item so that we can free it in nss_cleanup() */
   if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) {
     if(SECSuccess == CERT_UncacheCRL(db, crl_der))
       SECITEM_FreeItem(crl_der, PR_TRUE);
@@ -665,14 +665,13 @@ fail:
   return CURLE_SSL_CRL_BADFILE;
 }
 
-static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
-                             char *key_file)
+static CURLcode nss_load_key(struct Curl_easy *data, struct connectdata *conn,
+                             int sockindex, char *key_file)
 {
   PK11SlotInfo *slot, *tmp;
   SECStatus status;
   CURLcode result;
   struct ssl_connect_data *ssl = conn->ssl;
-  struct Curl_easy *data = conn->data;
 
   (void)sockindex; /* unused */
 
@@ -701,15 +700,15 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
   return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
 }
 
-static int display_error(struct connectdata *conn, PRInt32 err,
+static int display_error(struct Curl_easy *data, PRInt32 err,
                          const char *filename)
 {
   switch(err) {
   case SEC_ERROR_BAD_PASSWORD:
-    failf(conn->data, "Unable to load client key: Incorrect password");
+    failf(data, "Unable to load client key: Incorrect password");
     return 1;
   case SEC_ERROR_UNKNOWN_CERT:
-    failf(conn->data, "Unable to load certificate %s", filename);
+    failf(data, "Unable to load certificate %s", filename);
     return 1;
   default:
     break;
@@ -717,17 +716,16 @@ static int display_error(struct connectdata *conn, PRInt32 err,
   return 0; /* The caller will print a generic error */
 }
 
-static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
-                           char *cert_file, char *key_file)
+static CURLcode cert_stuff(struct Curl_easy *data, struct connectdata *conn,
+                           int sockindex, char *cert_file, char *key_file)
 {
-  struct Curl_easy *data = conn->data;
   CURLcode result;
 
   if(cert_file) {
     result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
     if(result) {
       const PRErrorCode err = PR_GetError();
-      if(!display_error(conn, err, cert_file)) {
+      if(!display_error(data, err, cert_file)) {
         const char *err_name = nss_error_to_name(err);
         failf(data, "unable to load client cert: %d (%s)", err, err_name);
       }
@@ -738,13 +736,13 @@ static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
 
   if(key_file || (is_file(cert_file))) {
     if(key_file)
-      result = nss_load_key(conn, sockindex, key_file);
+      result = nss_load_key(data, conn, sockindex, key_file);
     else
       /* In case the cert file also has the key */
-      result = nss_load_key(conn, sockindex, cert_file);
+      result = nss_load_key(data, conn, sockindex, cert_file);
     if(result) {
       const PRErrorCode err = PR_GetError();
-      if(!display_error(conn, err, key_file)) {
+      if(!display_error(data, err, key_file)) {
         const char *err_name = nss_error_to_name(err);
         failf(data, "unable to load client key: %d (%s)", err, err_name);
       }
@@ -771,7 +769,8 @@ static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
 static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
                                     PRBool isServer)
 {
-  struct connectdata *conn = (struct connectdata *)arg;
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct connectdata *conn = data->conn;
 
 #ifdef SSL_ENABLE_OCSP_STAPLING
   if(SSL_CONN_CONFIG(verifystatus)) {
@@ -779,12 +778,12 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
 
     const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
     if(!csa) {
-      failf(conn->data, "Invalid OCSP response");
+      failf(data, "Invalid OCSP response");
       return SECFailure;
     }
 
     if(csa->len == 0) {
-      failf(conn->data, "No OCSP response received");
+      failf(data, "No OCSP response received");
       return SECFailure;
     }
 
@@ -794,14 +793,14 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
     );
 
     if(cacheResult != SECSuccess) {
-      failf(conn->data, "Invalid OCSP response");
+      failf(data, "Invalid OCSP response");
       return cacheResult;
     }
   }
 #endif
 
   if(!SSL_CONN_CONFIG(verifypeer)) {
-    infof(conn->data, "skipping SSL peer certificate verification\n");
+    infof(data, "skipping SSL peer certificate verification\n");
     return SECSuccess;
   }
 
@@ -813,7 +812,8 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
  */
 static void HandshakeCallback(PRFileDesc *sock, void *arg)
 {
-  struct connectdata *conn = (struct connectdata*) arg;
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct connectdata *conn = data->conn;
   unsigned int buflenmax = 50;
   unsigned char buf[50];
   unsigned int buflen;
@@ -833,15 +833,15 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
 #endif
     case SSL_NEXT_PROTO_NO_SUPPORT:
     case SSL_NEXT_PROTO_NO_OVERLAP:
-      infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n");
+      infof(data, "ALPN/NPN, server did not agree to a protocol\n");
       return;
 #ifdef SSL_ENABLE_ALPN
     case SSL_NEXT_PROTO_SELECTED:
-      infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf);
+      infof(data, "ALPN, server accepted to use %.*s\n", buflen, buf);
       break;
 #endif
     case SSL_NEXT_PROTO_NEGOTIATED:
-      infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf);
+      infof(data, "NPN, server accepted to use %.*s\n", buflen, buf);
       break;
     }
 
@@ -856,7 +856,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
        !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
       conn->negnpn = CURL_HTTP_VERSION_1_1;
     }
-    Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+    Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
   }
 }
@@ -865,8 +865,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
 static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
                                        PRBool *canFalseStart)
 {
-  struct connectdata *conn = client_data;
-  struct Curl_easy *data = conn->data;
+  struct Curl_easy *data = (struct Curl_easy *)client_data;
 
   SSLChannelInfo channelInfo;
   SSLCipherSuiteInfo cipherInfo;
@@ -949,7 +948,7 @@ static void display_cert_info(struct Curl_easy *data,
   PR_Free(common_name);
 }
 
-static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
+static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
 {
   CURLcode result = CURLE_OK;
   SSLChannelInfo channel;
@@ -965,16 +964,16 @@ static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
      channel.cipherSuite) {
     if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
                               &suite, sizeof(suite)) == SECSuccess) {
-      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
+      infof(data, "SSL connection using %s\n", suite.cipherSuiteName);
     }
   }
 
   cert = SSL_PeerCertificate(sock);
   if(cert) {
-    infof(conn->data, "Server certificate:\n");
+    infof(data, "Server certificate:\n");
 
-    if(!conn->data->set.ssl.certinfo) {
-      display_cert_info(conn->data, cert);
+    if(!data->set.ssl.certinfo) {
+      display_cert_info(data, cert);
       CERT_DestroyCertificate(cert);
     }
     else {
@@ -995,10 +994,10 @@ static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
         }
       }
 
-      result = Curl_ssl_init_certinfo(conn->data, i);
+      result = Curl_ssl_init_certinfo(data, i);
       if(!result) {
         for(i = 0; cert; cert = cert2) {
-          result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data,
+          result = Curl_extract_certinfo(data, i++, (char *)cert->derCert.data,
                                          (char *)cert->derCert.data +
                                                  cert->derCert.len);
           if(result)
@@ -1021,18 +1020,13 @@ static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
 
 static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
 {
-  struct connectdata *conn = (struct connectdata *)arg;
-  struct Curl_easy *data = conn->data;
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct connectdata *conn = data->conn;
   PRErrorCode err = PR_GetError();
   CERTCertificate *cert;
 
   /* remember the cert verification result */
-#ifndef CURL_DISABLE_PROXY
-  if(SSL_IS_PROXY())
-    data->set.proxy_ssl.certverifyresult = err;
-  else
-#endif
-    data->set.ssl.certverifyresult = err;
+  SSL_SET_OPTION_LVALUE(certverifyresult) = err;
 
   if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
     /* we are asked not to verify the host name */
@@ -1340,7 +1334,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
 
     infof(data, "Initializing NSS with certpath: %s\n", certpath);
     nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
-            NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
+                                  NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
     free(certpath);
 
     if(nss_context != NULL)
@@ -1365,7 +1359,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
 }
 
 /* data might be NULL */
-static CURLcode nss_init(struct Curl_easy *data)
+static CURLcode nss_setup(struct Curl_easy *data)
 {
   char *cert_dir;
   struct_stat st;
@@ -1374,7 +1368,7 @@ static CURLcode nss_init(struct Curl_easy *data)
   if(initialized)
     return CURLE_OK;
 
-  /* list of all CRL items we need to destroy in Curl_nss_cleanup() */
+  /* list of all CRL items we need to destroy in nss_cleanup() */
   Curl_llist_init(&nss_crl_list, nss_destroy_crl_item);
 
   /* First we check if $SSL_DIR points to a valid dir */
@@ -1428,7 +1422,7 @@ static CURLcode nss_init(struct Curl_easy *data)
  * @retval 0 error initializing SSL
  * @retval 1 SSL initialized successfully
  */
-static int Curl_nss_init(void)
+static int nss_init(void)
 {
   /* curl_global_init() is not thread-safe so this test is ok */
   if(nss_initlock == NULL) {
@@ -1456,14 +1450,14 @@ CURLcode Curl_nss_force_init(struct Curl_easy *data)
   }
 
   PR_Lock(nss_initlock);
-  result = nss_init(data);
+  result = nss_setup(data);
   PR_Unlock(nss_initlock);
 
   return result;
 }
 
 /* Global cleanup */
-static void Curl_nss_cleanup(void)
+static void nss_cleanup(void)
 {
   /* This function isn't required to be threadsafe and this is only done
    * as a safety feature.
@@ -1503,7 +1497,7 @@ static void Curl_nss_cleanup(void)
  *     0 means the connection has been closed
  *    -1 means the connection status is unknown
  */
-static int Curl_nss_check_cxn(struct connectdata *conn)
+static int nss_check_cxn(struct connectdata *conn)
 {
   struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
   struct ssl_backend_data *backend = connssl->backend;
@@ -1522,7 +1516,7 @@ static int Curl_nss_check_cxn(struct connectdata *conn)
   return -1;  /* connection status unknown */
 }
 
-static void nss_close(struct ssl_connect_data *connssl)
+static void close_one(struct ssl_connect_data *connssl)
 {
   /* before the cleanup, check whether we are using a client certificate */
   struct ssl_backend_data *backend = connssl->backend;
@@ -1552,7 +1546,8 @@ static void nss_close(struct ssl_connect_data *connssl)
 /*
  * This function is called when an SSL connection is closed.
  */
-static void Curl_nss_close(struct connectdata *conn, int sockindex)
+static void nss_close(struct Curl_easy *data, struct connectdata *conn,
+                      int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 #ifndef CURL_DISABLE_PROXY
@@ -1560,6 +1555,7 @@ static void Curl_nss_close(struct connectdata *conn, int sockindex)
 #endif
   struct ssl_backend_data *backend = connssl->backend;
 
+  (void)data;
   if(backend->handle
 #ifndef CURL_DISABLE_PROXY
     || connssl_proxy->backend->handle
@@ -1578,9 +1574,9 @@ static void Curl_nss_close(struct connectdata *conn, int sockindex)
        a double close leading to crash. */
     connssl_proxy->backend->handle = NULL;
 
-  nss_close(connssl_proxy);
+  close_one(connssl_proxy);
 #endif
-  nss_close(connssl);
+  close_one(connssl);
 }
 
 /* return true if NSS can provide error code (and possibly msg) for the
@@ -1616,10 +1612,10 @@ static bool is_cc_error(PRInt32 err)
 static Curl_recv nss_recv;
 static Curl_send nss_send;
 
-static CURLcode nss_load_ca_certificates(struct connectdata *conn,
+static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
+                                         struct connectdata *conn,
                                          int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   const char *cafile = SSL_CONN_CONFIG(CAfile);
   const char *capath = SSL_CONN_CONFIG(CApath);
   bool use_trust_module;
@@ -1631,9 +1627,8 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
   if(capath && !capath[0])
     capath = NULL;
 
-  infof(data, "  CAfile: %s\n  CApath: %s\n",
-      cafile ? cafile : "none",
-      capath ? capath : "none");
+  infof(data, " CAfile: %s\n", cafile ? cafile : "none");
+  infof(data, " CApath: %s\n", capath ? capath : "none");
 
   /* load libnssckbi.so if no other trust roots were specified */
   use_trust_module = !cafile && !capath;
@@ -1673,7 +1668,8 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
       if(!dir)
         return CURLE_SSL_CACERT_BADFILE;
 
-      while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
+      while((entry =
+             PR_ReadDir(dir, (PRDirFlags)(PR_SKIP_BOTH | PR_SKIP_HIDDEN)))) {
         char *fullpath = aprintf("%s/%s", capath, entry->name);
         if(!fullpath) {
           PR_CloseDir(dir);
@@ -1824,26 +1820,20 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
   return CURLE_OK;
 }
 
-static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
+static CURLcode nss_setup_connect(struct Curl_easy *data,
+                                  struct connectdata *conn, int sockindex)
 {
   PRFileDesc *model = NULL;
   PRFileDesc *nspr_io = NULL;
   PRFileDesc *nspr_io_stub = NULL;
   PRBool ssl_no_cache;
   PRBool ssl_cbc_random_iv;
-  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd = conn->sock[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   CURLcode result;
   bool second_layer = FALSE;
   SSLVersionRange sslver_supported;
-#ifndef CURL_DISABLE_PROXY
-  const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
-    conn->host.name;
-#else
-  const char *hostname = conn->host.name;
-#endif
 
   SSLVersionRange sslver = {
     SSL_LIBRARY_VERSION_TLS_1_0,  /* min */
@@ -1860,11 +1850,11 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
 
   backend->data = data;
 
-  /* list of all NSS objects we need to destroy in Curl_nss_close() */
+  /* list of all NSS objects we need to destroy in nss_do_close() */
   Curl_llist_init(&backend->obj_list, nss_destroy_object);
 
   PR_Lock(nss_initlock);
-  result = nss_init(conn->data);
+  result = nss_setup(data);
   if(result) {
     PR_Unlock(nss_initlock);
     goto error;
@@ -1944,25 +1934,20 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
 
   /* bypass the default SSL_AuthCertificate() hook in case we do not want to
    * verify peer */
-  if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
+  if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess)
     goto error;
 
   /* not checked yet */
-#ifndef CURL_DISABLE_PROXY
-  if(SSL_IS_PROXY())
-    data->set.proxy_ssl.certverifyresult = 0;
-  else
-#endif
-    data->set.ssl.certverifyresult = 0;
+  SSL_SET_OPTION_LVALUE(certverifyresult) = 0;
 
-  if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
+  if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess)
     goto error;
 
-  if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
+  if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess)
     goto error;
 
   {
-    const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
+    const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
     if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
       /* not a fatal error because we are not going to verify the peer */
       infof(data, "warning: CA certificates failed to load\n");
@@ -1981,14 +1966,15 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
     infof(data, "  CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
   }
 
-  if(SSL_SET_OPTION(cert)) {
-    char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
+  if(SSL_SET_OPTION(primary.clientcert)) {
+    char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert));
     if(nickname) {
       /* we are not going to use libnsspem.so to read the client cert */
       backend->obj_clicert = NULL;
     }
     else {
-      CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
+      CURLcode rv = cert_stuff(data, conn, sockindex,
+                               SSL_SET_OPTION(primary.clientcert),
                                SSL_SET_OPTION(key));
       if(rv) {
         /* failf() is already done in cert_stuff() */
@@ -2086,7 +2072,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
       goto error;
 
     if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
-        conn) != SECSuccess)
+        data) != SECSuccess)
       goto error;
   }
 #endif
@@ -2124,11 +2110,11 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
     goto error;
 
   /* propagate hostname to the TLS layer */
-  if(SSL_SetURL(backend->handle, hostname) != SECSuccess)
+  if(SSL_SetURL(backend->handle, SSL_HOST_NAME()) != SECSuccess)
     goto error;
 
   /* prevent NSS from re-using the session for a different hostname */
-  if(SSL_SetSockPeerID(backend->handle, hostname) != SECSuccess)
+  if(SSL_SetSockPeerID(backend->handle, SSL_HOST_NAME()) != SECSuccess)
     goto error;
 
   return CURLE_OK;
@@ -2140,25 +2126,13 @@ error:
   return nss_fail_connect(connssl, data, result);
 }
 
-static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
+static CURLcode nss_do_connect(struct Curl_easy *data,
+                               struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_SSL_CONNECT_ERROR;
   PRUint32 timeout;
-#ifndef CURL_DISABLE_PROXY
-  long * const certverifyresult = SSL_IS_PROXY() ?
-    &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
-  const char * const pinnedpubkey = SSL_IS_PROXY() ?
-              data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
-              data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
-#else
-  long * const certverifyresult = &data->set.ssl.certverifyresult;
-  const char * const pinnedpubkey =
-              data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
-#endif
-
 
   /* check timeout situation */
   const timediff_t time_left = Curl_timeleft(data, NULL, TRUE);
@@ -2174,14 +2148,14 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
     if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
       /* blocking direction is updated by nss_update_connecting_state() */
       return CURLE_AGAIN;
-    else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
+    else if(SSL_SET_OPTION(certverifyresult) == SSL_ERROR_BAD_CERT_DOMAIN)
       result = CURLE_PEER_FAILED_VERIFICATION;
-    else if(*certverifyresult != 0)
+    else if(SSL_SET_OPTION(certverifyresult) != 0)
       result = CURLE_PEER_FAILED_VERIFICATION;
     goto error;
   }
 
-  result = display_conn_info(conn, backend->handle);
+  result = display_conn_info(data, backend->handle);
   if(result)
     goto error;
 
@@ -2204,7 +2178,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
     }
   }
 
-  result = cmp_peer_pubkey(connssl, pinnedpubkey);
+  result = cmp_peer_pubkey(connssl, SSL_PINNED_PUB_KEY());
   if(result)
     /* status already printed */
     goto error;
@@ -2215,11 +2189,11 @@ error:
   return nss_fail_connect(connssl, data, result);
 }
 
-static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
+static CURLcode nss_connect_common(struct Curl_easy *data,
+                                   struct connectdata *conn, int sockindex,
                                    bool *done)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct Curl_easy *data = conn->data;
   const bool blocking = (done == NULL);
   CURLcode result;
 
@@ -2230,7 +2204,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
   }
 
   if(connssl->connecting_state == ssl_connect_1) {
-    result = nss_setup_connect(conn, sockindex);
+    result = nss_setup_connect(data, conn, sockindex);
     if(result)
       /* we do not expect CURLE_AGAIN from nss_setup_connect() */
       return result;
@@ -2243,7 +2217,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
   if(result)
     return result;
 
-  result = nss_do_connect(conn, sockindex);
+  result = nss_do_connect(data, conn, sockindex);
   switch(result) {
   case CURLE_OK:
     break;
@@ -2276,30 +2250,33 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
   return CURLE_OK;
 }
 
-static CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
+static CURLcode nss_connect(struct Curl_easy *data, struct connectdata *conn,
+                            int sockindex)
 {
-  return nss_connect_common(conn, sockindex, /* blocking */ NULL);
+  return nss_connect_common(data, conn, sockindex, /* blocking */ NULL);
 }
 
-static CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
-                                             int sockindex, bool *done)
+static CURLcode nss_connect_nonblocking(struct Curl_easy *data,
+                                        struct connectdata *conn,
+                                        int sockindex, bool *done)
 {
-  return nss_connect_common(conn, sockindex, done);
+  return nss_connect_common(data, conn, sockindex, done);
 }
 
-static ssize_t nss_send(struct connectdata *conn,  /* connection data */
+static ssize_t nss_send(struct Curl_easy *data,    /* transfer */
                         int sockindex,             /* socketindex */
                         const void *mem,           /* send this data */
                         size_t len,                /* amount to write */
                         CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   ssize_t rc;
 
   /* The SelectClientCert() hook uses this for infof() and failf() but the
      handle stored in nss_setup_connect() could have already been freed. */
-  backend->data = conn->data;
+  backend->data = data;
 
   rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
   if(rc < 0) {
@@ -2309,10 +2286,10 @@ static ssize_t nss_send(struct connectdata *conn,  /* connection data */
     else {
       /* print the error number and error string */
       const char *err_name = nss_error_to_name(err);
-      infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);
+      infof(data, "SSL write: error %d (%s)\n", err, err_name);
 
       /* print a human-readable message describing the error if available */
-      nss_print_error_message(conn->data, err);
+      nss_print_error_message(data, err);
 
       *curlcode = (is_cc_error(err))
         ? CURLE_SSL_CERTPROBLEM
@@ -2325,19 +2302,20 @@ static ssize_t nss_send(struct connectdata *conn,  /* connection data */
   return rc; /* number of bytes */
 }
 
-static ssize_t nss_recv(struct connectdata *conn,  /* connection data */
+static ssize_t nss_recv(struct Curl_easy *data,    /* transfer */
                         int sockindex,             /* socketindex */
-                        char *buf,                 /* store read data here */
-                        size_t buffersize,         /* max amount to read */
+                        char *buf,             /* store read data here */
+                        size_t buffersize,     /* max amount to read */
                         CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   ssize_t nread;
 
   /* The SelectClientCert() hook uses this for infof() and failf() but the
      handle stored in nss_setup_connect() could have already been freed. */
-  backend->data = conn->data;
+  backend->data = data;
 
   nread = PR_Recv(backend->handle, buf, (int)buffersize, 0,
                   PR_INTERVAL_NO_WAIT);
@@ -2350,10 +2328,10 @@ static ssize_t nss_recv(struct connectdata *conn,  /* connection data */
     else {
       /* print the error number and error string */
       const char *err_name = nss_error_to_name(err);
-      infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);
+      infof(data, "SSL read: errno %d (%s)\n", err, err_name);
 
       /* print a human-readable message describing the error if available */
-      nss_print_error_message(conn->data, err);
+      nss_print_error_message(data, err);
 
       *curlcode = (is_cc_error(err))
         ? CURLE_SSL_CERTPROBLEM
@@ -2366,9 +2344,9 @@ static ssize_t nss_recv(struct connectdata *conn,  /* connection data */
   return nread;
 }
 
-static size_t Curl_nss_version(char *buffer, size_t size)
+static size_t nss_version(char *buffer, size_t size)
 {
-  return msnprintf(buffer, size, "NSS/%s", NSS_VERSION);
+  return msnprintf(buffer, size, "NSS/%s", NSS_GetVersion());
 }
 
 /* data might be NULL */
@@ -2379,9 +2357,9 @@ static int Curl_nss_seed(struct Curl_easy *data)
 }
 
 /* data might be NULL */
-static CURLcode Curl_nss_random(struct Curl_easy *data,
-                                unsigned char *entropy,
-                                size_t length)
+static CURLcode nss_random(struct Curl_easy *data,
+                           unsigned char *entropy,
+                           size_t length)
 {
   Curl_nss_seed(data);  /* Initiate the seed if not already done */
 
@@ -2392,28 +2370,10 @@ static CURLcode Curl_nss_random(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */
-                                size_t tmplen,
-                                unsigned char *md5sum, /* output */
-                                size_t md5len)
-{
-  PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
-  unsigned int MD5out;
-
-  if(!MD5pw)
-    return CURLE_NOT_BUILT_IN;
-
-  PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
-  PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
-  PK11_DestroyContext(MD5pw, PR_TRUE);
-
-  return CURLE_OK;
-}
-
-static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */
-                               size_t tmplen,
-                               unsigned char *sha256sum, /* output */
-                               size_t sha256len)
+static CURLcode nss_sha256sum(const unsigned char *tmp, /* input */
+                              size_t tmplen,
+                              unsigned char *sha256sum, /* output */
+                              size_t sha256len)
 {
   PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
   unsigned int SHA256out;
@@ -2428,7 +2388,7 @@ static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */
   return CURLE_OK;
 }
 
-static bool Curl_nss_cert_status_request(void)
+static bool nss_cert_status_request(void)
 {
 #ifdef SSL_ENABLE_OCSP_STAPLING
   return TRUE;
@@ -2437,7 +2397,7 @@ static bool Curl_nss_cert_status_request(void)
 #endif
 }
 
-static bool Curl_nss_false_start(void)
+static bool nss_false_start(void)
 {
 #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
   return TRUE;
@@ -2446,7 +2406,7 @@ static bool Curl_nss_false_start(void)
 #endif
 }
 
-static void *Curl_nss_get_internals(struct ssl_connect_data *connssl,
+static void *nss_get_internals(struct ssl_connect_data *connssl,
                                     CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
@@ -2464,28 +2424,27 @@ const struct Curl_ssl Curl_ssl_nss = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_nss_init,                /* init */
-  Curl_nss_cleanup,             /* cleanup */
-  Curl_nss_version,             /* version */
-  Curl_nss_check_cxn,           /* check_cxn */
+  nss_init,                     /* init */
+  nss_cleanup,                  /* cleanup */
+  nss_version,                  /* version */
+  nss_check_cxn,                /* check_cxn */
   /* NSS has no shutdown function provided and thus always fail */
   Curl_none_shutdown,           /* shutdown */
   Curl_none_data_pending,       /* data_pending */
-  Curl_nss_random,              /* random */
-  Curl_nss_cert_status_request, /* cert_status_request */
-  Curl_nss_connect,             /* connect */
-  Curl_nss_connect_nonblocking, /* connect_nonblocking */
-  Curl_nss_get_internals,       /* get_internals */
-  Curl_nss_close,               /* close_one */
+  nss_random,                   /* random */
+  nss_cert_status_request,      /* cert_status_request */
+  nss_connect,                  /* connect */
+  nss_connect_nonblocking,      /* connect_nonblocking */
+  nss_get_internals,            /* get_internals */
+  nss_close,                    /* close_one */
   Curl_none_close_all,          /* close_all */
   /* NSS has its own session ID cache */
   Curl_none_session_free,       /* session_free */
   Curl_none_set_engine,         /* set_engine */
   Curl_none_set_engine_default, /* set_engine_default */
   Curl_none_engines_list,       /* engines_list */
-  Curl_nss_false_start,         /* false_start */
-  Curl_nss_md5sum,              /* md5sum */
-  Curl_nss_sha256sum            /* sha256sum */
+  nss_false_start,              /* false_start */
+  nss_sha256sum                 /* sha256sum */
 };
 
 #endif /* USE_NSS */
index 41e51b0..37b3646 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 1685a4a..784d9f7 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
 /* Wincrypt must be included before anything that could include OpenSSL. */
 #if defined(USE_WIN32_CRYPTO)
 #include <wincrypt.h>
+/* Undefine wincrypt conflicting symbols for BoringSSL. */
+#undef X509_NAME
+#undef X509_EXTENSIONS
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef PKCS7_SIGNER_INFO
+#undef OCSP_REQUEST
+#undef OCSP_RESPONSE
 #endif
 
 #include "urldata.h"
      !defined(OPENSSL_IS_BORINGSSL))
 #define HAVE_SSL_CTX_SET_CIPHERSUITES
 #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
+/* SET_EC_CURVES available under the same preconditions: see
+ * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
+ */
+#define HAVE_SSL_CTX_SET_EC_CURVES
 #endif
 
 #if defined(LIBRESSL_VERSION_NUMBER)
   "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
 #endif
 
+#ifdef HAVE_OPENSSL_SRP
+/* the function exists */
+#ifdef USE_TLS_SRP
+/* the functionality is not disabled */
+#define USE_OPENSSL_SRP
+#endif
+#endif
+
 struct ssl_backend_data {
   /* these ones requires specific SSL-types */
   SSL_CTX* ctx;
@@ -343,6 +362,18 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size)
   return buf;
 }
 
+/* Return an extra data index for the transfer data.
+ * This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
+ */
+static int ossl_get_ssl_data_index(void)
+{
+  static int ssl_ex_data_data_index = -1;
+  if(ssl_ex_data_data_index < 0) {
+    ssl_ex_data_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+  }
+  return ssl_ex_data_data_index;
+}
+
 /* Return an extra data index for the connection data.
  * This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
  */
@@ -391,7 +422,7 @@ static bool rand_enough(void)
   return (0 != RAND_status()) ? TRUE : FALSE;
 }
 
-static CURLcode Curl_ossl_seed(struct Curl_easy *data)
+static CURLcode ossl_seed(struct Curl_easy *data)
 {
   /* we have the "SSL is seeded" boolean static to prevent multiple
      time-consuming seedings in vain */
@@ -553,8 +584,7 @@ static bool is_pkcs11_uri(const char *string)
 
 #endif
 
-static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
-                                     const char *engine);
+static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine);
 
 static int
 SSL_CTX_use_certificate_bio(SSL_CTX *ctx, BIO *in, int type,
@@ -681,7 +711,7 @@ SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
 }
 
 static
-int cert_stuff(struct connectdata *conn,
+int cert_stuff(struct Curl_easy *data,
                SSL_CTX* ctx,
                char *cert_file,
                BIO *cert_bio,
@@ -691,7 +721,6 @@ int cert_stuff(struct connectdata *conn,
                const char *key_type,
                char *key_passwd)
 {
-  struct Curl_easy *data = conn->data;
   char error_buffer[256];
   bool check_privkey = TRUE;
 
@@ -754,7 +783,7 @@ int cert_stuff(struct connectdata *conn,
          * cert_file is a PKCS#11 URI */
         if(!data->state.engine) {
           if(is_pkcs11_uri(cert_file)) {
-            if(Curl_ossl_set_engine(data, "pkcs11") != CURLE_OK) {
+            if(ossl_set_engine(data, "pkcs11") != CURLE_OK) {
               return 0;
             }
           }
@@ -953,7 +982,7 @@ int cert_stuff(struct connectdata *conn,
          * key_file is a PKCS#11 URI */
         if(!data->state.engine) {
           if(is_pkcs11_uri(key_file)) {
-            if(Curl_ossl_set_engine(data, "pkcs11") != CURLE_OK) {
+            if(ossl_set_engine(data, "pkcs11") != CURLE_OK) {
               return 0;
             }
           }
@@ -1065,9 +1094,6 @@ int cert_stuff(struct connectdata *conn,
 /* returns non-zero on failure */
 static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
 {
-#if 0
-  return X509_NAME_oneline(a, buf, size);
-#else
   BIO *bio_out = BIO_new(BIO_s_mem());
   BUF_MEM *biomem;
   int rc;
@@ -1089,7 +1115,6 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
   BIO_free(bio_out);
 
   return !rc;
-#endif
 }
 
 /**
@@ -1098,8 +1123,23 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
  * @retval 0 error initializing SSL
  * @retval 1 SSL initialized successfully
  */
-static int Curl_ossl_init(void)
+static int ossl_init(void)
 {
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) &&  \
+  !defined(LIBRESSL_VERSION_NUMBER)
+  const uint64_t flags =
+#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN
+    /* not present in BoringSSL */
+    OPENSSL_INIT_ENGINE_ALL_BUILTIN |
+#endif
+#ifdef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
+    OPENSSL_INIT_NO_LOAD_CONFIG |
+#else
+    OPENSSL_INIT_LOAD_CONFIG |
+#endif
+    0;
+  OPENSSL_init_ssl(flags, NULL);
+#else
   OPENSSL_load_builtin_modules();
 
 #ifdef USE_OPENSSL_ENGINE
@@ -1118,10 +1158,6 @@ static int Curl_ossl_init(void)
                          CONF_MFLAGS_IGNORE_MISSING_FILE);
 #endif
 
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
-    !defined(LIBRESSL_VERSION_NUMBER)
-  /* OpenSSL 1.1.0+ takes care of initialization itself */
-#else
   /* Lets get nice error messages */
   SSL_load_error_strings();
 
@@ -1135,14 +1171,15 @@ static int Curl_ossl_init(void)
   Curl_tls_keylog_open();
 
   /* Initialize the extra data indexes */
-  if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0)
+  if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_conn_index() < 0 ||
+     ossl_get_ssl_sockindex_index() < 0)
     return 0;
 
   return 1;
 }
 
 /* Global cleanup */
-static void Curl_ossl_cleanup(void)
+static void ossl_cleanup(void)
 {
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
     !defined(LIBRESSL_VERSION_NUMBER)
@@ -1186,7 +1223,7 @@ static void Curl_ossl_cleanup(void)
  *     0 means the connection has been closed
  *    -1 means the connection status is unknown
  */
-static int Curl_ossl_check_cxn(struct connectdata *conn)
+static int ossl_check_cxn(struct connectdata *conn)
 {
   /* SSL_peek takes data out of the raw recv buffer without peeking so we use
      recv MSG_PEEK instead. Bug #795 */
@@ -1232,8 +1269,7 @@ static int Curl_ossl_check_cxn(struct connectdata *conn)
 
 /* Selects an OpenSSL crypto engine
  */
-static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
-                                     const char *engine)
+static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine)
 {
 #ifdef USE_OPENSSL_ENGINE
   ENGINE *e;
@@ -1263,7 +1299,7 @@ static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
     char buf[256];
 
     ENGINE_free(e);
-    failf(data, "Failed to initialise SSL Engine '%s':\n%s",
+    failf(data, "Failed to initialise SSL Engine '%s': %s",
           engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
     return CURLE_SSL_ENGINE_INITFAILED;
   }
@@ -1278,7 +1314,7 @@ static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
 
 /* Sets engine as default for all SSL operations
  */
-static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
+static CURLcode ossl_set_engine_default(struct Curl_easy *data)
 {
 #ifdef USE_OPENSSL_ENGINE
   if(data->state.engine) {
@@ -1300,7 +1336,7 @@ static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
 
 /* Return list of OpenSSL crypto engine names.
  */
-static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
+static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
 {
   struct curl_slist *list = NULL;
 #ifdef USE_OPENSSL_ENGINE
@@ -1320,7 +1356,7 @@ static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
   return list;
 }
 
-static void ossl_close(struct ssl_connect_data *connssl)
+static void ossl_closeone(struct ssl_connect_data *connssl)
 {
   struct ssl_backend_data *backend = connssl->backend;
   if(backend->handle) {
@@ -1339,11 +1375,13 @@ static void ossl_close(struct ssl_connect_data *connssl)
 /*
  * This function is called when an SSL connection is closed.
  */
-static void Curl_ossl_close(struct connectdata *conn, int sockindex)
+static void ossl_close(struct Curl_easy *data, struct connectdata *conn,
+                       int sockindex)
 {
-  ossl_close(&conn->ssl[sockindex]);
+  (void) data;
+  ossl_closeone(&conn->ssl[sockindex]);
 #ifndef CURL_DISABLE_PROXY
-  ossl_close(&conn->proxy_ssl[sockindex]);
+  ossl_closeone(&conn->proxy_ssl[sockindex]);
 #endif
 }
 
@@ -1351,11 +1389,11 @@ static void Curl_ossl_close(struct connectdata *conn, int sockindex)
  * This function is called to shut down the SSL layer but keep the
  * socket open (CCC - Clear Command Channel)
  */
-static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
+static int ossl_shutdown(struct Curl_easy *data,
+                         struct connectdata *conn, int sockindex)
 {
   int retval = 0;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct Curl_easy *data = conn->data;
   char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
                     to be at least 256 bytes long. */
   unsigned long sslerror;
@@ -1407,7 +1445,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
         default:
           /* openssl/ssl.h says "look at error stack/return value/errno" */
           sslerror = ERR_get_error();
-          failf(conn->data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
+          failf(data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
                 (sslerror ?
                  ossl_strerror(sslerror, buf, sizeof(buf)) :
                  SSL_ERROR_to_str(err)),
@@ -1452,7 +1490,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
   return retval;
 }
 
-static void Curl_ossl_session_free(void *ptr)
+static void ossl_session_free(void *ptr)
 {
   /* free the ID */
   SSL_SESSION_free(ptr);
@@ -1462,7 +1500,7 @@ static void Curl_ossl_session_free(void *ptr)
  * This function is called when the 'data' struct is going away. Close
  * down everything and free all resources!
  */
-static void Curl_ossl_close_all(struct Curl_easy *data)
+static void ossl_close_all(struct Curl_easy *data)
 {
 #ifdef USE_OPENSSL_ENGINE
   if(data->state.engine) {
@@ -1556,12 +1594,12 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
    in the certificate and must exactly match the IP in the URI.
 
 */
-static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
+static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
+                           X509 *server_cert)
 {
   bool matched = FALSE;
   int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
   size_t addrlen = 0;
-  struct Curl_easy *data = conn->data;
   STACK_OF(GENERAL_NAME) *altnames;
 #ifdef ENABLE_IPV6
   struct in6_addr addr;
@@ -1571,16 +1609,8 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
   CURLcode result = CURLE_OK;
   bool dNSName = FALSE; /* if a dNSName field exists in the cert */
   bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
-#ifndef CURL_DISABLE_PROXY
-  const char * const hostname = SSL_IS_PROXY() ?
-    conn->http_proxy.host.name : conn->host.name;
-  const char * const dispname = SSL_IS_PROXY() ?
-    conn->http_proxy.host.dispname : conn->host.dispname;
-#else
-  /* disabled proxy support */
-  const char * const hostname = conn->host.name;
-  const char * const dispname = conn->host.dispname;
-#endif
+  const char * const hostname = SSL_HOST_NAME();
+  const char * const dispname = SSL_HOST_DISPNAME();
 
 #ifdef ENABLE_IPV6
   if(conn->bits.ipv6_ip &&
@@ -1764,19 +1794,23 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
 
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
     !defined(OPENSSL_NO_OCSP)
-static CURLcode verifystatus(struct connectdata *conn,
+static CURLcode verifystatus(struct Curl_easy *data,
                              struct ssl_connect_data *connssl)
 {
   int i, ocsp_status;
   unsigned char *status;
   const unsigned char *p;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   OCSP_RESPONSE *rsp = NULL;
   OCSP_BASICRESP *br = NULL;
   X509_STORE     *st = NULL;
   STACK_OF(X509) *ch = NULL;
   struct ssl_backend_data *backend = connssl->backend;
+  X509 *cert;
+  OCSP_CERTID *id = NULL;
+  int cert_status, crl_reason;
+  ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+  int ret;
 
   long len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status);
 
@@ -1845,43 +1879,63 @@ static CURLcode verifystatus(struct connectdata *conn,
     goto end;
   }
 
-  for(i = 0; i < OCSP_resp_count(br); i++) {
-    int cert_status, crl_reason;
-    OCSP_SINGLERESP *single = NULL;
-
-    ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+  /* Compute the certificate's ID */
+  cert = SSL_get_peer_certificate(backend->handle);
+  if(!cert) {
+    failf(data, "Error getting peer certificate");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
 
-    single = OCSP_resp_get0(br, i);
-    if(!single)
-      continue;
+  for(i = 0; i < sk_X509_num(ch); i++) {
+    X509 *issuer = sk_X509_value(ch, i);
+    if(X509_check_issued(issuer, cert) == X509_V_OK) {
+      id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
+      break;
+    }
+  }
+  X509_free(cert);
 
-    cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
-                                          &thisupd, &nextupd);
+  if(!id) {
+    failf(data, "Error computing OCSP ID");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
 
-    if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
-      failf(data, "OCSP response has expired");
-      result = CURLE_SSL_INVALIDCERTSTATUS;
-      goto end;
-    }
+  /* Find the single OCSP response corresponding to the certificate ID */
+  ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev,
+                              &thisupd, &nextupd);
+  OCSP_CERTID_free(id);
+  if(ret != 1) {
+    failf(data, "Could not find certificate ID in OCSP response");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
 
-    infof(data, "SSL certificate status: %s (%d)\n",
-          OCSP_cert_status_str(cert_status), cert_status);
+  /* Validate the corresponding single OCSP response */
+  if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
+    failf(data, "OCSP response has expired");
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
+  }
 
-    switch(cert_status) {
-      case V_OCSP_CERTSTATUS_GOOD:
-        break;
+  infof(data, "SSL certificate status: %s (%d)\n",
+        OCSP_cert_status_str(cert_status), cert_status);
 
-      case V_OCSP_CERTSTATUS_REVOKED:
-        result = CURLE_SSL_INVALIDCERTSTATUS;
+  switch(cert_status) {
+  case V_OCSP_CERTSTATUS_GOOD:
+    break;
 
-        failf(data, "SSL certificate revocation reason: %s (%d)",
-              OCSP_crl_reason_str(crl_reason), crl_reason);
-        goto end;
+  case V_OCSP_CERTSTATUS_REVOKED:
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    failf(data, "SSL certificate revocation reason: %s (%d)",
+          OCSP_crl_reason_str(crl_reason), crl_reason);
+    goto end;
 
-      case V_OCSP_CERTSTATUS_UNKNOWN:
-        result = CURLE_SSL_INVALIDCERTSTATUS;
-        goto end;
-    }
+  case V_OCSP_CERTSTATUS_UNKNOWN:
+  default:
+    result = CURLE_SSL_INVALIDCERTSTATUS;
+    goto end;
   }
 
 end:
@@ -2163,15 +2217,15 @@ select_next_proto_cb(SSL *ssl,
                      const unsigned char *in, unsigned int inlen,
                      void *arg)
 {
-  struct connectdata *conn = (struct connectdata*) arg;
-
+  struct Curl_easy *data = (struct Curl_easy *)arg;
+  struct connectdata *conn = data->conn;
   (void)ssl;
 
 #ifdef USE_NGHTTP2
-  if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 &&
+  if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
      !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID,
                            NGHTTP2_PROTO_VERSION_ID_LEN)) {
-    infof(conn->data, "NPN, negotiated HTTP2 (%s)\n",
+    infof(data, "NPN, negotiated HTTP2 (%s)\n",
           NGHTTP2_PROTO_VERSION_ID);
     conn->negnpn = CURL_HTTP_VERSION_2;
     return SSL_TLSEXT_ERR_OK;
@@ -2180,12 +2234,12 @@ select_next_proto_cb(SSL *ssl,
 
   if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1,
                            ALPN_HTTP_1_1_LENGTH)) {
-    infof(conn->data, "NPN, negotiated HTTP1.1\n");
+    infof(data, "NPN, negotiated HTTP1.1\n");
     conn->negnpn = CURL_HTTP_VERSION_1_1;
     return SSL_TLSEXT_ERR_OK;
   }
 
-  infof(conn->data, "NPN, no overlap, use HTTP1.1\n");
+  infof(data, "NPN, no overlap, use HTTP1.1\n");
   *out = (unsigned char *)ALPN_HTTP_1_1;
   *outlen = ALPN_HTTP_1_1_LENGTH;
   conn->negnpn = CURL_HTTP_VERSION_1_1;
@@ -2316,16 +2370,14 @@ typedef long ctx_option_t;
 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */
 static CURLcode
 set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
-                              struct connectdata *conn, int sockindex)
+                               struct Curl_easy *data,
+                               struct connectdata *conn, int sockindex)
 {
-#if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION)
-  /* convoluted #if condition just to avoid compiler warnings on unused
-     variable */
-  struct Curl_easy *data = conn->data;
-#endif
   long ssl_version = SSL_CONN_CONFIG(version);
   long ssl_version_max = SSL_CONN_CONFIG(version_max);
 
+  (void) data; /* In case it's unused. */
+
   switch(ssl_version) {
     case CURL_SSLVERSION_TLSv1_3:
 #ifdef TLS1_3_VERSION
@@ -2400,17 +2452,18 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
   struct Curl_easy *data;
   int sockindex;
   curl_socket_t *sockindex_ptr;
+  int data_idx = ossl_get_ssl_data_index();
   int connectdata_idx = ossl_get_ssl_conn_index();
   int sockindex_idx = ossl_get_ssl_sockindex_index();
 
-  if(connectdata_idx < 0 || sockindex_idx < 0)
+  if(data_idx < 0 || connectdata_idx < 0 || sockindex_idx < 0)
     return 0;
 
   conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx);
   if(!conn)
     return 0;
 
-  data = conn->data;
+  data = (struct Curl_easy *) SSL_get_ex_data(ssl, data_idx);
 
   /* The sockindex has been stored as a pointer to an array element */
   sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx);
@@ -2420,19 +2473,19 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
     bool incache;
     void *old_ssl_sessionid = NULL;
 
-    Curl_ssl_sessionid_lock(conn);
-    incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
+    Curl_ssl_sessionid_lock(data);
+    incache = !(Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL,
                                       sockindex));
     if(incache) {
       if(old_ssl_sessionid != ssl_sessionid) {
         infof(data, "old SSL session ID is stale, removing\n");
-        Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+        Curl_ssl_delsessionid(data, old_ssl_sessionid);
         incache = FALSE;
       }
     }
 
     if(!incache) {
-      if(!Curl_ssl_addsessionid(conn, ssl_sessionid,
+      if(!Curl_ssl_addsessionid(data, conn, ssl_sessionid,
                                       0 /* unknown size */, sockindex)) {
         /* the session has been put into the session cache */
         res = 1;
@@ -2440,17 +2493,17 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
       else
         failf(data, "failed to store ssl session");
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   return res;
 }
 
-static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step1(struct Curl_easy *data,
+                                   struct connectdata *conn, int sockindex)
 {
   CURLcode result = CURLE_OK;
   char *ciphers;
-  struct Curl_easy *data = conn->data;
   SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
   X509_LOOKUP *lookup = NULL;
   curl_socket_t sockfd = conn->sock[sockindex];
@@ -2459,12 +2512,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
   bool sni;
-#ifndef CURL_DISABLE_PROXY
-  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
-    conn->host.name;
-#else
-  const char * const hostname = conn->host.name;
-#endif
+  const char * const hostname = SSL_HOST_NAME();
 
 #ifdef ENABLE_IPV6
   struct in6_addr addr;
@@ -2472,18 +2520,12 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   struct in_addr addr;
 #endif
 #endif
-#ifndef CURL_DISABLE_PROXY
-  long * const certverifyresult = SSL_IS_PROXY() ?
-    &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
-#else
-  long * const certverifyresult = &data->set.ssl.certverifyresult;
-#endif
   const long int ssl_version = SSL_CONN_CONFIG(version);
-#ifdef USE_TLS_SRP
+#ifdef USE_OPENSSL_SRP
   const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype);
 #endif
-  char * const ssl_cert = SSL_SET_OPTION(cert);
-  const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob);
+  char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
+  const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
   const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
   const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
   const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
@@ -2496,11 +2538,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
 
   /* Make funny stuff to get random input */
-  result = Curl_ossl_seed(data);
+  result = ossl_seed(data);
   if(result)
     return result;
 
-  *certverifyresult = !X509_V_OK;
+  SSL_SET_OPTION_LVALUE(certverifyresult) = !X509_V_OK;
 
   /* check to see if we've been told to use an explicit SSL/TLS version */
 
@@ -2524,7 +2566,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
     failf(data, OSSL_PACKAGE " was built without SSLv2 support");
     return CURLE_NOT_BUILT_IN;
 #else
-#ifdef USE_TLS_SRP
+#ifdef USE_OPENSSL_SRP
     if(ssl_authtype == CURL_TLSAUTH_SRP)
       return CURLE_SSL_CONNECT_ERROR;
 #endif
@@ -2537,7 +2579,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
     failf(data, OSSL_PACKAGE " was built without SSLv3 support");
     return CURLE_NOT_BUILT_IN;
 #else
-#ifdef USE_TLS_SRP
+#ifdef USE_OPENSSL_SRP
     if(ssl_authtype == CURL_TLSAUTH_SRP)
       return CURLE_SSL_CONNECT_ERROR;
 #endif
@@ -2682,7 +2724,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
       result = set_ssl_version_min_max(backend->ctx, conn);
 #else
-      result = set_ssl_version_min_max_legacy(&ctx_options, conn, sockindex);
+      result = set_ssl_version_min_max_legacy(&ctx_options, data, conn,
+                                              sockindex);
 #endif
       if(result != CURLE_OK)
         return result;
@@ -2697,7 +2740,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 
 #ifdef HAS_NPN
   if(conn->bits.tls_enable_npn)
-    SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, conn);
+    SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, data);
 #endif
 
 #ifdef HAS_ALPN
@@ -2735,33 +2778,33 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
     BIO *ssl_cert_bio = NULL;
     BIO *ssl_key_bio = NULL;
-    int result_cert_stuff;
     if(ssl_cert_blob) {
       /* the typecast of blob->len is fine since it is guaranteed to never be
          larger than CURL_MAX_INPUT_LENGTH */
       ssl_cert_bio = BIO_new_mem_buf(ssl_cert_blob->data,
                                      (int)ssl_cert_blob->len);
       if(!ssl_cert_bio)
-        return CURLE_SSL_CERTPROBLEM;
+        result = CURLE_OUT_OF_MEMORY;
     }
-    if(SSL_SET_OPTION(key_blob)) {
+    if(!result && SSL_SET_OPTION(key_blob)) {
       ssl_key_bio = BIO_new_mem_buf(SSL_SET_OPTION(key_blob)->data,
                                     (int)SSL_SET_OPTION(key_blob)->len);
       if(!ssl_key_bio)
-        return CURLE_SSL_CERTPROBLEM;
+        result = CURLE_OUT_OF_MEMORY;
     }
-    result_cert_stuff = cert_stuff(conn, backend->ctx,
+    if(!result &&
+       !cert_stuff(data, backend->ctx,
                    ssl_cert, ssl_cert_bio, ssl_cert_type,
                    SSL_SET_OPTION(key), ssl_key_bio,
-                   SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd));
+                   SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd)))
+      result = CURLE_SSL_CERTPROBLEM;
     if(ssl_cert_bio)
       BIO_free(ssl_cert_bio);
     if(ssl_key_bio)
       BIO_free(ssl_key_bio);
-    if(!result_cert_stuff) {
+    if(result)
       /* failf() is already done in cert_stuff() */
-      return CURLE_SSL_CERTPROBLEM;
-    }
+      return result;
   }
 
   ciphers = SSL_CONN_CONFIG(cipher_list);
@@ -2793,7 +2836,19 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   SSL_CTX_set_post_handshake_auth(backend->ctx, 1);
 #endif
 
-#ifdef USE_TLS_SRP
+#ifdef HAVE_SSL_CTX_SET_EC_CURVES
+  {
+    char *curves = SSL_CONN_CONFIG(curves);
+    if(curves) {
+      if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+        failf(data, "failed setting curves list: '%s'", curves);
+        return CURLE_SSL_CIPHER;
+      }
+    }
+  }
+#endif
+
+#ifdef USE_OPENSSL_SRP
   if(ssl_authtype == CURL_TLSAUTH_SRP) {
     char * const ssl_username = SSL_SET_OPTION(username);
 
@@ -2910,7 +2965,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
               /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is
                  good for all uses. If it returns zero, the certificate has no
                  valid uses." */
-              if(GetLastError() != CRYPT_E_NOT_FOUND)
+              if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
                 continue;
             }
             else {
@@ -2970,7 +3025,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   {
     if(ssl_cafile) {
       if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
-        if(verifypeer) {
+        if(verifypeer && !imported_native_ca) {
           /* Fail if we insist on successfully verifying the server. */
           failf(data, "error setting certificate file: %s", ssl_cafile);
           return CURLE_SSL_CACERT_BADFILE;
@@ -2978,11 +3033,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
         /* Continue with a warning if no certificate verif is required. */
         infof(data, "error setting certificate file, continuing anyway\n");
       }
-      infof(data, "  CAfile: %s\n", ssl_cafile);
+      infof(data, " CAfile: %s\n", ssl_cafile);
     }
     if(ssl_capath) {
       if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
-        if(verifypeer) {
+        if(verifypeer && !imported_native_ca) {
           /* Fail if we insist on successfully verifying the server. */
           failf(data, "error setting certificate path: %s", ssl_capath);
           return CURLE_SSL_CACERT_BADFILE;
@@ -2990,7 +3045,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
         /* Continue with a warning if no certificate verif is required. */
         infof(data, "error setting certificate path, continuing anyway\n");
       }
-      infof(data, "  CApath: %s\n", ssl_capath);
+      infof(data, " CApath: %s\n", ssl_capath);
     }
   }
 #else
@@ -3000,8 +3055,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
     if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) {
       if(verifypeer && !imported_native_ca) {
         /* Fail if we insist on successfully verifying the server. */
-        failf(data, "error setting certificate verify locations:\n"
-              "  CAfile: %s\n  CApath: %s",
+        failf(data, "error setting certificate verify locations:"
+              "  CAfile: %s CApath: %s",
               ssl_cafile ? ssl_cafile : "none",
               ssl_capath ? ssl_capath : "none");
         return CURLE_SSL_CACERT_BADFILE;
@@ -3015,11 +3070,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
       /* Everything is fine. */
       infof(data, "successfully set certificate verify locations:\n");
     }
-    infof(data,
-          "  CAfile: %s\n"
-          "  CApath: %s\n",
-          ssl_cafile ? ssl_cafile : "none",
-          ssl_capath ? ssl_capath : "none");
+    infof(data, " CAfile: %s\n", ssl_cafile ? ssl_cafile : "none");
+    infof(data, " CApath: %s\n", ssl_capath ? ssl_capath : "none");
   }
 #endif
 
@@ -3137,30 +3189,43 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 #ifdef ENABLE_IPV6
      (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
 #endif
-     sni &&
-     !SSL_set_tlsext_host_name(backend->handle, hostname))
-    infof(data, "WARNING: failed to configure server name indication (SNI) "
-          "TLS extension\n");
+     sni) {
+    size_t nlen = strlen(hostname);
+    if((long)nlen >= data->set.buffer_size)
+      /* this is seriously messed up */
+      return CURLE_SSL_CONNECT_ERROR;
+
+    /* RFC 6066 section 3 says the SNI field is case insensitive, but browsers
+       send the data lowercase and subsequently there are now numerous servers
+       out there that don't work unless the name is lowercased */
+    Curl_strntolower(data->state.buffer, hostname, nlen);
+    data->state.buffer[nlen] = 0;
+    if(!SSL_set_tlsext_host_name(backend->handle, data->state.buffer))
+      infof(data, "WARNING: failed to configure server name indication (SNI) "
+            "TLS extension\n");
+  }
 #endif
 
   /* Check if there's a cached ID we can/should use here! */
   if(SSL_SET_OPTION(primary.sessionid)) {
     void *ssl_sessionid = NULL;
+    int data_idx = ossl_get_ssl_data_index();
     int connectdata_idx = ossl_get_ssl_conn_index();
     int sockindex_idx = ossl_get_ssl_sockindex_index();
 
-    if(connectdata_idx >= 0 && sockindex_idx >= 0) {
+    if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0) {
       /* Store the data needed for the "new session" callback.
        * The sockindex is stored as a pointer to an array element. */
+      SSL_set_ex_data(backend->handle, data_idx, data);
       SSL_set_ex_data(backend->handle, connectdata_idx, conn);
       SSL_set_ex_data(backend->handle, sockindex_idx, conn->sock + sockindex);
     }
 
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
       /* we got a session id, use it! */
       if(!SSL_set_session(backend->handle, ssl_sessionid)) {
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(data, "SSL: SSL_set_session failed: %s",
               ossl_strerror(ERR_get_error(), error_buffer,
                             sizeof(error_buffer)));
@@ -3169,7 +3234,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
       /* Informational message */
       infof(data, "SSL re-using session ID\n");
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
 #ifndef CURL_DISABLE_PROXY
@@ -3196,17 +3261,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step2(struct Curl_easy *data,
+                                   struct connectdata *conn, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   int err;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-#ifndef CURL_DISABLE_PROXY
-  long * const certverifyresult = SSL_IS_PROXY() ?
-    &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
-#else
-  long * const certverifyresult = &data->set.ssl.certverifyresult;
-#endif
   struct ssl_backend_data *backend = connssl->backend;
   DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
               || ssl_connect_2_reading == connssl->connecting_state
@@ -3265,12 +3324,13 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
       reason = ERR_GET_REASON(errdetail);
 
       if((lib == ERR_LIB_SSL) &&
-         (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) {
+         ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) ||
+          (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
         result = CURLE_PEER_FAILED_VERIFICATION;
 
         lerr = SSL_get_verify_result(backend->handle);
         if(lerr != X509_V_OK) {
-          *certverifyresult = lerr;
+          SSL_SET_OPTION_LVALUE(certverifyresult) = lerr;
           msnprintf(error_buffer, sizeof(error_buffer),
                     "SSL certificate problem: %s",
                     X509_verify_cert_error_string(lerr));
@@ -3292,12 +3352,10 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
        * the SO_ERROR is also lost.
        */
       if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
+        const char * const hostname = SSL_HOST_NAME();
 #ifndef CURL_DISABLE_PROXY
-        const char * const hostname = SSL_IS_PROXY() ?
-          conn->http_proxy.host.name : conn->host.name;
         const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
 #else
-        const char * const hostname = conn->host.name;
         const long int port = conn->remote_port;
 #endif
         char extramsg[80]="";
@@ -3351,7 +3409,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
       else
         infof(data, "ALPN, server did not agree to a protocol\n");
 
-      Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+      Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
     }
 #endif
@@ -3457,14 +3515,12 @@ typedef size_t numcert_t;
 typedef int numcert_t;
 #endif
 
-static CURLcode get_cert_chain(struct connectdata *conn,
+static CURLcode get_cert_chain(struct Curl_easy *data,
                                struct ssl_connect_data *connssl)
-
 {
   CURLcode result;
   STACK_OF(X509) *sk;
   int i;
-  struct Curl_easy *data = conn->data;
   numcert_t numcerts;
   BIO *mem;
   struct ssl_backend_data *backend = connssl->backend;
@@ -3739,31 +3795,25 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
  * We check certificates to authenticate the server; otherwise we risk
  * man-in-the-middle attack.
  */
-static CURLcode servercert(struct connectdata *conn,
+static CURLcode servercert(struct Curl_easy *data,
+                           struct connectdata *conn,
                            struct ssl_connect_data *connssl,
                            bool strict)
 {
   CURLcode result = CURLE_OK;
   int rc;
   long lerr;
-  struct Curl_easy *data = conn->data;
   X509 *issuer;
   BIO *fp = NULL;
   char error_buffer[256]="";
   char buffer[2048];
   const char *ptr;
-#ifndef CURL_DISABLE_PROXY
-  long * const certverifyresult = SSL_IS_PROXY() ?
-    &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
-#else
-  long * const certverifyresult = &data->set.ssl.certverifyresult;
-#endif
   BIO *mem = BIO_new(BIO_s_mem());
   struct ssl_backend_data *backend = connssl->backend;
 
   if(data->set.ssl.certinfo)
     /* we've been asked to gather certificate info! */
-    (void)get_cert_chain(conn, connssl);
+    (void)get_cert_chain(data, connssl);
 
   backend->server_cert = SSL_get_peer_certificate(backend->handle);
   if(!backend->server_cert) {
@@ -3799,7 +3849,7 @@ static CURLcode servercert(struct connectdata *conn,
   BIO_free(mem);
 
   if(SSL_CONN_CONFIG(verifyhost)) {
-    result = verifyhost(conn, backend->server_cert);
+    result = verifyhost(data, conn, backend->server_cert);
     if(result) {
       X509_free(backend->server_cert);
       backend->server_cert = NULL;
@@ -3878,9 +3928,9 @@ static CURLcode servercert(struct connectdata *conn,
       X509_free(issuer);
     }
 
-    lerr = *certverifyresult = SSL_get_verify_result(backend->handle);
-
-    if(*certverifyresult != X509_V_OK) {
+    lerr = SSL_get_verify_result(backend->handle);
+    SSL_SET_OPTION_LVALUE(certverifyresult) = lerr;
+    if(lerr != X509_V_OK) {
       if(SSL_CONN_CONFIG(verifypeer)) {
         /* We probably never reach this, because SSL_connect() will fail
            and we return earlier if verifypeer is set? */
@@ -3901,7 +3951,7 @@ static CURLcode servercert(struct connectdata *conn,
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
     !defined(OPENSSL_NO_OCSP)
   if(SSL_CONN_CONFIG(verifystatus)) {
-    result = verifystatus(conn, connssl);
+    result = verifystatus(data, connssl);
     if(result) {
       X509_free(backend->server_cert);
       backend->server_cert = NULL;
@@ -3929,7 +3979,8 @@ static CURLcode servercert(struct connectdata *conn,
   return result;
 }
 
-static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step3(struct Curl_easy *data,
+                                   struct connectdata *conn, int sockindex)
 {
   CURLcode result = CURLE_OK;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -3943,8 +3994,8 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
    * operations.
    */
 
-  result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) ||
-                                      SSL_CONN_CONFIG(verifyhost)));
+  result = servercert(data, conn, connssl, (SSL_CONN_CONFIG(verifypeer) ||
+                                            SSL_CONN_CONFIG(verifyhost)));
 
   if(!result)
     connssl->connecting_state = ssl_connect_done;
@@ -3955,13 +4006,13 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
 static Curl_recv ossl_recv;
 static Curl_send ossl_send;
 
-static CURLcode ossl_connect_common(struct connectdata *conn,
+static CURLcode ossl_connect_common(struct Curl_easy *data,
+                                    struct connectdata *conn,
                                     int sockindex,
                                     bool nonblocking,
                                     bool *done)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   int what;
@@ -3982,7 +4033,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
       return CURLE_OPERATION_TIMEDOUT;
     }
 
-    result = ossl_connect_step1(conn, sockindex);
+    result = ossl_connect_step1(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -4034,7 +4085,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
      * before step2 has completed while ensuring that a client using select()
      * or epoll() will always have a valid fdset to wait on.
      */
-    result = ossl_connect_step2(conn, sockindex);
+    result = ossl_connect_step2(data, conn, sockindex);
     if(result || (nonblocking &&
                   (ssl_connect_2 == connssl->connecting_state ||
                    ssl_connect_2_reading == connssl->connecting_state ||
@@ -4044,7 +4095,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
   } /* repeat step2 until all transactions are done. */
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    result = ossl_connect_step3(conn, sockindex);
+    result = ossl_connect_step3(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -4064,19 +4115,21 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
-                                              int sockindex,
-                                              bool *done)
+static CURLcode ossl_connect_nonblocking(struct Curl_easy *data,
+                                         struct connectdata *conn,
+                                         int sockindex,
+                                         bool *done)
 {
-  return ossl_connect_common(conn, sockindex, TRUE, done);
+  return ossl_connect_common(data, conn, sockindex, TRUE, done);
 }
 
-static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect(struct Curl_easy *data, struct connectdata *conn,
+                             int sockindex)
 {
   CURLcode result;
   bool done = FALSE;
 
-  result = ossl_connect_common(conn, sockindex, FALSE, &done);
+  result = ossl_connect_common(data, conn, sockindex, FALSE, &done);
   if(result)
     return result;
 
@@ -4085,8 +4138,8 @@ static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static bool Curl_ossl_data_pending(const struct connectdata *conn,
-                                   int connindex)
+static bool ossl_data_pending(const struct connectdata *conn,
+                              int connindex)
 {
   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
   if(connssl->backend->handle && SSL_pending(connssl->backend->handle))
@@ -4101,9 +4154,9 @@ static bool Curl_ossl_data_pending(const struct connectdata *conn,
   return FALSE;
 }
 
-static size_t Curl_ossl_version(char *buffer, size_t size);
+static size_t ossl_version(char *buffer, size_t size);
 
-static ssize_t ossl_send(struct connectdata *conn,
+static ssize_t ossl_send(struct Curl_easy *data,
                          int sockindex,
                          const void *mem,
                          size_t len,
@@ -4116,6 +4169,7 @@ static ssize_t ossl_send(struct connectdata *conn,
   unsigned long sslerror;
   int memlen;
   int rc;
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
 
@@ -4147,7 +4201,7 @@ static ssize_t ossl_send(struct connectdata *conn,
           strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer));
           error_buffer[sizeof(error_buffer) - 1] = '\0';
         }
-        failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+        failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
               error_buffer, sockerr);
         *curlcode = CURLE_SEND_ERROR;
         return -1;
@@ -4164,18 +4218,17 @@ static ssize_t ossl_send(struct connectdata *conn,
 #endif
         ) {
         char ver[120];
-        Curl_ossl_version(ver, 120);
-        failf(conn->data, "Error: %s does not support double SSL tunneling.",
-              ver);
+        ossl_version(ver, 120);
+        failf(data, "Error: %s does not support double SSL tunneling.", ver);
       }
       else
-        failf(conn->data, "SSL_write() error: %s",
+        failf(data, "SSL_write() error: %s",
               ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
       *curlcode = CURLE_SEND_ERROR;
       return -1;
     }
     /* a true error */
-    failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+    failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
           SSL_ERROR_to_str(err), SOCKERRNO);
     *curlcode = CURLE_SEND_ERROR;
     return -1;
@@ -4184,7 +4237,7 @@ static ssize_t ossl_send(struct connectdata *conn,
   return (ssize_t)rc; /* number of bytes */
 }
 
-static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
+static ssize_t ossl_recv(struct Curl_easy *data,   /* transfer */
                          int num,                  /* socketindex */
                          char *buf,                /* store read data here */
                          size_t buffersize,        /* max amount to read */
@@ -4194,6 +4247,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
   unsigned long sslerror;
   ssize_t nread;
   int buffsize;
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
   struct ssl_backend_data *backend = connssl->backend;
 
@@ -4237,7 +4291,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
           strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer));
           error_buffer[sizeof(error_buffer) - 1] = '\0';
         }
-        failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d",
+        failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
               error_buffer, sockerr);
         *curlcode = CURLE_RECV_ERROR;
         return -1;
@@ -4259,7 +4313,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
           msnprintf(error_buffer, sizeof(error_buffer),
                     "Connection closed abruptly");
         }
-        failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d"
+        failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d"
               " (Fatal because this is a curl debug build)",
               error_buffer, sockerr);
         *curlcode = CURLE_RECV_ERROR;
@@ -4271,7 +4325,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
   return nread;
 }
 
-static size_t Curl_ossl_version(char *buffer, size_t size)
+static size_t ossl_version(char *buffer, size_t size)
 {
 #ifdef LIBRESSL_VERSION_NUMBER
 #if LIBRESSL_VERSION_NUMBER < 0x2070100fL
@@ -4342,12 +4396,12 @@ static size_t Curl_ossl_version(char *buffer, size_t size)
 }
 
 /* can be called with data == NULL */
-static CURLcode Curl_ossl_random(struct Curl_easy *data,
-                                 unsigned char *entropy, size_t length)
+static CURLcode ossl_random(struct Curl_easy *data,
+                            unsigned char *entropy, size_t length)
 {
   int rc;
   if(data) {
-    if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */
+    if(ossl_seed(data)) /* Initiate the seed if not already done */
       return CURLE_FAILED_INIT; /* couldn't seed for some reason */
   }
   else {
@@ -4359,35 +4413,20 @@ static CURLcode Curl_ossl_random(struct Curl_easy *data,
   return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
 }
 
-static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */
-                                 size_t tmplen,
-                                 unsigned char *md5sum /* output */,
-                                 size_t unused)
-{
-  EVP_MD_CTX *mdctx;
-  unsigned int len = 0;
-  (void) unused;
-
-  mdctx = EVP_MD_CTX_create();
-  EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
-  EVP_DigestUpdate(mdctx, tmp, tmplen);
-  EVP_DigestFinal_ex(mdctx, md5sum, &len);
-  EVP_MD_CTX_destroy(mdctx);
-  return CURLE_OK;
-}
-
 #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-static CURLcode Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
-                                size_t tmplen,
-                                unsigned char *sha256sum /* output */,
-                                size_t unused)
+static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
+                               size_t tmplen,
+                               unsigned char *sha256sum /* output */,
+                               size_t unused)
 {
   EVP_MD_CTX *mdctx;
   unsigned int len = 0;
   (void) unused;
 
   mdctx = EVP_MD_CTX_create();
-  EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL);
+  if(!mdctx)
+    return CURLE_OUT_OF_MEMORY;
+  EVP_DigestInit(mdctx, EVP_sha256());
   EVP_DigestUpdate(mdctx, tmp, tmplen);
   EVP_DigestFinal_ex(mdctx, sha256sum, &len);
   EVP_MD_CTX_destroy(mdctx);
@@ -4395,7 +4434,7 @@ static CURLcode Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
 }
 #endif
 
-static bool Curl_ossl_cert_status_request(void)
+static bool ossl_cert_status_request(void)
 {
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
     !defined(OPENSSL_NO_OCSP)
@@ -4405,8 +4444,8 @@ static bool Curl_ossl_cert_status_request(void)
 #endif
 }
 
-static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl,
-                                     CURLINFO info)
+static void *ossl_get_internals(struct ssl_connect_data *connssl,
+                                CURLINFO info)
 {
   /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
   struct ssl_backend_data *backend = connssl->backend;
@@ -4428,29 +4467,28 @@ const struct Curl_ssl Curl_ssl_openssl = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_ossl_init,                /* init */
-  Curl_ossl_cleanup,             /* cleanup */
-  Curl_ossl_version,             /* version */
-  Curl_ossl_check_cxn,           /* check_cxn */
-  Curl_ossl_shutdown,            /* shutdown */
-  Curl_ossl_data_pending,        /* data_pending */
-  Curl_ossl_random,              /* random */
-  Curl_ossl_cert_status_request, /* cert_status_request */
-  Curl_ossl_connect,             /* connect */
-  Curl_ossl_connect_nonblocking, /* connect_nonblocking */
-  Curl_ossl_get_internals,       /* get_internals */
-  Curl_ossl_close,               /* close_one */
-  Curl_ossl_close_all,           /* close_all */
-  Curl_ossl_session_free,        /* session_free */
-  Curl_ossl_set_engine,          /* set_engine */
-  Curl_ossl_set_engine_default,  /* set_engine_default */
-  Curl_ossl_engines_list,        /* engines_list */
-  Curl_none_false_start,         /* false_start */
-  Curl_ossl_md5sum,              /* md5sum */
+  ossl_init,                /* init */
+  ossl_cleanup,             /* cleanup */
+  ossl_version,             /* version */
+  ossl_check_cxn,           /* check_cxn */
+  ossl_shutdown,            /* shutdown */
+  ossl_data_pending,        /* data_pending */
+  ossl_random,              /* random */
+  ossl_cert_status_request, /* cert_status_request */
+  ossl_connect,             /* connect */
+  ossl_connect_nonblocking, /* connect_nonblocking */
+  ossl_get_internals,       /* get_internals */
+  ossl_close,               /* close_one */
+  ossl_close_all,           /* close_all */
+  ossl_session_free,        /* session_free */
+  ossl_set_engine,          /* set_engine */
+  ossl_set_engine_default,  /* set_engine_default */
+  ossl_engines_list,        /* engines_list */
+  Curl_none_false_start,    /* false_start */
 #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-  Curl_ossl_sha256sum            /* sha256sum */
+  ossl_sha256sum            /* sha256sum */
 #else
-  NULL                           /* sha256sum */
+  NULL                      /* sha256sum */
 #endif
 };
 
index 114dc4b..2f6e1b2 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 1c1432d..0668f98 100644 (file)
@@ -5,13 +5,13 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
  * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
 static Curl_recv schannel_recv;
 static Curl_send schannel_send;
 
-static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
+                                    struct connectdata *conn, int sockindex,
                                     const char *pinnedpubkey);
 
 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
@@ -162,9 +163,9 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
 }
 
 static CURLcode
-set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
+set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct Curl_easy *data,
+                        struct connectdata *conn)
 {
-  struct Curl_easy *data = conn->data;
   long ssl_version = SSL_CONN_CONFIG(version);
   long ssl_version_max = SSL_CONN_CONFIG(version_max);
   long i = ssl_version;
@@ -346,6 +347,8 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
 }
 
 #ifdef HAS_CLIENT_CERT_PATH
+
+/* Function allocates memory for store_path only if CURLE_OK is returned */
 static CURLcode
 get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
                   TCHAR **thumbprint)
@@ -388,25 +391,25 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
   if(sep == NULL)
     return CURLE_SSL_CERTPROBLEM;
 
+  *thumbprint = sep + 1;
+  if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
+    return CURLE_SSL_CERTPROBLEM;
+
   *sep = TEXT('\0');
   *store_path = _tcsdup(store_path_start);
   *sep = TEXT('\\');
   if(*store_path == NULL)
     return CURLE_OUT_OF_MEMORY;
 
-  *thumbprint = sep + 1;
-  if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
-    return CURLE_SSL_CERTPROBLEM;
-
   return CURLE_OK;
 }
 #endif
 
 static CURLcode
-schannel_connect_step1(struct connectdata *conn, int sockindex)
+schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
+                       int sockindex)
 {
   ssize_t written = -1;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   SecBuffer outbuf;
   SecBufferDesc outbuf_desc;
@@ -418,7 +421,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
   SCHANNEL_CRED schannel_cred;
   PCCERT_CONTEXT client_certs[1] = { NULL };
   SECURITY_STATUS sspi_status = SEC_E_OK;
-  struct curl_schannel_cred *old_cred = NULL;
+  struct Curl_schannel_cred *old_cred = NULL;
   struct in_addr addr;
 #ifdef ENABLE_IPV6
   struct in6_addr addr6;
@@ -491,8 +494,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 
   /* check for an existing re-usable credential handle */
   if(SSL_SET_OPTION(primary.sessionid)) {
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn,
+                              (void **)&old_cred, NULL, sockindex)) {
       BACKEND->cred = old_cred;
       DEBUGF(infof(data, "schannel: re-using existing credential handle\n"));
 
@@ -502,7 +506,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
                    "schannel: incremented credential handle refcount = %d\n",
                    BACKEND->cred->refcount));
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   if(!BACKEND->cred) {
@@ -561,7 +565,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
     case CURL_SSLVERSION_TLSv1_2:
     case CURL_SSLVERSION_TLSv1_3:
     {
-      result = set_ssl_version_min_max(&schannel_cred, conn);
+      result = set_ssl_version_min_max(&schannel_cred, data, conn);
       if(result != CURLE_OK)
         return result;
       break;
@@ -588,7 +592,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 
 #ifdef HAS_CLIENT_CERT_PATH
     /* client certificate */
-    if(data->set.ssl.cert || data->set.ssl.cert_blob) {
+    if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
       DWORD cert_store_name = 0;
       TCHAR *cert_store_path = NULL;
       TCHAR *cert_thumbprint_str = NULL;
@@ -598,27 +602,28 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
       FILE *fInCert = NULL;
       void *certdata = NULL;
       size_t certsize = 0;
-      bool blob = data->set.ssl.cert_blob != NULL;
+      bool blob = data->set.ssl.primary.cert_blob != NULL;
       TCHAR *cert_path = NULL;
       if(blob) {
-        certdata = data->set.ssl.cert_blob->data;
-        certsize = data->set.ssl.cert_blob->len;
+        certdata = data->set.ssl.primary.cert_blob->data;
+        certsize = data->set.ssl.primary.cert_blob->len;
       }
       else {
-        cert_path = curlx_convert_UTF8_to_tchar(data->set.ssl.cert);
+        cert_path = curlx_convert_UTF8_to_tchar(
+          data->set.ssl.primary.clientcert);
         if(!cert_path)
           return CURLE_OUT_OF_MEMORY;
 
         result = get_cert_location(cert_path, &cert_store_name,
           &cert_store_path, &cert_thumbprint_str);
 
-        if(result && (data->set.ssl.cert[0]!='\0'))
-          fInCert = fopen(data->set.ssl.cert, "rb");
+        if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
+          fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
 
         if(result && !fInCert) {
           failf(data, "schannel: Failed to get certificate location"
                 " or file for %s",
-                data->set.ssl.cert);
+                data->set.ssl.primary.clientcert);
           curlx_unicodefree(cert_path);
           return result;
         }
@@ -628,7 +633,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
           (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
         failf(data, "schannel: certificate format compatibility error "
                 " for %s",
-                blob ? "(memory blob)" : data->set.ssl.cert);
+                blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
         curlx_unicodefree(cert_path);
         return CURLE_SSL_CERTPROBLEM;
       }
@@ -643,7 +648,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
         size_t pwd_len = 0;
         int str_w_len = 0;
         const char *cert_showfilename_error = blob ?
-          "(memory blob)" : data->set.ssl.cert;
+          "(memory blob)" : data->set.ssl.primary.clientcert;
         curlx_unicodefree(cert_path);
         if(fInCert) {
           long cert_tell = 0;
@@ -664,7 +669,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
           fclose(fInCert);
           if(!continue_reading) {
             failf(data, "schannel: Failed to read cert file %s",
-                data->set.ssl.cert);
+                data->set.ssl.primary.clientcert);
             free(certdata);
             return CURLE_SSL_CERTPROBLEM;
           }
@@ -771,15 +776,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
       CertCloseStore(cert_store, 0);
     }
 #else
-    if(data->set.ssl.cert) {
+    if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
       failf(data, "schannel: client cert support not built in");
       return CURLE_NOT_BUILT_IN;
     }
 #endif
 
     /* allocate memory for the re-usable credential handle */
-    BACKEND->cred = (struct curl_schannel_cred *)
-      calloc(1, sizeof(struct curl_schannel_cred));
+    BACKEND->cred = (struct Curl_schannel_cred *)
+      calloc(1, sizeof(struct Curl_schannel_cred));
     if(!BACKEND->cred) {
       failf(data, "schannel: unable to allocate memory");
 
@@ -893,8 +898,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
     ISC_REQ_STREAM;
 
   /* allocate memory for the security context handle */
-  BACKEND->ctxt = (struct curl_schannel_ctxt *)
-    calloc(1, sizeof(struct curl_schannel_ctxt));
+  BACKEND->ctxt = (struct Curl_schannel_ctxt *)
+    calloc(1, sizeof(struct Curl_schannel_ctxt));
   if(!BACKEND->ctxt) {
     failf(data, "schannel: unable to allocate memory");
     return CURLE_OUT_OF_MEMORY;
@@ -953,7 +958,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
                "sending %lu bytes...\n", outbuf.cbBuffer));
 
   /* send initial handshake data which is now stored in output buffer */
-  result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
+  result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
                             outbuf.cbBuffer, &written);
   s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
   if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
@@ -977,11 +982,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 }
 
 static CURLcode
-schannel_connect_step2(struct connectdata *conn, int sockindex)
+schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
+                       int sockindex)
 {
   int i;
   ssize_t nread = -1, written = -1;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   unsigned char *reallocated_buffer;
   SecBuffer outbuf[3];
@@ -1150,7 +1155,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
                        "sending %lu bytes...\n", outbuf[i].cbBuffer));
 
           /* send handshake token to server */
-          result = Curl_write_plain(conn, conn->sock[sockindex],
+          result = Curl_write_plain(data, conn->sock[sockindex],
                                     outbuf[i].pvBuffer, outbuf[i].cbBuffer,
                                     &written);
           if((result != CURLE_OK) ||
@@ -1178,6 +1183,10 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
         failf(data, "schannel: SNI or certificate check failed: %s",
               Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
         return CURLE_PEER_FAILED_VERIFICATION;
+      case SEC_E_UNTRUSTED_ROOT:
+        failf(data, "schannel: %s",
+              Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+        return CURLE_PEER_FAILED_VERIFICATION;
         /*
           case SEC_E_INVALID_HANDLE:
           case SEC_E_INVALID_TOKEN:
@@ -1245,7 +1254,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
     data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
     data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
   if(pubkey_ptr) {
-    result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
+    result = pkp_pin_peer_pubkey(data, conn, sockindex, pubkey_ptr);
     if(result) {
       failf(data, "SSL: public key does not match pinned public key!");
       return result;
@@ -1254,7 +1263,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
 
 #ifdef HAS_MANUAL_VERIFY_API
   if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
-    return Curl_verify_certificate(conn, sockindex);
+    return Curl_verify_certificate(data, conn, sockindex);
   }
 #endif
 
@@ -1298,7 +1307,7 @@ cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
 
 struct Adder_args
 {
-  struct connectdata *conn;
+  struct Curl_easy *data;
   CURLcode result;
   int idx;
   int certs_count;
@@ -1313,17 +1322,18 @@ add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
     const char *beg = (const char *) ccert_context->pbCertEncoded;
     const char *end = beg + ccert_context->cbCertEncoded;
     int insert_index = (args->certs_count - 1) - args->idx;
-    args->result = Curl_extract_certinfo(args->conn, insert_index, beg, end);
+    args->result = Curl_extract_certinfo(args->data, insert_index,
+                                         beg, end);
     args->idx++;
   }
   return args->result == CURLE_OK;
 }
 
 static CURLcode
-schannel_connect_step3(struct connectdata *conn, int sockindex)
+schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
+                       int sockindex)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   SECURITY_STATUS sspi_status = SEC_E_OK;
   CERT_CONTEXT *ccert_context = NULL;
@@ -1393,7 +1403,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
     }
     else
       infof(data, "ALPN, server did not agree to a protocol\n");
-    Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+    Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
   }
 #endif
@@ -1401,26 +1411,26 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
   /* save the current session data for possible re-use */
   if(SSL_SET_OPTION(primary.sessionid)) {
     bool incache;
-    struct curl_schannel_cred *old_cred = NULL;
+    struct Curl_schannel_cred *old_cred = NULL;
 
-    Curl_ssl_sessionid_lock(conn);
-    incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
+    Curl_ssl_sessionid_lock(data);
+    incache = !(Curl_ssl_getsessionid(data, conn, (void **)&old_cred, NULL,
                                       sockindex));
     if(incache) {
       if(old_cred != BACKEND->cred) {
         DEBUGF(infof(data,
                      "schannel: old credential handle is stale, removing\n"));
         /* we're not taking old_cred ownership here, no refcount++ is needed */
-        Curl_ssl_delsessionid(conn, (void *)old_cred);
+        Curl_ssl_delsessionid(data, (void *)old_cred);
         incache = FALSE;
       }
     }
     if(!incache) {
-      result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
-                                     sizeof(struct curl_schannel_cred),
+      result = Curl_ssl_addsessionid(data, conn, (void *)BACKEND->cred,
+                                     sizeof(struct Curl_schannel_cred),
                                      sockindex);
       if(result) {
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(data, "schannel: failed to store credential handle");
         return result;
       }
@@ -1431,7 +1441,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
                      "schannel: stored credential handle in session cache\n"));
       }
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   if(data->set.ssl.certinfo) {
@@ -1451,7 +1461,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
     result = Curl_ssl_init_certinfo(data, certs_count);
     if(!result) {
       struct Adder_args args;
-      args.conn = conn;
+      args.data = data;
       args.idx = 0;
       args.certs_count = certs_count;
       traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
@@ -1468,11 +1478,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
 }
 
 static CURLcode
-schannel_connect_common(struct connectdata *conn, int sockindex,
-                        bool nonblocking, bool *done)
+schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
+                        int sockindex, bool nonblocking, bool *done)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   timediff_t timeout_ms;
@@ -1494,7 +1503,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
       return CURLE_OPERATION_TIMEDOUT;
     }
 
-    result = schannel_connect_step1(conn, sockindex);
+    result = schannel_connect_step1(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -1549,7 +1558,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
      * ensuring that a client using select() or epoll() will always
      * have a valid fdset to wait on.
      */
-    result = schannel_connect_step2(conn, sockindex);
+    result = schannel_connect_step2(data, conn, sockindex);
     if(result || (nonblocking &&
                   (ssl_connect_2 == connssl->connecting_state ||
                    ssl_connect_2_reading == connssl->connecting_state ||
@@ -1559,7 +1568,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
   } /* repeat step2 until all transactions are done. */
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    result = schannel_connect_step3(conn, sockindex);
+    result = schannel_connect_step3(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -1590,12 +1599,13 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
 }
 
 static ssize_t
-schannel_send(struct connectdata *conn, int sockindex,
+schannel_send(struct Curl_easy *data, int sockindex,
               const void *buf, size_t len, CURLcode *err)
 {
   ssize_t written = -1;
   size_t data_len = 0;
-  unsigned char *data = NULL;
+  unsigned char *ptr = NULL;
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   SecBuffer outbuf[4];
   SecBufferDesc outbuf_desc;
@@ -1622,19 +1632,19 @@ schannel_send(struct connectdata *conn, int sockindex,
   /* calculate the complete message length and allocate a buffer for it */
   data_len = BACKEND->stream_sizes.cbHeader + len +
     BACKEND->stream_sizes.cbTrailer;
-  data = (unsigned char *) malloc(data_len);
-  if(data == NULL) {
+  ptr = (unsigned char *) malloc(data_len);
+  if(!ptr) {
     *err = CURLE_OUT_OF_MEMORY;
     return -1;
   }
 
   /* setup output buffers (header, data, trailer, empty) */
   InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
-                data, BACKEND->stream_sizes.cbHeader);
+                ptr, BACKEND->stream_sizes.cbHeader);
   InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
-                data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
+                ptr + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
   InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
-                data + BACKEND->stream_sizes.cbHeader + len,
+                ptr + BACKEND->stream_sizes.cbHeader + len,
                 BACKEND->stream_sizes.cbTrailer);
   InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
   InitSecBufferDesc(&outbuf_desc, outbuf, 4);
@@ -1673,10 +1683,10 @@ schannel_send(struct connectdata *conn, int sockindex,
     while(len > (size_t)written) {
       ssize_t this_write = 0;
       int what;
-      timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
+      timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
       if(timeout_ms < 0) {
         /* we already got the timeout */
-        failf(conn->data, "schannel: timed out sending data "
+        failf(data, "schannel: timed out sending data "
               "(bytes sent: %zd)", written);
         *err = CURLE_OPERATION_TIMEDOUT;
         written = -1;
@@ -1687,13 +1697,13 @@ schannel_send(struct connectdata *conn, int sockindex,
       what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
       if(what < 0) {
         /* fatal error */
-        failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
         *err = CURLE_SEND_ERROR;
         written = -1;
         break;
       }
       else if(0 == what) {
-        failf(conn->data, "schannel: timed out sending data "
+        failf(data, "schannel: timed out sending data "
               "(bytes sent: %zd)", written);
         *err = CURLE_OPERATION_TIMEDOUT;
         written = -1;
@@ -1701,7 +1711,7 @@ schannel_send(struct connectdata *conn, int sockindex,
       }
       /* socket is writable */
 
-      result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
+      result = Curl_write_plain(data, conn->sock[sockindex], ptr + written,
                                 len - written, &this_write);
       if(result == CURLE_AGAIN)
         continue;
@@ -1721,7 +1731,7 @@ schannel_send(struct connectdata *conn, int sockindex,
     *err = CURLE_SEND_ERROR;
   }
 
-  Curl_safefree(data);
+  Curl_safefree(ptr);
 
   if(len == (size_t)written)
     /* Encrypted message including header, data and trailer entirely sent.
@@ -1732,12 +1742,12 @@ schannel_send(struct connectdata *conn, int sockindex,
 }
 
 static ssize_t
-schannel_recv(struct connectdata *conn, int sockindex,
+schannel_recv(struct Curl_easy *data, int sockindex,
               char *buf, size_t len, CURLcode *err)
 {
   size_t size = 0;
   ssize_t nread = -1;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   unsigned char *reallocated_buffer;
   size_t reallocated_length;
@@ -1776,14 +1786,12 @@ schannel_recv(struct connectdata *conn, int sockindex,
     infof(data, "schannel: server indicated shutdown in a prior call\n");
     goto cleanup;
   }
-  else if(!len) {
-    /* It's debatable what to return when !len. Regardless we can't return
-       immediately because there may be data to decrypt (in the case we want to
-       decrypt all encrypted cached data) so handle !len later in cleanup.
-    */
-    ; /* do nothing */
-  }
-  else if(!BACKEND->recv_connection_closed) {
+
+  /* It's debatable what to return when !len. Regardless we can't return
+     immediately because there may be data to decrypt (in the case we want to
+     decrypt all encrypted cached data) so handle !len later in cleanup.
+  */
+  else if(len && !BACKEND->recv_connection_closed) {
     /* increase enc buffer in order to fit the requested amount of data */
     size = BACKEND->encdata_length - BACKEND->encdata_offset;
     if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
@@ -1950,7 +1958,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
         infof(data, "schannel: renegotiating SSL/TLS connection\n");
         connssl->state = ssl_connection_negotiating;
         connssl->connecting_state = ssl_connect_2_writing;
-        *err = schannel_connect_common(conn, sockindex, FALSE, &done);
+        *err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
         if(*err) {
           infof(data, "schannel: renegotiation failed\n");
           goto cleanup;
@@ -2057,18 +2065,20 @@ schannel_recv(struct connectdata *conn, int sockindex,
   return *err ? -1 : 0;
 }
 
-static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
-                                                  int sockindex, bool *done)
+static CURLcode schannel_connect_nonblocking(struct Curl_easy *data,
+                                             struct connectdata *conn,
+                                             int sockindex, bool *done)
 {
-  return schannel_connect_common(conn, sockindex, TRUE, done);
+  return schannel_connect_common(data, conn, sockindex, TRUE, done);
 }
 
-static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
+static CURLcode schannel_connect(struct Curl_easy *data,
+                                 struct connectdata *conn, int sockindex)
 {
   CURLcode result;
   bool done = FALSE;
 
-  result = schannel_connect_common(conn, sockindex, FALSE, &done);
+  result = schannel_connect_common(data, conn, sockindex, FALSE, &done);
   if(result)
     return result;
 
@@ -2077,8 +2087,8 @@ static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static bool Curl_schannel_data_pending(const struct connectdata *conn,
-                                       int sockindex)
+static bool schannel_data_pending(const struct connectdata *conn,
+                                  int sockindex)
 {
   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
@@ -2089,17 +2099,18 @@ static bool Curl_schannel_data_pending(const struct connectdata *conn,
     return FALSE;
 }
 
-static void Curl_schannel_close(struct connectdata *conn, int sockindex)
+static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
+                           int sockindex)
 {
   if(conn->ssl[sockindex].use)
     /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
-    Curl_ssl_shutdown(conn, sockindex);
+    Curl_ssl_shutdown(data, conn, sockindex);
 }
 
-static void Curl_schannel_session_free(void *ptr)
+static void schannel_session_free(void *ptr)
 {
   /* this is expected to be called under sessionid lock */
-  struct curl_schannel_cred *cred = ptr;
+  struct Curl_schannel_cred *cred = ptr;
 
   cred->refcount--;
   if(cred->refcount == 0) {
@@ -2108,12 +2119,12 @@ static void Curl_schannel_session_free(void *ptr)
   }
 }
 
-static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
+static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
+                             int sockindex)
 {
   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
    * Shutting Down an Schannel Connection
    */
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 #ifndef CURL_DISABLE_PROXY
   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
@@ -2176,7 +2187,7 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
       /* send close message which is in output buffer */
       ssize_t written;
-      result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
+      result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
                                 outbuf.cbBuffer, &written);
 
       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
@@ -2196,14 +2207,9 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
 
   /* free SSPI Schannel API credential handle */
   if(BACKEND->cred) {
-    /*
-     * When this function is called from Curl_schannel_close() the connection
-     * might not have an associated transfer so the check for conn->data is
-     * necessary.
-     */
-    Curl_ssl_sessionid_lock(conn);
-    Curl_schannel_session_free(BACKEND->cred);
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_lock(data);
+    schannel_session_free(BACKEND->cred);
+    Curl_ssl_sessionid_unlock(data);
     BACKEND->cred = NULL;
   }
 
@@ -2225,25 +2231,25 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static int Curl_schannel_init(void)
+static int schannel_init(void)
 {
   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
 }
 
-static void Curl_schannel_cleanup(void)
+static void schannel_cleanup(void)
 {
   Curl_sspi_global_cleanup();
 }
 
-static size_t Curl_schannel_version(char *buffer, size_t size)
+static size_t schannel_version(char *buffer, size_t size)
 {
   size = msnprintf(buffer, size, "Schannel");
 
   return size;
 }
 
-static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
-                                     unsigned char *entropy, size_t length)
+static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
+                                unsigned char *entropy, size_t length)
 {
   HCRYPTPROV hCryptProv = 0;
 
@@ -2262,10 +2268,10 @@ static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
   return CURLE_OK;
 }
 
-static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
+                                    struct connectdata *conn, int sockindex,
                                     const char *pinnedpubkey)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   CERT_CONTEXT *pCertContextServer = NULL;
 
@@ -2327,12 +2333,12 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
   return result;
 }
 
-static void Curl_schannel_checksum(const unsigned char *input,
-                                   size_t inputlen,
-                                   unsigned char *checksum,
-                                   size_t checksumlen,
-                                   DWORD provType,
-                                   const unsigned int algId)
+static void schannel_checksum(const unsigned char *input,
+                              size_t inputlen,
+                              unsigned char *checksum,
+                              size_t checksumlen,
+                              DWORD provType,
+                              const unsigned int algId)
 {
   HCRYPTPROV hProv = 0;
   HCRYPTHASH hHash = 0;
@@ -2377,28 +2383,18 @@ static void Curl_schannel_checksum(const unsigned char *input,
     CryptReleaseContext(hProv, 0);
 }
 
-static CURLcode Curl_schannel_md5sum(unsigned char *input,
-                                     size_t inputlen,
-                                     unsigned char *md5sum,
-                                     size_t md5len)
-{
-  Curl_schannel_checksum(input, inputlen, md5sum, md5len,
-                         PROV_RSA_FULL, CALG_MD5);
-  return CURLE_OK;
-}
-
-static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
-                                        size_t inputlen,
-                                        unsigned char *sha256sum,
-                                        size_t sha256len)
+static CURLcode schannel_sha256sum(const unsigned char *input,
+                                   size_t inputlen,
+                                   unsigned char *sha256sum,
+                                   size_t sha256len)
 {
-  Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
-                         PROV_RSA_AES, CALG_SHA_256);
+  schannel_checksum(input, inputlen, sha256sum, sha256len,
+                    PROV_RSA_AES, CALG_SHA_256);
   return CURLE_OK;
 }
 
-static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
-                                         CURLINFO info UNUSED_PARAM)
+static void *schannel_get_internals(struct ssl_connect_data *connssl,
+                                    CURLINFO info UNUSED_PARAM)
 {
   (void)info;
   return &BACKEND->ctxt->ctxt_handle;
@@ -2412,26 +2408,25 @@ const struct Curl_ssl Curl_ssl_schannel = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_schannel_init,                /* init */
-  Curl_schannel_cleanup,             /* cleanup */
-  Curl_schannel_version,             /* version */
+  schannel_init,                     /* init */
+  schannel_cleanup,                  /* cleanup */
+  schannel_version,                  /* version */
   Curl_none_check_cxn,               /* check_cxn */
-  Curl_schannel_shutdown,            /* shutdown */
-  Curl_schannel_data_pending,        /* data_pending */
-  Curl_schannel_random,              /* random */
+  schannel_shutdown,                 /* shutdown */
+  schannel_data_pending,             /* data_pending */
+  schannel_random,                   /* random */
   Curl_none_cert_status_request,     /* cert_status_request */
-  Curl_schannel_connect,             /* connect */
-  Curl_schannel_connect_nonblocking, /* connect_nonblocking */
-  Curl_schannel_get_internals,       /* get_internals */
-  Curl_schannel_close,               /* close_one */
+  schannel_connect,                  /* connect */
+  schannel_connect_nonblocking,      /* connect_nonblocking */
+  schannel_get_internals,            /* get_internals */
+  schannel_close,                    /* close_one */
   Curl_none_close_all,               /* close_all */
-  Curl_schannel_session_free,        /* session_free */
+  schannel_session_free,             /* session_free */
   Curl_none_set_engine,              /* set_engine */
   Curl_none_set_engine_default,      /* set_engine_default */
   Curl_none_engines_list,            /* engines_list */
   Curl_none_false_start,             /* false_start */
-  Curl_schannel_md5sum,              /* md5sum */
-  Curl_schannel_sha256sum            /* sha256sum */
+  schannel_sha256sum                 /* sha256sum */
 };
 
 #endif /* USE_SCHANNEL */
index ee8d7d4..2952caa 100644 (file)
@@ -8,11 +8,11 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -53,7 +53,8 @@
 
 extern const struct Curl_ssl Curl_ssl_schannel;
 
-CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex);
+CURLcode Curl_verify_certificate(struct Curl_easy *data,
+                                 struct connectdata *conn, int sockindex);
 
 /* structs to expose only in schannel.c and schannel_verify.c */
 #ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS
@@ -70,20 +71,20 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex);
 #endif
 #endif
 
-struct curl_schannel_cred {
+struct Curl_schannel_cred {
   CredHandle cred_handle;
   TimeStamp time_stamp;
   int refcount;
 };
 
-struct curl_schannel_ctxt {
+struct Curl_schannel_ctxt {
   CtxtHandle ctxt_handle;
   TimeStamp time_stamp;
 };
 
 struct ssl_backend_data {
-  struct curl_schannel_cred *cred;
-  struct curl_schannel_ctxt *ctxt;
+  struct Curl_schannel_cred *cred;
+  struct Curl_schannel_ctxt *ctxt;
   SecPkgContext_StreamSizes stream_sizes;
   size_t encdata_length, decdata_length;
   size_t encdata_offset, decdata_offset;
index ab7be39..2ef39cc 100644 (file)
@@ -7,11 +7,11 @@
  *
  * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
  * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -79,10 +79,9 @@ static int is_cr_or_lf(char c)
 
 static CURLcode add_certs_to_store(HCERTSTORE trust_store,
                                    const char *ca_file,
-                                   struct connectdata *conn)
+                                   struct Curl_easy *data)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
   LARGE_INTEGER file_size;
   char *ca_file_buffer = NULL;
@@ -477,7 +476,7 @@ static CURLcode verify_host(struct Curl_easy *data,
      * (or some equivalent) encoding
      */
     cert_hostname = curlx_convert_tchar_to_UTF8(
-        &cert_hostname_buff[cert_hostname_buff_index]);
+      &cert_hostname_buff[cert_hostname_buff_index]);
     if(!cert_hostname) {
       result = CURLE_OUT_OF_MEMORY;
     }
@@ -500,8 +499,8 @@ static CURLcode verify_host(struct Curl_easy *data,
               "against certificate name (%s)\n",
               conn_hostname, cert_hostname);
 
-        cert_hostname_len = _tcslen(
-            &cert_hostname_buff[cert_hostname_buff_index]);
+        cert_hostname_len =
+          _tcslen(&cert_hostname_buff[cert_hostname_buff_index]);
 
         /* Move on to next cert name */
         cert_hostname_buff_index += cert_hostname_len + 1;
@@ -522,15 +521,15 @@ static CURLcode verify_host(struct Curl_easy *data,
     failf(data, "schannel: server certificate name verification failed");
 
 cleanup:
-  curlx_unicodefree(cert_hostname_buff);
+  Curl_safefree(cert_hostname_buff);
 
   return result;
 }
 
-CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex)
+CURLcode Curl_verify_certificate(struct Curl_easy *data,
+                                 struct connectdata *conn, int sockindex)
 {
   SECURITY_STATUS sspi_status;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   CURLcode result = CURLE_OK;
   CERT_CONTEXT *pCertContextServer = NULL;
@@ -584,7 +583,7 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex)
       }
       else {
         result = add_certs_to_store(trust_store, SSL_CONN_CONFIG(CAfile),
-                                    conn);
+                                    data);
       }
     }
 
@@ -675,7 +674,7 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex)
 
   if(result == CURLE_OK) {
     if(SSL_CONN_CONFIG(verifyhost)) {
-      result = verify_host(conn->data, pCertContextServer, conn_hostname);
+      result = verify_host(data, pCertContextServer, conn_hostname);
     }
   }
 
index 2627aff..9a8f7de 100644 (file)
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2012 - 2017, Nick Zitzmann, <nickzman@gmail.com>.
- * Copyright (C) 2012 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -1291,9 +1291,9 @@ static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver,
 #endif
 
 static CURLcode
-set_ssl_version_min_max(struct connectdata *conn, int sockindex)
+set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
+                        int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   long ssl_version = SSL_CONN_CONFIG(version);
@@ -1387,21 +1387,26 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
 }
 
 
-static CURLcode sectransp_connect_step1(struct connectdata *conn,
+static CURLcode sectransp_connect_step1(struct Curl_easy *data,
+                                        struct connectdata *conn,
                                         int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd = conn->sock[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
   const struct curl_blob *ssl_cablob = NULL;
   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
-  char * const ssl_cert = SSL_SET_OPTION(cert);
-  const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob);
+  char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
+  const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
+#ifndef CURL_DISABLE_PROXY
   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
     conn->host.name;
   const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#else
+  const char * const hostname = conn->host.name;
+  const long int port = conn->remote_port;
+#endif
 #ifdef ENABLE_IPV6
   struct in6_addr addr;
 #else
@@ -1473,7 +1478,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
     case CURL_SSLVERSION_TLSv1_2:
     case CURL_SSLVERSION_TLSv1_3:
       {
-        CURLcode result = set_ssl_version_min_max(conn, sockindex);
+        CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
         if(result != CURLE_OK)
           return result;
         break;
@@ -1522,7 +1527,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
     case CURL_SSLVERSION_TLSv1_2:
     case CURL_SSLVERSION_TLSv1_3:
       {
-        CURLcode result = set_ssl_version_min_max(conn, sockindex);
+        CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
         if(result != CURLE_OK)
           return result;
         break;
@@ -1606,8 +1611,11 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
                                                        &kCFTypeArrayCallBacks);
 
 #ifdef USE_NGHTTP2
-      if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
-         (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
+      if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifndef CURL_DISABLE_PROXY
+         && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+#endif
+        ) {
         CFArrayAppendValue(alpnArr, CFSTR(NGHTTP2_PROTO_VERSION_ID));
         infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
       }
@@ -1944,12 +1952,12 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
     char *ssl_sessionid;
     size_t ssl_sessionid_len;
 
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn, (void **)&ssl_sessionid,
                               &ssl_sessionid_len, sockindex)) {
       /* we got a session id, use it! */
       err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
-      Curl_ssl_sessionid_unlock(conn);
+      Curl_ssl_sessionid_unlock(data);
       if(err != noErr) {
         failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
         return CURLE_SSL_CONNECT_ERROR;
@@ -1962,20 +1970,20 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
     else {
       CURLcode result;
       ssl_sessionid =
-        aprintf("%s:%d:%d:%s:%hu", ssl_cafile,
+        aprintf("%s:%d:%d:%s:%ld", ssl_cafile,
                 verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
       ssl_sessionid_len = strlen(ssl_sessionid);
 
       err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
       if(err != noErr) {
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
         return CURLE_SSL_CONNECT_ERROR;
       }
 
-      result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len,
-                                     sockindex);
-      Curl_ssl_sessionid_unlock(conn);
+      result = Curl_ssl_addsessionid(data, conn, ssl_sessionid,
+                                     ssl_sessionid_len, sockindex);
+      Curl_ssl_sessionid_unlock(data);
       if(result) {
         failf(data, "failed to store ssl session");
         return result;
@@ -2181,7 +2189,7 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
     if(res < 0) {
       free(certbuf);
       CFRelease(array);
-      failf(data, "SSL: invalid CA certificate #%d (offset %d) in bundle",
+      failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
             n, offset);
       return CURLE_SSL_CACERT_BADFILE;
     }
@@ -2371,16 +2379,20 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
 #endif /* SECTRANSP_PINNEDPUBKEY */
 
 static CURLcode
-sectransp_connect_step2(struct connectdata *conn, int sockindex)
+sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
+                        int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   OSStatus err;
   SSLCipherSuite cipher;
   SSLProtocol protocol = 0;
+#ifndef CURL_DISABLE_PROXY
   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
     conn->host.name;
+#else
+  const char * const hostname = conn->host.name;
+#endif
 
   DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
               || ssl_connect_2_reading == connssl->connecting_state
@@ -2406,7 +2418,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex)
             return result;
         }
         /* the documentation says we need to call SSLHandshake() again */
-        return sectransp_connect_step2(conn, sockindex);
+        return sectransp_connect_step2(data, conn, sockindex);
 
       /* Problem with encrypt / decrypt */
       case errSSLPeerDecodeError:
@@ -2681,7 +2693,7 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex)
         else
           infof(data, "ALPN, server did not agree to a protocol\n");
 
-        Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+        Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                             BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
 
         /* chosenProtocol is a reference to the string within alpnArr
@@ -2699,10 +2711,10 @@ sectransp_connect_step2(struct connectdata *conn, int sockindex)
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
 /* This should be called during step3 of the connection at the earliest */
 static void
-show_verbose_server_cert(struct connectdata *conn,
+show_verbose_server_cert(struct Curl_easy *data,
+                         struct connectdata *conn,
                          int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   CFArrayRef server_certs = NULL;
@@ -2805,10 +2817,9 @@ show_verbose_server_cert(struct connectdata *conn,
 #endif /* !CURL_DISABLE_VERBOSE_STRINGS */
 
 static CURLcode
-sectransp_connect_step3(struct connectdata *conn,
+sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn,
                         int sockindex)
 {
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   /* There is no step 3!
@@ -2816,7 +2827,7 @@ sectransp_connect_step3(struct connectdata *conn,
    * server certificates. */
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   if(data->set.verbose)
-    show_verbose_server_cert(conn, sockindex);
+    show_verbose_server_cert(data, conn, sockindex);
 #endif
 
   connssl->connecting_state = ssl_connect_done;
@@ -2827,13 +2838,13 @@ static Curl_recv sectransp_recv;
 static Curl_send sectransp_send;
 
 static CURLcode
-sectransp_connect_common(struct connectdata *conn,
+sectransp_connect_common(struct Curl_easy *data,
+                         struct connectdata *conn,
                          int sockindex,
                          bool nonblocking,
                          bool *done)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   int what;
@@ -2854,7 +2865,7 @@ sectransp_connect_common(struct connectdata *conn,
       return CURLE_OPERATION_TIMEDOUT;
     }
 
-    result = sectransp_connect_step1(conn, sockindex);
+    result = sectransp_connect_step1(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -2908,7 +2919,7 @@ sectransp_connect_common(struct connectdata *conn,
      * before step2 has completed while ensuring that a client using select()
      * or epoll() will always have a valid fdset to wait on.
      */
-    result = sectransp_connect_step2(conn, sockindex);
+    result = sectransp_connect_step2(data, conn, sockindex);
     if(result || (nonblocking &&
                   (ssl_connect_2 == connssl->connecting_state ||
                    ssl_connect_2_reading == connssl->connecting_state ||
@@ -2919,7 +2930,7 @@ sectransp_connect_common(struct connectdata *conn,
 
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    result = sectransp_connect_step3(conn, sockindex);
+    result = sectransp_connect_step3(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -2939,18 +2950,20 @@ sectransp_connect_common(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static CURLcode Curl_sectransp_connect_nonblocking(struct connectdata *conn,
-                                                   int sockindex, bool *done)
+static CURLcode sectransp_connect_nonblocking(struct Curl_easy *data,
+                                              struct connectdata *conn,
+                                              int sockindex, bool *done)
 {
-  return sectransp_connect_common(conn, sockindex, TRUE, done);
+  return sectransp_connect_common(data, conn, sockindex, TRUE, done);
 }
 
-static CURLcode Curl_sectransp_connect(struct connectdata *conn, int sockindex)
+static CURLcode sectransp_connect(struct Curl_easy *data,
+                                  struct connectdata *conn, int sockindex)
 {
   CURLcode result;
   bool done = FALSE;
 
-  result = sectransp_connect_common(conn, sockindex, FALSE, &done);
+  result = sectransp_connect_common(data, conn, sockindex, FALSE, &done);
 
   if(result)
     return result;
@@ -2960,11 +2973,14 @@ static CURLcode Curl_sectransp_connect(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static void Curl_sectransp_close(struct connectdata *conn, int sockindex)
+static void sectransp_close(struct Curl_easy *data, struct connectdata *conn,
+                            int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
 
+  (void) data;
+
   if(backend->ssl_ctx) {
     (void)SSLClose(backend->ssl_ctx);
 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
@@ -2982,11 +2998,11 @@ static void Curl_sectransp_close(struct connectdata *conn, int sockindex)
   backend->ssl_sockfd = 0;
 }
 
-static int Curl_sectransp_shutdown(struct connectdata *conn, int sockindex)
+static int sectransp_shutdown(struct Curl_easy *data,
+                              struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
-  struct Curl_easy *data = conn->data;
   ssize_t nread;
   int what;
   int rc;
@@ -3000,7 +3016,7 @@ static int Curl_sectransp_shutdown(struct connectdata *conn, int sockindex)
     return 0;
 #endif
 
-  Curl_sectransp_close(conn, sockindex);
+  sectransp_close(data, conn, sockindex);
 
   rc = 0;
 
@@ -3038,7 +3054,7 @@ static int Curl_sectransp_shutdown(struct connectdata *conn, int sockindex)
   return rc;
 }
 
-static void Curl_sectransp_session_free(void *ptr)
+static void sectransp_session_free(void *ptr)
 {
   /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
      cached session ID inside the Security framework. There is a private
@@ -3049,7 +3065,7 @@ static void Curl_sectransp_session_free(void *ptr)
   Curl_safefree(ptr);
 }
 
-static size_t Curl_sectransp_version(char *buffer, size_t size)
+static size_t sectransp_version(char *buffer, size_t size)
 {
   return msnprintf(buffer, size, "SecureTransport");
 }
@@ -3062,7 +3078,7 @@ static size_t Curl_sectransp_version(char *buffer, size_t size)
  *     0 means the connection has been closed
  *    -1 means the connection status is unknown
  */
-static int Curl_sectransp_check_cxn(struct connectdata *conn)
+static int sectransp_check_cxn(struct connectdata *conn)
 {
   struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
   struct ssl_backend_data *backend = connssl->backend;
@@ -3078,8 +3094,8 @@ static int Curl_sectransp_check_cxn(struct connectdata *conn)
   return 0;
 }
 
-static bool Curl_sectransp_data_pending(const struct connectdata *conn,
-                                        int connindex)
+static bool sectransp_data_pending(const struct connectdata *conn,
+                                   int connindex)
 {
   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
   struct ssl_backend_data *backend = connssl->backend;
@@ -3096,8 +3112,8 @@ static bool Curl_sectransp_data_pending(const struct connectdata *conn,
     return false;
 }
 
-static CURLcode Curl_sectransp_random(struct Curl_easy *data UNUSED_PARAM,
-                                      unsigned char *entropy, size_t length)
+static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
+                                 unsigned char *entropy, size_t length)
 {
   /* arc4random_buf() isn't available on cats older than Lion, so let's
      do this manually for the benefit of the older cats. */
@@ -3116,27 +3132,17 @@ static CURLcode Curl_sectransp_random(struct Curl_easy *data UNUSED_PARAM,
   return CURLE_OK;
 }
 
-static CURLcode Curl_sectransp_md5sum(unsigned char *tmp, /* input */
-                                      size_t tmplen,
-                                      unsigned char *md5sum, /* output */
-                                      size_t md5len)
-{
-  (void)md5len;
-  (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum);
-  return CURLE_OK;
-}
-
-static CURLcode Curl_sectransp_sha256sum(const unsigned char *tmp, /* input */
-                                     size_t tmplen,
-                                     unsigned char *sha256sum, /* output */
-                                     size_t sha256len)
+static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
+                                    size_t tmplen,
+                                    unsigned char *sha256sum, /* output */
+                                    size_t sha256len)
 {
   assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
   (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
   return CURLE_OK;
 }
 
-static bool Curl_sectransp_false_start(void)
+static bool sectransp_false_start(void)
 {
 #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
   if(SSLSetSessionOption != NULL)
@@ -3145,13 +3151,13 @@ static bool Curl_sectransp_false_start(void)
   return FALSE;
 }
 
-static ssize_t sectransp_send(struct connectdata *conn,
+static ssize_t sectransp_send(struct Curl_easy *data,
                               int sockindex,
                               const void *mem,
                               size_t len,
                               CURLcode *curlcode)
 {
-  /*struct Curl_easy *data = conn->data;*/
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   size_t processed = 0UL;
@@ -3186,7 +3192,7 @@ static ssize_t sectransp_send(struct connectdata *conn,
         *curlcode = CURLE_AGAIN;
         return -1L;
       default:
-        failf(conn->data, "SSLWrite() returned error %d", err);
+        failf(data, "SSLWrite() returned error %d", err);
         *curlcode = CURLE_SEND_ERROR;
         return -1L;
     }
@@ -3203,7 +3209,7 @@ static ssize_t sectransp_send(struct connectdata *conn,
           *curlcode = CURLE_AGAIN;
           return -1L;
         default:
-          failf(conn->data, "SSLWrite() returned error %d", err);
+          failf(data, "SSLWrite() returned error %d", err);
           *curlcode = CURLE_SEND_ERROR;
           return -1L;
       }
@@ -3212,13 +3218,13 @@ static ssize_t sectransp_send(struct connectdata *conn,
   return (ssize_t)processed;
 }
 
-static ssize_t sectransp_recv(struct connectdata *conn,
+static ssize_t sectransp_recv(struct Curl_easy *data,
                               int num,
                               char *buf,
                               size_t buffersize,
                               CURLcode *curlcode)
 {
-  /*struct Curl_easy *data = conn->data;*/
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
   struct ssl_backend_data *backend = connssl->backend;
   size_t processed = 0UL;
@@ -3250,14 +3256,14 @@ static ssize_t sectransp_recv(struct connectdata *conn,
            Leopard's headers */
       case -9841:
         if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) {
-          CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), conn->data,
+          CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data,
                                         backend->ssl_ctx);
           if(result)
             return result;
         }
         goto again;
       default:
-        failf(conn->data, "SSLRead() return error %d", err);
+        failf(data, "SSLRead() return error %d", err);
         *curlcode = CURLE_RECV_ERROR;
         return -1L;
         break;
@@ -3266,8 +3272,8 @@ static ssize_t sectransp_recv(struct connectdata *conn,
   return (ssize_t)processed;
 }
 
-static void *Curl_sectransp_get_internals(struct ssl_connect_data *connssl,
-                                          CURLINFO info UNUSED_PARAM)
+static void *sectransp_get_internals(struct ssl_connect_data *connssl,
+                                     CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
   (void)info;
@@ -3287,24 +3293,23 @@ const struct Curl_ssl Curl_ssl_sectransp = {
 
   Curl_none_init,                     /* init */
   Curl_none_cleanup,                  /* cleanup */
-  Curl_sectransp_version,             /* version */
-  Curl_sectransp_check_cxn,           /* check_cxn */
-  Curl_sectransp_shutdown,            /* shutdown */
-  Curl_sectransp_data_pending,        /* data_pending */
-  Curl_sectransp_random,              /* random */
+  sectransp_version,                  /* version */
+  sectransp_check_cxn,                /* check_cxn */
+  sectransp_shutdown,                 /* shutdown */
+  sectransp_data_pending,             /* data_pending */
+  sectransp_random,                   /* random */
   Curl_none_cert_status_request,      /* cert_status_request */
-  Curl_sectransp_connect,             /* connect */
-  Curl_sectransp_connect_nonblocking, /* connect_nonblocking */
-  Curl_sectransp_get_internals,       /* get_internals */
-  Curl_sectransp_close,               /* close_one */
+  sectransp_connect,                  /* connect */
+  sectransp_connect_nonblocking,      /* connect_nonblocking */
+  sectransp_get_internals,            /* get_internals */
+  sectransp_close,                    /* close_one */
   Curl_none_close_all,                /* close_all */
-  Curl_sectransp_session_free,        /* session_free */
+  sectransp_session_free,             /* session_free */
   Curl_none_set_engine,               /* set_engine */
   Curl_none_set_engine_default,       /* set_engine_default */
   Curl_none_engines_list,             /* engines_list */
-  Curl_sectransp_false_start,         /* false_start */
-  Curl_sectransp_md5sum,              /* md5sum */
-  Curl_sectransp_sha256sum            /* sha256sum */
+  sectransp_false_start,              /* false_start */
+  sectransp_sha256sum                 /* sha256sum */
 };
 
 #ifdef __clang__
index 5cec797..0febd66 100644 (file)
@@ -8,11 +8,11 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>.
- * Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 281043a..b8ab749 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
                                   (1<<CURL_LOCK_DATA_SSL_SESSION)))
 
 #define CLONE_STRING(var)                    \
-  if(source->var) {                          \
-    dest->var = strdup(source->var);         \
-    if(!dest->var)                           \
-      return FALSE;                          \
-  }                                          \
-  else                                       \
-    dest->var = NULL;
-
-#define CLONE_BLOB(var)                         \
-  if(blobdup(&dest->var, source->var))         \
-    return FALSE;
+  do {                                       \
+    if(source->var) {                        \
+      dest->var = strdup(source->var);       \
+      if(!dest->var)                         \
+        return FALSE;                        \
+    }                                        \
+    else                                     \
+      dest->var = NULL;                      \
+  } while(0)
+
+#define CLONE_BLOB(var)                        \
+  do {                                         \
+    if(blobdup(&dest->var, source->var))       \
+      return FALSE;                            \
+  } while(0)
 
 static CURLcode blobdup(struct curl_blob **dest,
                         struct curl_blob *src)
@@ -138,6 +142,7 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
      Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
      Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
      Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
+     Curl_safe_strcasecompare(data->curves, needle->curves) &&
      Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key))
     return TRUE;
 
@@ -164,6 +169,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
   CLONE_STRING(cipher_list);
   CLONE_STRING(cipher_list13);
   CLONE_STRING(pinned_key);
+  CLONE_STRING(curves);
 
   return TRUE;
 }
@@ -179,16 +185,17 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
   Curl_safefree(sslc->cipher_list13);
   Curl_safefree(sslc->pinned_key);
   Curl_safefree(sslc->cert_blob);
+  Curl_safefree(sslc->curves);
 }
 
 #ifdef USE_SSL
-static int multissl_init(const struct Curl_ssl *backend);
+static int multissl_setup(const struct Curl_ssl *backend);
 #endif
 
 int Curl_ssl_backend(void)
 {
 #ifdef USE_SSL
-  multissl_init(NULL);
+  multissl_setup(NULL);
   return Curl_ssl->info.id;
 #else
   return (int)CURLSSLBACKEND_NONE;
@@ -284,7 +291,8 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
 #endif
 
 CURLcode
-Curl_ssl_connect(struct connectdata *conn, int sockindex)
+Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
+                 int sockindex)
 {
   CURLcode result;
 
@@ -296,26 +304,27 @@ Curl_ssl_connect(struct connectdata *conn, int sockindex)
   }
 #endif
 
-  if(!ssl_prefs_check(conn->data))
+  if(!ssl_prefs_check(data))
     return CURLE_SSL_CONNECT_ERROR;
 
   /* mark this is being ssl-enabled from here on. */
   conn->ssl[sockindex].use = TRUE;
   conn->ssl[sockindex].state = ssl_connection_negotiating;
 
-  result = Curl_ssl->connect_blocking(conn, sockindex);
+  result = Curl_ssl->connect_blocking(data, conn, sockindex);
 
   if(!result)
-    Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+    Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
 
   return result;
 }
 
 CURLcode
-Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
-                             bool *done)
+Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
+                             int sockindex, bool *done)
 {
   CURLcode result;
+
 #ifndef CURL_DISABLE_PROXY
   if(conn->bits.proxy_ssl_connected[sockindex]) {
     result = ssl_connect_init_proxy(conn, sockindex);
@@ -323,47 +332,46 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
       return result;
   }
 #endif
-  if(!ssl_prefs_check(conn->data))
+  if(!ssl_prefs_check(data))
     return CURLE_SSL_CONNECT_ERROR;
 
   /* mark this is being ssl requested from here on. */
   conn->ssl[sockindex].use = TRUE;
-  result = Curl_ssl->connect_nonblocking(conn, sockindex, done);
+  result = Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
   if(!result && *done)
-    Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+    Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
   return result;
 }
 
 /*
  * Lock shared SSL session data
  */
-void Curl_ssl_sessionid_lock(struct connectdata *conn)
+void Curl_ssl_sessionid_lock(struct Curl_easy *data)
 {
-  if(SSLSESSION_SHARED(conn->data))
-    Curl_share_lock(conn->data,
-                    CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+  if(SSLSESSION_SHARED(data))
+    Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
 }
 
 /*
  * Unlock shared SSL session data
  */
-void Curl_ssl_sessionid_unlock(struct connectdata *conn)
+void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
 {
-  if(SSLSESSION_SHARED(conn->data))
-    Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
+  if(SSLSESSION_SHARED(data))
+    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
 }
 
 /*
  * Check if there's a session ID for the given connection in the cache, and if
  * there's one suitable, it is provided. Returns TRUE when no entry matched.
  */
-bool Curl_ssl_getsessionid(struct connectdata *conn,
+bool Curl_ssl_getsessionid(struct Curl_easy *data,
+                           struct connectdata *conn,
                            void **ssl_sessionid,
                            size_t *idsize, /* set 0 if unknown */
                            int sockindex)
 {
-  struct curl_ssl_session *check;
-  struct Curl_easy *data = conn->data;
+  struct Curl_ssl_session *check;
   size_t i;
   long *general_age;
   bool no_match = TRUE;
@@ -429,7 +437,7 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
 /*
  * Kill a single session ID entry in the cache.
  */
-void Curl_ssl_kill_session(struct curl_ssl_session *session)
+void Curl_ssl_kill_session(struct Curl_ssl_session *session)
 {
   if(session->sessionid) {
     /* defensive check */
@@ -450,13 +458,12 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)
 /*
  * Delete the given session ID from the cache.
  */
-void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
+void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
 {
   size_t i;
-  struct Curl_easy *data = conn->data;
 
   for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
-    struct curl_ssl_session *check = &data->state.session[i];
+    struct Curl_ssl_session *check = &data->state.session[i];
 
     if(check->sessionid == ssl_sessionid) {
       Curl_ssl_kill_session(check);
@@ -471,14 +478,14 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
  * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
  * later on.
  */
-CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
+                               struct connectdata *conn,
                                void *ssl_sessionid,
                                size_t idsize,
                                int sockindex)
 {
   size_t i;
-  struct Curl_easy *data = conn->data; /* the mother of all structs */
-  struct curl_ssl_session *store = &data->state.session[0];
+  struct Curl_ssl_session *store = &data->state.session[0];
   long oldest_age = data->state.session[0].age; /* zero if unused */
   char *clone_host;
   char *clone_conn_to_host;
@@ -617,16 +624,18 @@ int Curl_ssl_getsock(struct connectdata *conn,
 /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_SECTRANSP || USE_NSS */
 #endif
 
-void Curl_ssl_close(struct connectdata *conn, int sockindex)
+void Curl_ssl_close(struct Curl_easy *data, struct connectdata *conn,
+                    int sockindex)
 {
   DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
-  Curl_ssl->close_one(conn, sockindex);
+  Curl_ssl->close_one(data, conn, sockindex);
   conn->ssl[sockindex].state = ssl_connection_none;
 }
 
-CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
+CURLcode Curl_ssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
+                           int sockindex)
 {
-  if(Curl_ssl->shut_down(conn, sockindex))
+  if(Curl_ssl->shut_down(data, conn, sockindex))
     return CURLE_SSL_SHUTDOWN_FAILED;
 
   conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
@@ -664,13 +673,13 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
  */
 CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
 {
-  struct curl_ssl_session *session;
+  struct Curl_ssl_session *session;
 
   if(data->state.session)
     /* this is just a precaution to prevent multiple inits */
     return CURLE_OK;
 
-  session = calloc(amount, sizeof(struct curl_ssl_session));
+  session = calloc(amount, sizeof(struct Curl_ssl_session));
   if(!session)
     return CURLE_OUT_OF_MEMORY;
 
@@ -681,12 +690,12 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
   return CURLE_OK;
 }
 
-static size_t Curl_multissl_version(char *buffer, size_t size);
+static size_t multissl_version(char *buffer, size_t size);
 
 size_t Curl_ssl_version(char *buffer, size_t size)
 {
 #ifdef CURL_WITH_MULTI_SSL
-  return Curl_multissl_version(buffer, size);
+  return multissl_version(buffer, size);
 #else
   return Curl_ssl->version(buffer, size);
 #endif
@@ -1027,16 +1036,6 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
   return result;
 }
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
-                         size_t tmplen,
-                         unsigned char *md5sum, /* output */
-                         size_t md5len)
-{
-  return Curl_ssl->md5sum(tmp, tmplen, md5sum, md5len);
-}
-#endif
-
 /*
  * Check whether the SSL backend supports the status_request extension.
  */
@@ -1073,9 +1072,11 @@ int Curl_none_init(void)
 void Curl_none_cleanup(void)
 { }
 
-int Curl_none_shutdown(struct connectdata *conn UNUSED_PARAM,
+int Curl_none_shutdown(struct Curl_easy *data UNUSED_PARAM,
+                       struct connectdata *conn UNUSED_PARAM,
                        int sockindex UNUSED_PARAM)
 {
+  (void)data;
   (void)conn;
   (void)sockindex;
   return 0;
@@ -1145,70 +1146,44 @@ bool Curl_none_false_start(void)
   return FALSE;
 }
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
-                          unsigned char *md5sum, size_t md5len UNUSED_PARAM)
+static int multissl_init(void)
 {
-  struct MD5_context *MD5pw;
-
-  (void)md5len;
-
-  MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
-  if(!MD5pw)
-    return CURLE_OUT_OF_MEMORY;
-  Curl_MD5_update(MD5pw, input, curlx_uztoui(inputlen));
-  Curl_MD5_final(MD5pw, md5sum);
-  return CURLE_OK;
-}
-#else
-CURLcode Curl_none_md5sum(unsigned char *input UNUSED_PARAM,
-                          size_t inputlen UNUSED_PARAM,
-                          unsigned char *md5sum UNUSED_PARAM,
-                          size_t md5len UNUSED_PARAM)
-{
-  (void)input;
-  (void)inputlen;
-  (void)md5sum;
-  (void)md5len;
-  return CURLE_NOT_BUILT_IN;
-}
-#endif
-
-static int Curl_multissl_init(void)
-{
-  if(multissl_init(NULL))
+  if(multissl_setup(NULL))
     return 1;
   return Curl_ssl->init();
 }
 
-static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex)
+static CURLcode multissl_connect(struct Curl_easy *data,
+                                 struct connectdata *conn, int sockindex)
 {
-  if(multissl_init(NULL))
+  if(multissl_setup(NULL))
     return CURLE_FAILED_INIT;
-  return Curl_ssl->connect_blocking(conn, sockindex);
+  return Curl_ssl->connect_blocking(data, conn, sockindex);
 }
 
-static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn,
-                                                  int sockindex, bool *done)
+static CURLcode multissl_connect_nonblocking(struct Curl_easy *data,
+                                             struct connectdata *conn,
+                                             int sockindex, bool *done)
 {
-  if(multissl_init(NULL))
+  if(multissl_setup(NULL))
     return CURLE_FAILED_INIT;
-  return Curl_ssl->connect_nonblocking(conn, sockindex, done);
+  return Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
 }
 
-static void *Curl_multissl_get_internals(struct ssl_connect_data *connssl,
-                                         CURLINFO info)
+static void *multissl_get_internals(struct ssl_connect_data *connssl,
+                                    CURLINFO info)
 {
-  if(multissl_init(NULL))
+  if(multissl_setup(NULL))
     return NULL;
   return Curl_ssl->get_internals(connssl, info);
 }
 
-static void Curl_multissl_close(struct connectdata *conn, int sockindex)
+static void multissl_close(struct Curl_easy *data, struct connectdata *conn,
+                           int sockindex)
 {
-  if(multissl_init(NULL))
+  if(multissl_setup(NULL))
     return;
-  Curl_ssl->close_one(conn, sockindex);
+  Curl_ssl->close_one(data, conn, sockindex);
 }
 
 static const struct Curl_ssl Curl_ssl_multi = {
@@ -1216,25 +1191,24 @@ static const struct Curl_ssl Curl_ssl_multi = {
   0, /* supports nothing */
   (size_t)-1, /* something insanely large to be on the safe side */
 
-  Curl_multissl_init,                /* init */
+  multissl_init,                     /* init */
   Curl_none_cleanup,                 /* cleanup */
-  Curl_multissl_version,             /* version */
+  multissl_version,                  /* version */
   Curl_none_check_cxn,               /* check_cxn */
   Curl_none_shutdown,                /* shutdown */
   Curl_none_data_pending,            /* data_pending */
   Curl_none_random,                  /* random */
   Curl_none_cert_status_request,     /* cert_status_request */
-  Curl_multissl_connect,             /* connect */
-  Curl_multissl_connect_nonblocking, /* connect_nonblocking */
-  Curl_multissl_get_internals,       /* get_internals */
-  Curl_multissl_close,               /* close_one */
+  multissl_connect,                  /* connect */
+  multissl_connect_nonblocking,      /* connect_nonblocking */
+  multissl_get_internals,            /* get_internals */
+  multissl_close,                    /* close_one */
   Curl_none_close_all,               /* close_all */
   Curl_none_session_free,            /* session_free */
   Curl_none_set_engine,              /* set_engine */
   Curl_none_set_engine_default,      /* set_engine_default */
   Curl_none_engines_list,            /* engines_list */
   Curl_none_false_start,             /* false_start */
-  Curl_none_md5sum,                  /* md5sum */
   NULL                               /* sha256sum */
 };
 
@@ -1299,7 +1273,7 @@ static const struct Curl_ssl *available_backends[] = {
   NULL
 };
 
-static size_t Curl_multissl_version(char *buffer, size_t size)
+static size_t multissl_version(char *buffer, size_t size)
 {
   static const struct Curl_ssl *selected;
   static char backends[200];
@@ -1343,7 +1317,7 @@ static size_t Curl_multissl_version(char *buffer, size_t size)
   return backends_len;
 }
 
-static int multissl_init(const struct Curl_ssl *backend)
+static int multissl_setup(const struct Curl_ssl *backend)
 {
   const char *env;
   char *env_tmp;
@@ -1402,7 +1376,7 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
   for(i = 0; available_backends[i]; i++) {
     if(available_backends[i]->info.id == id ||
        (name && strcasecompare(available_backends[i]->info.name, name))) {
-      multissl_init(available_backends[i]);
+      multissl_setup(available_backends[i]);
       return CURLSSLSET_OK;
     }
   }
index bcc8444..9666682 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -47,7 +47,8 @@ struct Curl_ssl {
 
   size_t (*version)(char *buffer, size_t size);
   int (*check_cxn)(struct connectdata *cxn);
-  int (*shut_down)(struct connectdata *conn, int sockindex);
+  int (*shut_down)(struct Curl_easy *data, struct connectdata *conn,
+                   int sockindex);
   bool (*data_pending)(const struct connectdata *conn,
                        int connindex);
 
@@ -56,11 +57,14 @@ struct Curl_ssl {
                      size_t length);
   bool (*cert_status_request)(void);
 
-  CURLcode (*connect_blocking)(struct connectdata *conn, int sockindex);
-  CURLcode (*connect_nonblocking)(struct connectdata *conn, int sockindex,
+  CURLcode (*connect_blocking)(struct Curl_easy *data,
+                               struct connectdata *conn, int sockindex);
+  CURLcode (*connect_nonblocking)(struct Curl_easy *data,
+                                  struct connectdata *conn, int sockindex,
                                   bool *done);
   void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
-  void (*close_one)(struct connectdata *conn, int sockindex);
+  void (*close_one)(struct Curl_easy *data, struct connectdata *conn,
+                    int sockindex);
   void (*close_all)(struct Curl_easy *data);
   void (*session_free)(void *ptr);
 
@@ -69,9 +73,6 @@ struct Curl_ssl {
   struct curl_slist *(*engines_list)(struct Curl_easy *data);
 
   bool (*false_start)(void);
-
-  CURLcode (*md5sum)(unsigned char *input, size_t inputlen,
-                     unsigned char *md5sum, size_t md5sumlen);
   CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
                     unsigned char *sha256sum, size_t sha256sumlen);
 };
@@ -82,7 +83,8 @@ extern const struct Curl_ssl *Curl_ssl;
 
 int Curl_none_init(void);
 void Curl_none_cleanup(void);
-int Curl_none_shutdown(struct connectdata *conn, int sockindex);
+int Curl_none_shutdown(struct Curl_easy *data, struct connectdata *conn,
+                       int sockindex);
 int Curl_none_check_cxn(struct connectdata *conn);
 CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
                           size_t length);
@@ -95,8 +97,6 @@ CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
 struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
 bool Curl_none_false_start(void);
 bool Curl_ssl_tls13_ciphersuites(void);
-CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
-                          unsigned char *md5sum, size_t md5len);
 
 #include "openssl.h"        /* OpenSSL versions */
 #include "gtls.h"           /* GnuTLS versions */
@@ -131,12 +131,26 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
                    CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
 #define SSL_SET_OPTION(var)                                             \
   (SSL_IS_PROXY() ? data->set.proxy_ssl.var : data->set.ssl.var)
+#define SSL_SET_OPTION_LVALUE(var)                                      \
+  (*(SSL_IS_PROXY() ? &data->set.proxy_ssl.var : &data->set.ssl.var))
 #define SSL_CONN_CONFIG(var)                                            \
   (SSL_IS_PROXY() ? conn->proxy_ssl_config.var : conn->ssl_config.var)
+#define SSL_HOST_NAME()                                                 \
+  (SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name)
+#define SSL_HOST_DISPNAME()                                             \
+  (SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname)
+#define SSL_PINNED_PUB_KEY() (SSL_IS_PROXY()                            \
+  ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]                     \
+  : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG])
 #else
 #define SSL_IS_PROXY() FALSE
 #define SSL_SET_OPTION(var) data->set.ssl.var
+#define SSL_SET_OPTION_LVALUE(var) data->set.ssl.var
 #define SSL_CONN_CONFIG(var) conn->ssl_config.var
+#define SSL_HOST_NAME() conn->host.name
+#define SSL_HOST_DISPNAME() conn->host.dispname
+#define SSL_PINNED_PUB_KEY()                                            \
+  data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]
 #endif
 
 bool Curl_ssl_config_matches(struct ssl_primary_config *data,
@@ -151,15 +165,19 @@ int Curl_ssl_backend(void);
 #ifdef USE_SSL
 int Curl_ssl_init(void);
 void Curl_ssl_cleanup(void);
-CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
+CURLcode Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
+                          int sockindex);
+CURLcode Curl_ssl_connect_nonblocking(struct Curl_easy *data,
+                                      struct connectdata *conn,
                                       int sockindex,
                                       bool *done);
 /* tell the SSL stuff to close down all open information regarding
    connections (and thus session ID caching etc) */
 void Curl_ssl_close_all(struct Curl_easy *data);
-void Curl_ssl_close(struct connectdata *conn, int sockindex);
-CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
+void Curl_ssl_close(struct Curl_easy *data, struct connectdata *conn,
+                    int sockindex);
+CURLcode Curl_ssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
+                           int sockindex);
 CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine);
 /* Sets engine as default for all SSL operations */
 CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data);
@@ -191,10 +209,10 @@ CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum,
  * The purpose of explicitly locking SSL session cache data is to allow
  * individual SSL engines to manage session lifetime in their specific way.
  */
-void Curl_ssl_sessionid_lock(struct connectdata *conn);
+void Curl_ssl_sessionid_lock(struct Curl_easy *data);
 
 /* Unlock session cache mutex */
-void Curl_ssl_sessionid_unlock(struct connectdata *conn);
+void Curl_ssl_sessionid_unlock(struct Curl_easy *data);
 
 /* extract a session ID
  * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
@@ -202,7 +220,8 @@ void Curl_ssl_sessionid_unlock(struct connectdata *conn);
  * is properly taken (e.g. its refcount is incremented
  * under sessionid mutex).
  */
-bool Curl_ssl_getsessionid(struct connectdata *conn,
+bool Curl_ssl_getsessionid(struct Curl_easy *data,
+                           struct connectdata *conn,
                            void **ssl_sessionid,
                            size_t *idsize, /* set 0 if unknown */
                            int sockindex);
@@ -211,7 +230,8 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
  * Caller must ensure that it has properly shared ownership of this sessionid
  * object with cache (e.g. incrementing refcount on success)
  */
-CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
+                               struct connectdata *conn,
                                void *ssl_sessionid,
                                size_t idsize,
                                int sockindex);
@@ -221,22 +241,18 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
  * take sessionid object ownership from sessionid cache
  * (e.g. decrement refcount).
  */
-void Curl_ssl_kill_session(struct curl_ssl_session *session);
+void Curl_ssl_kill_session(struct Curl_ssl_session *session);
 /* delete a session from the cache
  * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
  * This will call engine-specific curlssl_session_free function, which must
  * take sessionid object ownership from sessionid cache
  * (e.g. decrement refcount).
  */
-void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
+void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid);
 
 /* get N random bytes into the buffer */
 CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer,
                          size_t length);
-CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
-                         size_t tmplen,
-                         unsigned char *md5sum, /* output */
-                         size_t md5len);
 /* Check pinned public key. */
 CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
                               const char *pinnedpubkey,
@@ -253,10 +269,10 @@ bool Curl_ssl_false_start(void);
 /* When SSL support is not present, just define away these function calls */
 #define Curl_ssl_init() 1
 #define Curl_ssl_cleanup() Curl_nop_stmt
-#define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_connect(x,y,z) CURLE_NOT_BUILT_IN
 #define Curl_ssl_close_all(x) Curl_nop_stmt
-#define Curl_ssl_close(x,y) Curl_nop_stmt
-#define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_close(x,y,z) Curl_nop_stmt
+#define Curl_ssl_shutdown(x,y,z) CURLE_NOT_BUILT_IN
 #define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
 #define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
 #define Curl_ssl_engines_list(x) NULL
@@ -266,7 +282,7 @@ bool Curl_ssl_false_start(void);
 #define Curl_ssl_data_pending(x,y) 0
 #define Curl_ssl_check_cxn(x) 0
 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt
-#define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN
+#define Curl_ssl_connect_nonblocking(x,y,z,w) CURLE_NOT_BUILT_IN
 #define Curl_ssl_kill_session(x) Curl_nop_stmt
 #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
 #define Curl_ssl_cert_status_request() FALSE
index 7b2a124..e1fa459 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -217,11 +217,10 @@ static int do_file_type(const char *type)
  * layer and do all necessary magic.
  */
 static CURLcode
-wolfssl_connect_step1(struct connectdata *conn,
+wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
                      int sockindex)
 {
   char *ciphers;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   SSL_METHOD* req_method = NULL;
@@ -256,7 +255,7 @@ wolfssl_connect_step1(struct connectdata *conn,
     use_sni(TRUE);
     break;
   case CURL_SSLVERSION_TLSv1_0:
-#ifdef WOLFSSL_ALLOW_TLSV10
+#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
     req_method = TLSv1_client_method();
     use_sni(TRUE);
 #else
@@ -265,8 +264,13 @@ wolfssl_connect_step1(struct connectdata *conn,
 #endif
     break;
   case CURL_SSLVERSION_TLSv1_1:
+#ifndef NO_OLD_TLS
     req_method = TLSv1_1_client_method();
     use_sni(TRUE);
+#else
+    failf(data, "wolfSSL does not support TLS 1.1");
+    return CURLE_NOT_BUILT_IN;
+#endif
     break;
   case CURL_SSLVERSION_TLSv1_2:
     req_method = TLSv1_2_client_method();
@@ -353,8 +357,8 @@ wolfssl_connect_step1(struct connectdata *conn,
                                       SSL_CONN_CONFIG(CApath))) {
       if(SSL_CONN_CONFIG(verifypeer)) {
         /* Fail if we insist on successfully verifying the server. */
-        failf(data, "error setting certificate verify locations:\n"
-              "  CAfile: %s\n  CApath: %s",
+        failf(data, "error setting certificate verify locations:"
+              " CAfile: %s CApath: %s",
               SSL_CONN_CONFIG(CAfile)?
               SSL_CONN_CONFIG(CAfile): "none",
               SSL_CONN_CONFIG(CApath)?
@@ -372,21 +376,19 @@ wolfssl_connect_step1(struct connectdata *conn,
       /* Everything is fine. */
       infof(data, "successfully set certificate verify locations:\n");
     }
-    infof(data,
-          "  CAfile: %s\n"
-          "  CApath: %s\n",
-          SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
-          "none",
-          SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath):
-          "none");
+    infof(data, " CAfile: %s\n",
+          SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none");
+    infof(data, " CApath: %s\n",
+          SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none");
   }
 
   /* Load the client certificate, and private key */
-  if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
+  if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
     int file_type = do_file_type(SSL_SET_OPTION(cert_type));
 
-    if(SSL_CTX_use_certificate_file(backend->ctx, SSL_SET_OPTION(cert),
-                                     file_type) != 1) {
+    if(SSL_CTX_use_certificate_file(backend->ctx,
+                                    SSL_SET_OPTION(primary.clientcert),
+                                    file_type) != 1) {
       failf(data, "unable to use client certificate (no key or wrong pass"
             " phrase?)");
       return CURLE_SSL_CONNECT_ERROR;
@@ -502,16 +504,23 @@ wolfssl_connect_step1(struct connectdata *conn,
   }
 #endif /* OPENSSL_EXTRA */
 
+#ifdef HAVE_SECURE_RENEGOTIATION
+  if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
+    failf(data, "SSL: failed setting secure renegotiation");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+#endif /* HAVE_SECURE_RENEGOTIATION */
+
   /* Check if there's a cached ID we can/should use here! */
   if(SSL_SET_OPTION(primary.sessionid)) {
     void *ssl_sessionid = NULL;
 
-    Curl_ssl_sessionid_lock(conn);
-    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
+    Curl_ssl_sessionid_lock(data);
+    if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
       /* we got a session id, use it! */
       if(!SSL_set_session(backend->handle, ssl_sessionid)) {
         char error_buffer[WOLFSSL_MAX_ERROR_SZ];
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(data, "SSL: SSL_set_session failed: %s",
               ERR_error_string(SSL_get_error(backend->handle, 0),
                                error_buffer));
@@ -520,7 +529,7 @@ wolfssl_connect_step1(struct connectdata *conn,
       /* Informational message */
       infof(data, "SSL re-using session ID\n");
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   /* pass the raw socket into the SSL layer */
@@ -535,11 +544,10 @@ wolfssl_connect_step1(struct connectdata *conn,
 
 
 static CURLcode
-wolfssl_connect_step2(struct connectdata *conn,
+wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
                      int sockindex)
 {
   int ret = -1;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
 #ifndef CURL_DISABLE_PROXY
@@ -610,7 +618,7 @@ wolfssl_connect_step2(struct connectdata *conn,
      * as also mismatching CN fields */
     else if(DOMAIN_NAME_MISMATCH == detail) {
 #if 1
-      failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
+      failf(data, "\tsubject alt name(s) or common name do not match \"%s\"",
             dispname);
       return CURLE_PEER_FAILED_VERIFICATION;
 #else
@@ -637,7 +645,7 @@ wolfssl_connect_step2(struct connectdata *conn,
 #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
     else if(ASN_NO_SIGNER_E == detail) {
       if(SSL_CONN_CONFIG(verifypeer)) {
-        failf(data, "\tCA signer not available for verification\n");
+        failf(data, "\tCA signer not available for verification");
         return CURLE_SSL_CACERT_BADFILE;
       }
       else {
@@ -725,7 +733,7 @@ wolfssl_connect_step2(struct connectdata *conn,
       else
         infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
               protocol);
-      Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
+      Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
     }
     else if(rc == SSL_ALPN_NOT_FOUND)
@@ -751,11 +759,10 @@ wolfssl_connect_step2(struct connectdata *conn,
 
 
 static CURLcode
-wolfssl_connect_step3(struct connectdata *conn,
+wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
                      int sockindex)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
 
@@ -768,27 +775,27 @@ wolfssl_connect_step3(struct connectdata *conn,
 
     our_ssl_sessionid = SSL_get_session(backend->handle);
 
-    Curl_ssl_sessionid_lock(conn);
-    incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
+    Curl_ssl_sessionid_lock(data);
+    incache = !(Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL,
                                       sockindex));
     if(incache) {
       if(old_ssl_sessionid != our_ssl_sessionid) {
         infof(data, "old SSL session ID is stale, removing\n");
-        Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+        Curl_ssl_delsessionid(data, old_ssl_sessionid);
         incache = FALSE;
       }
     }
 
     if(!incache) {
-      result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+      result = Curl_ssl_addsessionid(data, conn, our_ssl_sessionid,
                                      0 /* unknown size */, sockindex);
       if(result) {
-        Curl_ssl_sessionid_unlock(conn);
+        Curl_ssl_sessionid_unlock(data);
         failf(data, "failed to store ssl session");
         return result;
       }
     }
-    Curl_ssl_sessionid_unlock(conn);
+    Curl_ssl_sessionid_unlock(data);
   }
 
   connssl->connecting_state = ssl_connect_done;
@@ -797,12 +804,13 @@ wolfssl_connect_step3(struct connectdata *conn,
 }
 
 
-static ssize_t wolfssl_send(struct connectdata *conn,
-                           int sockindex,
-                           const void *mem,
-                           size_t len,
-                           CURLcode *curlcode)
+static ssize_t wolfssl_send(struct Curl_easy *data,
+                            int sockindex,
+                            const void *mem,
+                            size_t len,
+                            CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
@@ -819,7 +827,7 @@ static ssize_t wolfssl_send(struct connectdata *conn,
       *curlcode = CURLE_AGAIN;
       return -1;
     default:
-      failf(conn->data, "SSL write: %s, errno %d",
+      failf(data, "SSL write: %s, errno %d",
             ERR_error_string(err, error_buffer),
             SOCKERRNO);
       *curlcode = CURLE_SEND_ERROR;
@@ -829,11 +837,14 @@ static ssize_t wolfssl_send(struct connectdata *conn,
   return rc;
 }
 
-static void Curl_wolfssl_close(struct connectdata *conn, int sockindex)
+static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
+                          int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
 
+  (void) data;
+
   if(backend->handle) {
     (void)SSL_shutdown(backend->handle);
     SSL_free(backend->handle);
@@ -845,12 +856,13 @@ static void Curl_wolfssl_close(struct connectdata *conn, int sockindex)
   }
 }
 
-static ssize_t wolfssl_recv(struct connectdata *conn,
+static ssize_t wolfssl_recv(struct Curl_easy *data,
                             int num,
                             char *buf,
                             size_t buffersize,
                             CURLcode *curlcode)
 {
+  struct connectdata *conn = data->conn;
   struct ssl_connect_data *connssl = &conn->ssl[num];
   struct ssl_backend_data *backend = connssl->backend;
   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
@@ -869,9 +881,8 @@ static ssize_t wolfssl_recv(struct connectdata *conn,
       *curlcode = CURLE_AGAIN;
       return -1;
     default:
-      failf(conn->data, "SSL read: %s, errno %d",
-            ERR_error_string(err, error_buffer),
-            SOCKERRNO);
+      failf(data, "SSL read: %s, errno %d",
+            ERR_error_string(err, error_buffer), SOCKERRNO);
       *curlcode = CURLE_RECV_ERROR;
       return -1;
     }
@@ -880,14 +891,14 @@ static ssize_t wolfssl_recv(struct connectdata *conn,
 }
 
 
-static void Curl_wolfssl_session_free(void *ptr)
+static void wolfssl_session_free(void *ptr)
 {
   (void)ptr;
   /* wolfSSL reuses sessions on own, no free */
 }
 
 
-static size_t Curl_wolfssl_version(char *buffer, size_t size)
+static size_t wolfssl_version(char *buffer, size_t size)
 {
 #if LIBWOLFSSL_VERSION_HEX >= 0x03006000
   return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
@@ -897,7 +908,7 @@ static size_t Curl_wolfssl_version(char *buffer, size_t size)
 }
 
 
-static int Curl_wolfssl_init(void)
+static int wolfssl_init(void)
 {
 #ifdef OPENSSL_EXTRA
   Curl_tls_keylog_open();
@@ -906,7 +917,7 @@ static int Curl_wolfssl_init(void)
 }
 
 
-static void Curl_wolfssl_cleanup(void)
+static void wolfssl_cleanup(void)
 {
   wolfSSL_Cleanup();
 #ifdef OPENSSL_EXTRA
@@ -915,8 +926,8 @@ static void Curl_wolfssl_cleanup(void)
 }
 
 
-static bool Curl_wolfssl_data_pending(const struct connectdata *conn,
-                                      int connindex)
+static bool wolfssl_data_pending(const struct connectdata *conn,
+                                 int connindex)
 {
   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
   struct ssl_backend_data *backend = connssl->backend;
@@ -931,12 +942,15 @@ static bool Curl_wolfssl_data_pending(const struct connectdata *conn,
  * This function is called to shut down the SSL layer but keep the
  * socket open (CCC - Clear Command Channel)
  */
-static int Curl_wolfssl_shutdown(struct connectdata *conn, int sockindex)
+static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
+                            int sockindex)
 {
   int retval = 0;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
 
+  (void) data;
+
   if(backend->handle) {
     SSL_free(backend->handle);
     backend->handle = NULL;
@@ -946,13 +960,13 @@ static int Curl_wolfssl_shutdown(struct connectdata *conn, int sockindex)
 
 
 static CURLcode
-wolfssl_connect_common(struct connectdata *conn,
+wolfssl_connect_common(struct Curl_easy *data,
+                      struct connectdata *conn,
                       int sockindex,
                       bool nonblocking,
                       bool *done)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   int what;
@@ -973,7 +987,7 @@ wolfssl_connect_common(struct connectdata *conn,
       return CURLE_OPERATION_TIMEDOUT;
     }
 
-    result = wolfssl_connect_step1(conn, sockindex);
+    result = wolfssl_connect_step1(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -1028,7 +1042,7 @@ wolfssl_connect_common(struct connectdata *conn,
      * ensuring that a client using select() or epoll() will always
      * have a valid fdset to wait on.
      */
-    result = wolfssl_connect_step2(conn, sockindex);
+    result = wolfssl_connect_step2(data, conn, sockindex);
     if(result || (nonblocking &&
                   (ssl_connect_2 == connssl->connecting_state ||
                    ssl_connect_2_reading == connssl->connecting_state ||
@@ -1037,7 +1051,7 @@ wolfssl_connect_common(struct connectdata *conn,
   } /* repeat step2 until all transactions are done. */
 
   if(ssl_connect_3 == connssl->connecting_state) {
-    result = wolfssl_connect_step3(conn, sockindex);
+    result = wolfssl_connect_step3(data, conn, sockindex);
     if(result)
       return result;
   }
@@ -1058,19 +1072,21 @@ wolfssl_connect_common(struct connectdata *conn,
 }
 
 
-static CURLcode Curl_wolfssl_connect_nonblocking(struct connectdata *conn,
-                                                int sockindex, bool *done)
+static CURLcode wolfssl_connect_nonblocking(struct Curl_easy *data,
+                                            struct connectdata *conn,
+                                            int sockindex, bool *done)
 {
-  return wolfssl_connect_common(conn, sockindex, TRUE, done);
+  return wolfssl_connect_common(data, conn, sockindex, TRUE, done);
 }
 
 
-static CURLcode Curl_wolfssl_connect(struct connectdata *conn, int sockindex)
+static CURLcode wolfssl_connect(struct Curl_easy *data,
+                                struct connectdata *conn, int sockindex)
 {
   CURLcode result;
   bool done = FALSE;
 
-  result = wolfssl_connect_common(conn, sockindex, FALSE, &done);
+  result = wolfssl_connect_common(data, conn, sockindex, FALSE, &done);
   if(result)
     return result;
 
@@ -1079,8 +1095,8 @@ static CURLcode Curl_wolfssl_connect(struct connectdata *conn, int sockindex)
   return CURLE_OK;
 }
 
-static CURLcode Curl_wolfssl_random(struct Curl_easy *data,
-                                   unsigned char *entropy, size_t length)
+static CURLcode wolfssl_random(struct Curl_easy *data,
+                               unsigned char *entropy, size_t length)
 {
   WC_RNG rng;
   (void)data;
@@ -1095,10 +1111,10 @@ static CURLcode Curl_wolfssl_random(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */
-                                       size_t tmplen,
-                                       unsigned char *sha256sum /* output */,
-                                       size_t unused)
+static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
+                                  size_t tmplen,
+                                  unsigned char *sha256sum /* output */,
+                                  size_t unused)
 {
   wc_Sha256 SHA256pw;
   (void)unused;
@@ -1108,7 +1124,7 @@ static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */
   return CURLE_OK;
 }
 
-static void *Curl_wolfssl_get_internals(struct ssl_connect_data *connssl,
+static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
                                         CURLINFO info UNUSED_PARAM)
 {
   struct ssl_backend_data *backend = connssl->backend;
@@ -1126,26 +1142,25 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
 
   sizeof(struct ssl_backend_data),
 
-  Curl_wolfssl_init,                /* init */
-  Curl_wolfssl_cleanup,             /* cleanup */
-  Curl_wolfssl_version,             /* version */
+  wolfssl_init,                    /* init */
+  wolfssl_cleanup,                 /* cleanup */
+  wolfssl_version,                 /* version */
   Curl_none_check_cxn,             /* check_cxn */
-  Curl_wolfssl_shutdown,            /* shutdown */
-  Curl_wolfssl_data_pending,        /* data_pending */
-  Curl_wolfssl_random,              /* random */
+  wolfssl_shutdown,                /* shutdown */
+  wolfssl_data_pending,            /* data_pending */
+  wolfssl_random,                  /* random */
   Curl_none_cert_status_request,   /* cert_status_request */
-  Curl_wolfssl_connect,             /* connect */
-  Curl_wolfssl_connect_nonblocking, /* connect_nonblocking */
-  Curl_wolfssl_get_internals,       /* get_internals */
-  Curl_wolfssl_close,               /* close_one */
+  wolfssl_connect,                 /* connect */
+  wolfssl_connect_nonblocking,     /* connect_nonblocking */
+  wolfssl_get_internals,           /* get_internals */
+  wolfssl_close,                   /* close_one */
   Curl_none_close_all,             /* close_all */
-  Curl_wolfssl_session_free,        /* session_free */
+  wolfssl_session_free,            /* session_free */
   Curl_none_set_engine,            /* set_engine */
   Curl_none_set_engine_default,    /* set_engine_default */
   Curl_none_engines_list,          /* engines_list */
   Curl_none_false_start,           /* false_start */
-  Curl_none_md5sum,                /* md5sum */
-  Curl_wolfssl_sha256sum            /* sha256sum */
+  wolfssl_sha256sum                /* sha256sum */
 };
 
 #endif
index 2b9673c..d411e69 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index cfd5e8e..c0764c4 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -156,25 +156,6 @@ unsigned char curlx_ultouc(unsigned long ulnum)
 }
 
 /*
-** unsigned long to signed int
-*/
-
-int curlx_ultosi(unsigned long ulnum)
-{
-#ifdef __INTEL_COMPILER
-#  pragma warning(push)
-#  pragma warning(disable:810) /* conversion may lose significant bits */
-#endif
-
-  DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_SINT);
-  return (int)(ulnum & (unsigned long) CURL_MASK_SINT);
-
-#ifdef __INTEL_COMPILER
-#  pragma warning(pop)
-#endif
-}
-
-/*
 ** unsigned size_t to signed curl_off_t
 */
 
index ab78f94..2c619bf 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -33,8 +33,6 @@ unsigned short curlx_ultous(unsigned long ulnum);
 
 unsigned char curlx_ultouc(unsigned long ulnum);
 
-int curlx_ultosi(unsigned long ulnum);
-
 int curlx_uztosi(size_t uznum);
 
 curl_off_t curlx_uztoso(size_t uznum);
index e94d3c5..105bcce 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
index 306c8c9..081be9e 100644 (file)
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2010 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010 - 2020, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -39,18 +39,18 @@ typedef enum {
   CURLWC_ERROR, /* error cases */
   CURLWC_DONE   /* if is wildcard->state == CURLWC_DONE wildcard loop
                    will end */
-} curl_wildcard_states;
+} wildcard_states;
 
-typedef void (*curl_wildcard_dtor)(void *ptr);
+typedef void (*wildcard_dtor)(void *ptr);
 
 /* struct keeping information about wildcard download process */
 struct WildcardData {
-  curl_wildcard_states state;
+  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 */
+  struct Curl_llist filelist; /* llist with struct Curl_fileinfo */
   void *protdata; /* pointer to protocol specific temporary data */
-  curl_wildcard_dtor dtor;
+  wildcard_dtor dtor;
   void *customptr;  /* for CURLOPT_CHUNK_DATA pointer */
 };
 
index 52747d5..f29aa05 100644 (file)
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -945,13 +945,12 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
   }
 }
 
-CURLcode Curl_extract_certinfo(struct connectdata *conn,
+CURLcode Curl_extract_certinfo(struct Curl_easy *data,
                                int certnum,
                                const char *beg,
                                const char *end)
 {
   struct Curl_X509certificate cert;
-  struct Curl_easy *data = conn->data;
   struct Curl_asn1Element param;
   const char *ccp;
   char *cp1;
@@ -1132,10 +1131,9 @@ static const char *checkOID(const char *beg, const char *end,
   return matched? ccp: NULL;
 }
 
-CURLcode Curl_verifyhost(struct connectdata *conn,
+CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
                          const char *beg, const char *end)
 {
-  struct Curl_easy *data = conn->data;
   struct Curl_X509certificate cert;
   struct Curl_asn1Element dn;
   struct Curl_asn1Element elem;
index 0b7fb88..326e32d 100644 (file)
@@ -8,11 +8,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, 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.haxx.se/docs/copyright.html.
+ * 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
@@ -125,9 +125,9 @@ const char *Curl_ASN1tostr(struct Curl_asn1Element *elem, int type);
 const char *Curl_DNtostr(struct Curl_asn1Element *dn);
 int Curl_parseX509(struct Curl_X509certificate *cert,
                    const char *beg, const char *end);
-CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum,
+CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
                                const char *beg, const char *end);
-CURLcode Curl_verifyhost(struct connectdata *conn,
+CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
                          const char *beg, const char *end);
 #endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */
 #endif /* HEADER_CURL_X509ASN1_H */
index cf31556..b8dc4e8 100644 (file)
@@ -1,6 +1,6 @@
 # Disable warnings to avoid changing 3rd party code.
 IF(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 764be8d..74e9988 100644 (file)
@@ -2,7 +2,7 @@ project(JsonCpp CXX)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_CXX_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
 elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woffall")
index 6eeba0e..8362fc4 100644 (file)
@@ -2,74 +2,88 @@
 // Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
 // Distributed under MIT license, or public domain if desired and
 // recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+// See file LICENSE for detail or copy at
+// http://jsoncpp.sourceforge.net/LICENSE
 
 #if !defined(JSON_IS_AMALGAMATION)
-#include <json/assertions.h>
-#include <json/reader.h>
-#include <json/value.h>
-#include "json_tool.h"
+#  include <json/assertions.h>
+#  include <json/reader.h>
+#  include <json/value.h>
+
+#  include "json_tool.h"
 #endif // if !defined(JSON_IS_AMALGAMATION)
-#include <utility>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
 #include <istream>
-#include <sstream>
+#include <limits>
 #include <memory>
 #include <set>
-#include <limits>
+#include <sstream>
+#include <utility>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
 
 #if defined(_MSC_VER)
-#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above 
-#define snprintf sprintf_s
-#elif _MSC_VER >= 1900 // VC++ 14.0 and above
-#define snprintf std::snprintf
-#else
-#define snprintf _snprintf
-#endif
+#  if !defined(WINCE) && defined(__STDC_SECURE_LIB__) &&                      \
+    _MSC_VER >= 1500 // VC++ 9.0 and above
+#    define snprintf sprintf_s
+#  elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#    define snprintf std::snprintf
+#  else
+#    define snprintf _snprintf
+#  endif
 #elif defined(__ANDROID__) || defined(__QNXNTO__)
-#define snprintf snprintf
+#  define snprintf snprintf
 #elif __cplusplus >= 201103L
-#if !defined(__MINGW32__) && !defined(__CYGWIN__)
-#define snprintf std::snprintf
-#endif
+#  if !defined(__MINGW32__) && !defined(__CYGWIN__)
+#    define snprintf std::snprintf
+#  endif
 #endif
 
 #if defined(__QNXNTO__)
-#define sscanf std::sscanf
+#  define sscanf std::sscanf
 #endif
 
 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
 // Disable warning about strdup being deprecated.
-#pragma warning(disable : 4996)
+#  pragma warning(disable : 4996)
 #endif
 
-// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
+// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
+// time to change the stack limit
 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
-#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
+#  define JSONCPP_DEPRECATED_STACK_LIMIT 1000
 #endif
 
-static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
+static size_t const stackLimit_g =
+  JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
 
 namespace Json {
 
 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
 typedef std::unique_ptr<CharReader> CharReaderPtr;
 #else
-typedef std::auto_ptr<CharReader>   CharReaderPtr;
+typedef std::auto_ptr<CharReader> CharReaderPtr;
 #endif
 
 // Implementation of class Features
 // ////////////////////////////////
 
 Features::Features()
-    : allowComments_(true), strictRoot_(false),
-      allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
+  : allowComments_(true)
+  , strictRoot_(false)
+  , allowDroppedNullPlaceholders_(false)
+  , allowNumericKeys_(false)
+{
+}
 
-Features Features::all() { return Features(); }
+Features Features::all()
+{
+  return Features();
+}
 
-Features Features::strictMode() {
+Features Features::strictMode()
+{
   Features features;
   features.allowComments_ = false;
   features.strictRoot_ = true;
@@ -81,7 +95,8 @@ Features Features::strictMode() {
 // Implementation of class Reader
 // ////////////////////////////////
 
-bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
+bool Reader::containsNewLine(Reader::Location begin, Reader::Location end)
+{
   for (; begin < end; ++begin)
     if (*begin == '\n' || *begin == '\r')
       return true;
@@ -92,24 +107,44 @@ bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
 // //////////////////////////////////////////////////////////////////
 
 Reader::Reader()
-    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
-      lastValue_(), commentsBefore_(), features_(Features::all()),
-      collectComments_() {}
+  : errors_()
+  , document_()
+  , begin_()
+  , end_()
+  , current_()
+  , lastValueEnd_()
+  , lastValue_()
+  , commentsBefore_()
+  , features_(Features::all())
+  , collectComments_()
+{
+}
 
 Reader::Reader(const Features& features)
-    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
-      lastValue_(), commentsBefore_(), features_(features), collectComments_() {
+  : errors_()
+  , document_()
+  , begin_()
+  , end_()
+  , current_()
+  , lastValueEnd_()
+  , lastValue_()
+  , commentsBefore_()
+  , features_(features)
+  , collectComments_()
+{
 }
 
-bool
-Reader::parse(const std::string& document, Value& root, bool collectComments) {
-  document_.assign(document.begin(), document.end());
-  const char* begin = document_.c_str();
-  const char* end = begin + document_.length();
-  return parse(begin, end, root, collectComments);
+bool Reader::parse(const std::string& document, Value& root,
+                   bool collectComments)
+{
+  this->document_.assign(document.begin(), document.end());
+  const char* begin = this->document_.c_str();
+  const char* end = begin + this->document_.length();
+  return this->parse(begin, end, root, collectComments);
 }
 
-bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
+bool Reader::parse(std::istream& sin, Value& root, bool collectComments)
+{
   // std::istream_iterator<char> begin(sin);
   // std::istream_iterator<char> end;
   // Those would allow streamed input from a file, if parse() were a
@@ -119,257 +154,263 @@ bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
   // create an extra copy.
   JSONCPP_STRING doc;
   std::getline(sin, doc, (char)EOF);
-  return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
+  return this->parse(doc.data(), doc.data() + doc.size(), root,
+                     collectComments);
 }
 
-bool Reader::parse(const char* beginDoc,
-                   const char* endDoc,
-                   Value& root,
-                   bool collectComments) {
-  if (!features_.allowComments_) {
+bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
+                   bool collectComments)
+{
+  if (!this->features_.allowComments_) {
     collectComments = false;
   }
 
-  begin_ = beginDoc;
-  end_ = endDoc;
-  collectComments_ = collectComments;
-  current_ = begin_;
-  lastValueEnd_ = 0;
-  lastValue_ = 0;
-  commentsBefore_.clear();
-  errors_.clear();
-  while (!nodes_.empty())
-    nodes_.pop();
-  nodes_.push(&root);
-
-  bool successful = readValue();
+  this->begin_ = beginDoc;
+  this->end_ = endDoc;
+  this->collectComments_ = collectComments;
+  this->current_ = this->begin_;
+  this->lastValueEnd_ = 0;
+  this->lastValue_ = 0;
+  this->commentsBefore_.clear();
+  this->errors_.clear();
+  while (!this->nodes_.empty())
+    this->nodes_.pop();
+  this->nodes_.push(&root);
+
+  bool successful = this->readValue();
   Token token;
-  skipCommentTokens(token);
-  if (collectComments_ && !commentsBefore_.empty())
-    root.setComment(commentsBefore_, commentAfter);
-  if (features_.strictRoot_) {
+  this->skipCommentTokens(token);
+  if (this->collectComments_ && !this->commentsBefore_.empty())
+    root.setComment(this->commentsBefore_, commentAfter);
+  if (this->features_.strictRoot_) {
     if (!root.isArray() && !root.isObject()) {
-      // Set error location to start of doc, ideally should be first token found
-      // in doc
+      // Set error location to start of doc, ideally should be first token
+      // found in doc
       token.type_ = tokenError;
       token.start_ = beginDoc;
       token.end_ = endDoc;
-      addError(
-          "A valid JSON document must be either an array or an object value.",
-          token);
+      this->addError(
+        "A valid JSON document must be either an array or an object value.",
+        token);
       return false;
     }
   }
   return successful;
 }
 
-bool Reader::readValue() {
+bool Reader::readValue()
+{
   // readValue() may call itself only if it calls readObject() or ReadArray().
-  // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). 
-  // parse() executes one nodes_.push(), so > instead of >=.
-  if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
+  // These methods execute nodes_.push() just before and nodes_.pop)() just
+  // after calling readValue(). parse() executes one nodes_.push(), so >
+  // instead of >=.
+  if (this->nodes_.size() > stackLimit_g)
+    throwRuntimeError("Exceeded stackLimit in readValue().");
 
   Token token;
-  skipCommentTokens(token);
+  this->skipCommentTokens(token);
   bool successful = true;
 
-  if (collectComments_ && !commentsBefore_.empty()) {
-    currentValue().setComment(commentsBefore_, commentBefore);
-    commentsBefore_.clear();
+  if (this->collectComments_ && !this->commentsBefore_.empty()) {
+    this->currentValue().setComment(this->commentsBefore_, commentBefore);
+    this->commentsBefore_.clear();
   }
 
   switch (token.type_) {
-  case tokenObjectBegin:
-    successful = readObject(token);
-    currentValue().setOffsetLimit(current_ - begin_);
-    break;
-  case tokenArrayBegin:
-    successful = readArray(token);
-    currentValue().setOffsetLimit(current_ - begin_);
-    break;
-  case tokenNumber:
-    successful = decodeNumber(token);
-    break;
-  case tokenString:
-    successful = decodeString(token);
-    break;
-  case tokenTrue:
-    {
-    Value v(true);
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenFalse:
-    {
-    Value v(false);
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNull:
-    {
-    Value v;
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenArraySeparator:
-  case tokenObjectEnd:
-  case tokenArrayEnd:
-    if (features_.allowDroppedNullPlaceholders_) {
-      // "Un-read" the current token and mark the current value as a null
-      // token.
-      current_--;
-      Value v;
-      currentValue().swapPayload(v);
-      currentValue().setOffsetStart(current_ - begin_ - 1);
-      currentValue().setOffsetLimit(current_ - begin_);
+    case tokenObjectBegin:
+      successful = this->readObject(token);
+      this->currentValue().setOffsetLimit(this->current_ - this->begin_);
+      break;
+    case tokenArrayBegin:
+      successful = this->readArray(token);
+      this->currentValue().setOffsetLimit(this->current_ - this->begin_);
+      break;
+    case tokenNumber:
+      successful = this->decodeNumber(token);
       break;
-    } // Else, fall through...
-  default:
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    return addError("Syntax error: value, object or array expected.", token);
+    case tokenString:
+      successful = this->decodeString(token);
+      break;
+    case tokenTrue: {
+      Value v(true);
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenFalse: {
+      Value v(false);
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenNull: {
+      Value v;
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenArraySeparator:
+    case tokenObjectEnd:
+    case tokenArrayEnd:
+      if (this->features_.allowDroppedNullPlaceholders_) {
+        // "Un-read" the current token and mark the current value as a null
+        // token.
+        this->current_--;
+        Value v;
+        this->currentValue().swapPayload(v);
+        this->currentValue().setOffsetStart(this->current_ - this->begin_ - 1);
+        this->currentValue().setOffsetLimit(this->current_ - this->begin_);
+        break;
+      } // Else, fall through...
+    default:
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+      return this->addError("Syntax error: value, object or array expected.",
+                            token);
   }
 
-  if (collectComments_) {
-    lastValueEnd_ = current_;
-    lastValue_ = &currentValue();
+  if (this->collectComments_) {
+    this->lastValueEnd_ = this->current_;
+    this->lastValue_ = &this->currentValue();
   }
 
   return successful;
 }
 
-void Reader::skipCommentTokens(Token& token) {
-  if (features_.allowComments_) {
+void Reader::skipCommentTokens(Token& token)
+{
+  if (this->features_.allowComments_) {
     do {
-      readToken(token);
+      this->readToken(token);
     } while (token.type_ == tokenComment);
   } else {
-    readToken(token);
+    this->readToken(token);
   }
 }
 
-bool Reader::readToken(Token& token) {
-  skipSpaces();
-  token.start_ = current_;
-  Char c = getNextChar();
+bool Reader::readToken(Token& token)
+{
+  this->skipSpaces();
+  token.start_ = this->current_;
+  Char c = this->getNextChar();
   bool ok = true;
   switch (c) {
-  case '{':
-    token.type_ = tokenObjectBegin;
-    break;
-  case '}':
-    token.type_ = tokenObjectEnd;
-    break;
-  case '[':
-    token.type_ = tokenArrayBegin;
-    break;
-  case ']':
-    token.type_ = tokenArrayEnd;
-    break;
-  case '"':
-    token.type_ = tokenString;
-    ok = readString();
-    break;
-  case '/':
-    token.type_ = tokenComment;
-    ok = readComment();
-    break;
-  case '0':
-  case '1':
-  case '2':
-  case '3':
-  case '4':
-  case '5':
-  case '6':
-  case '7':
-  case '8':
-  case '9':
-  case '-':
-    token.type_ = tokenNumber;
-    readNumber();
-    break;
-  case 't':
-    token.type_ = tokenTrue;
-    ok = match("rue", 3);
-    break;
-  case 'f':
-    token.type_ = tokenFalse;
-    ok = match("alse", 4);
-    break;
-  case 'n':
-    token.type_ = tokenNull;
-    ok = match("ull", 3);
-    break;
-  case ',':
-    token.type_ = tokenArraySeparator;
-    break;
-  case ':':
-    token.type_ = tokenMemberSeparator;
-    break;
-  case 0:
-    token.type_ = tokenEndOfStream;
-    break;
-  default:
-    ok = false;
-    break;
+    case '{':
+      token.type_ = tokenObjectBegin;
+      break;
+    case '}':
+      token.type_ = tokenObjectEnd;
+      break;
+    case '[':
+      token.type_ = tokenArrayBegin;
+      break;
+    case ']':
+      token.type_ = tokenArrayEnd;
+      break;
+    case '"':
+      token.type_ = tokenString;
+      ok = this->readString();
+      break;
+    case '/':
+      token.type_ = tokenComment;
+      ok = this->readComment();
+      break;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '-':
+      token.type_ = tokenNumber;
+      this->readNumber();
+      break;
+    case 't':
+      token.type_ = tokenTrue;
+      ok = this->match("rue", 3);
+      break;
+    case 'f':
+      token.type_ = tokenFalse;
+      ok = this->match("alse", 4);
+      break;
+    case 'n':
+      token.type_ = tokenNull;
+      ok = this->match("ull", 3);
+      break;
+    case ',':
+      token.type_ = tokenArraySeparator;
+      break;
+    case ':':
+      token.type_ = tokenMemberSeparator;
+      break;
+    case 0:
+      token.type_ = tokenEndOfStream;
+      break;
+    default:
+      ok = false;
+      break;
   }
   if (!ok)
     token.type_ = tokenError;
-  token.end_ = current_;
+  token.end_ = this->current_;
   return true;
 }
 
-void Reader::skipSpaces() {
-  while (current_ != end_) {
-    Char c = *current_;
+void Reader::skipSpaces()
+{
+  while (this->current_ != this->end_) {
+    Char c = *this->current_;
     if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
-      ++current_;
+      ++this->current_;
     else
       break;
   }
 }
 
-bool Reader::match(Location pattern, int patternLength) {
-  if (end_ - current_ < patternLength)
+bool Reader::match(Location pattern, int patternLength)
+{
+  if (this->end_ - this->current_ < patternLength)
     return false;
   int index = patternLength;
   while (index--)
-    if (current_[index] != pattern[index])
+    if (this->current_[index] != pattern[index])
       return false;
-  current_ += patternLength;
+  this->current_ += patternLength;
   return true;
 }
 
-bool Reader::readComment() {
-  Location commentBegin = current_ - 1;
-  Char c = getNextChar();
+bool Reader::readComment()
+{
+  Location commentBegin = this->current_ - 1;
+  Char c = this->getNextChar();
   bool successful = false;
   if (c == '*')
-    successful = readCStyleComment();
+    successful = this->readCStyleComment();
   else if (c == '/')
-    successful = readCppStyleComment();
+    successful = this->readCppStyleComment();
   if (!successful)
     return false;
 
-  if (collectComments_) {
+  if (this->collectComments_) {
     CommentPlacement placement = commentBefore;
-    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
-      if (c != '*' || !containsNewLine(commentBegin, current_))
+    if (this->lastValueEnd_ &&
+        !containsNewLine(this->lastValueEnd_, commentBegin)) {
+      if (c != '*' || !containsNewLine(commentBegin, this->current_))
         placement = commentAfterOnSameLine;
     }
 
-    addComment(commentBegin, current_, placement);
+    this->addComment(commentBegin, this->current_, placement);
   }
   return true;
 }
 
-JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
+JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin,
+                                    Reader::Location end)
+{
   JSONCPP_STRING normalized;
   normalized.reserve(static_cast<size_t>(end - begin));
   Reader::Location current = begin;
@@ -377,8 +418,8 @@ JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end
     char c = *current++;
     if (c == '\r') {
       if (current != end && *current == '\n')
-         // convert dos EOL
-         ++current;
+        // convert dos EOL
+        ++current;
       // convert Mac EOL
       normalized += '\n';
     } else {
@@ -388,36 +429,39 @@ JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end
   return normalized;
 }
 
-void
-Reader::addComment(Location begin, Location end, CommentPlacement placement) {
-  assert(collectComments_);
+void Reader::addComment(Location begin, Location end,
+                        CommentPlacement placement)
+{
+  assert(this->collectComments_);
   const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
   if (placement == commentAfterOnSameLine) {
-    assert(lastValue_ != 0);
-    lastValue_->setComment(normalized, placement);
+    assert(this->lastValue_ != 0);
+    this->lastValue_->setComment(normalized, placement);
   } else {
-    commentsBefore_ += normalized;
+    this->commentsBefore_ += normalized;
   }
 }
 
-bool Reader::readCStyleComment() {
-  while ((current_ + 1) < end_) {
-    Char c = getNextChar();
-    if (c == '*' && *current_ == '/')
+bool Reader::readCStyleComment()
+{
+  while ((this->current_ + 1) < this->end_) {
+    Char c = this->getNextChar();
+    if (c == '*' && *this->current_ == '/')
       break;
   }
-  return getNextChar() == '/';
+  return this->getNextChar() == '/';
 }
 
-bool Reader::readCppStyleComment() {
-  while (current_ != end_) {
-    Char c = getNextChar();
+bool Reader::readCppStyleComment()
+{
+  while (this->current_ != this->end_) {
+    Char c = this->getNextChar();
     if (c == '\n')
       break;
     if (c == '\r') {
       // Consume DOS EOL. It will be normalized in addComment.
-      if (current_ != end_ && *current_ == '\n')
-        getNextChar();
+      if (this->current_ != this->end_ && *this->current_ == '\n')
+        this->getNextChar();
       // Break on Moc OS 9 EOL.
       break;
     }
@@ -425,127 +469,132 @@ bool Reader::readCppStyleComment() {
   return true;
 }
 
-void Reader::readNumber() {
-  const char *p = current_;
+void Reader::readNumber()
+{
+  const char* p = this->current_;
   char c = '0'; // stopgap for already consumed character
   // integral part
   while (c >= '0' && c <= '9')
-    c = (current_ = p) < end_ ? *p++ : '\0';
+    c = (this->current_ = p) < this->end_ ? *p++ : '\0';
   // fractional part
   if (c == '.') {
-    c = (current_ = p) < end_ ? *p++ : '\0';
+    c = (this->current_ = p) < this->end_ ? *p++ : '\0';
     while (c >= '0' && c <= '9')
-      c = (current_ = p) < end_ ? *p++ : '\0';
+      c = (this->current_ = p) < this->end_ ? *p++ : '\0';
   }
   // exponential part
   if (c == 'e' || c == 'E') {
-    c = (current_ = p) < end_ ? *p++ : '\0';
+    c = (this->current_ = p) < this->end_ ? *p++ : '\0';
     if (c == '+' || c == '-')
-      c = (current_ = p) < end_ ? *p++ : '\0';
+      c = (this->current_ = p) < this->end_ ? *p++ : '\0';
     while (c >= '0' && c <= '9')
-      c = (current_ = p) < end_ ? *p++ : '\0';
+      c = (this->current_ = p) < this->end_ ? *p++ : '\0';
   }
 }
 
-bool Reader::readString() {
+bool Reader::readString()
+{
   Char c = '\0';
-  while (current_ != end_) {
-    c = getNextChar();
+  while (this->current_ != this->end_) {
+    c = this->getNextChar();
     if (c == '\\')
-      getNextChar();
+      this->getNextChar();
     else if (c == '"')
       break;
   }
   return c == '"';
 }
 
-bool Reader::readObject(Token& tokenStart) {
+bool Reader::readObject(Token& tokenStart)
+{
   Token tokenName;
   JSONCPP_STRING name;
   Value init(objectValue);
-  currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
-  while (readToken(tokenName)) {
+  this->currentValue().swapPayload(init);
+  this->currentValue().setOffsetStart(tokenStart.start_ - this->begin_);
+  while (this->readToken(tokenName)) {
     bool initialTokenOk = true;
     while (tokenName.type_ == tokenComment && initialTokenOk)
-      initialTokenOk = readToken(tokenName);
+      initialTokenOk = this->readToken(tokenName);
     if (!initialTokenOk)
       break;
     if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
       return true;
     name.clear();
     if (tokenName.type_ == tokenString) {
-      if (!decodeString(tokenName, name))
-        return recoverFromError(tokenObjectEnd);
-    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      if (!this->decodeString(tokenName, name))
+        return this->recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber &&
+               this->features_.allowNumericKeys_) {
       Value numberName;
-      if (!decodeNumber(tokenName, numberName))
-        return recoverFromError(tokenObjectEnd);
+      if (!this->decodeNumber(tokenName, numberName))
+        return this->recoverFromError(tokenObjectEnd);
       name = JSONCPP_STRING(numberName.asCString());
     } else {
       break;
     }
 
     Token colon;
-    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
-      return addErrorAndRecover(
-          "Missing ':' after object member name", colon, tokenObjectEnd);
+    if (!this->readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return this->addErrorAndRecover("Missing ':' after object member name",
+                                      colon, tokenObjectEnd);
     }
-    Value& value = currentValue()[name];
-    nodes_.push(&value);
-    bool ok = readValue();
-    nodes_.pop();
+    Value& value = this->currentValue()[name];
+    this->nodes_.push(&value);
+    bool ok = this->readValue();
+    this->nodes_.pop();
     if (!ok) // error already set
-      return recoverFromError(tokenObjectEnd);
+      return this->recoverFromError(tokenObjectEnd);
 
     Token comma;
-    if (!readToken(comma) ||
+    if (!this->readToken(comma) ||
         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
          comma.type_ != tokenComment)) {
-      return addErrorAndRecover(
-          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+      return this->addErrorAndRecover(
+        "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
     }
     bool finalizeTokenOk = true;
     while (comma.type_ == tokenComment && finalizeTokenOk)
-      finalizeTokenOk = readToken(comma);
+      finalizeTokenOk = this->readToken(comma);
     if (comma.type_ == tokenObjectEnd)
       return true;
   }
-  return addErrorAndRecover(
-      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+  return this->addErrorAndRecover("Missing '}' or object member name",
+                                  tokenName, tokenObjectEnd);
 }
 
-bool Reader::readArray(Token& tokenStart) {
+bool Reader::readArray(Token& tokenStart)
+{
   Value init(arrayValue);
-  currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
-  skipSpaces();
-  if (current_ != end_ && *current_ == ']') // empty array
+  this->currentValue().swapPayload(init);
+  this->currentValue().setOffsetStart(tokenStart.start_ - this->begin_);
+  this->skipSpaces();
+  if (this->current_ != this->end_ && *this->current_ == ']') // empty array
   {
     Token endArray;
-    readToken(endArray);
+    this->readToken(endArray);
     return true;
   }
   int index = 0;
   for (;;) {
-    Value& value = currentValue()[index++];
-    nodes_.push(&value);
-    bool ok = readValue();
-    nodes_.pop();
+    Value& value = this->currentValue()[index++];
+    this->nodes_.push(&value);
+    bool ok = this->readValue();
+    this->nodes_.pop();
     if (!ok) // error already set
-      return recoverFromError(tokenArrayEnd);
+      return this->recoverFromError(tokenArrayEnd);
 
     Token token;
     // Accept Comment after last item in the array.
-    ok = readToken(token);
+    ok = this->readToken(token);
     while (token.type_ == tokenComment && ok) {
-      ok = readToken(token);
+      ok = this->readToken(token);
     }
     bool badTokenType =
-        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+      (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
     if (!ok || badTokenType) {
-      return addErrorAndRecover(
-          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+      return this->addErrorAndRecover(
+        "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
     }
     if (token.type_ == tokenArrayEnd)
       break;
@@ -553,17 +602,19 @@ bool Reader::readArray(Token& tokenStart) {
   return true;
 }
 
-bool Reader::decodeNumber(Token& token) {
+bool Reader::decodeNumber(Token& token)
+{
   Value decoded;
-  if (!decodeNumber(token, decoded))
+  if (!this->decodeNumber(token, decoded))
     return false;
-  currentValue().swapPayload(decoded);
-  currentValue().setOffsetStart(token.start_ - begin_);
-  currentValue().setOffsetLimit(token.end_ - begin_);
+  this->currentValue().swapPayload(decoded);
+  this->currentValue().setOffsetStart(token.start_ - this->begin_);
+  this->currentValue().setOffsetLimit(token.end_ - this->begin_);
   return true;
 }
 
-bool Reader::decodeNumber(Token& token, Value& decoded) {
+bool Reader::decodeNumber(Token& token, Value& decoded)
+{
   // Attempts to parse the number as an integer. If the number is
   // larger than the maximum supported value of an integer then
   // we decode the number as a double.
@@ -571,16 +622,17 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
   bool isNegative = *current == '-';
   if (isNegative)
     ++current;
-  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
-  Value::LargestUInt maxIntegerValue =
-      isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
-                 : Value::maxLargestUInt;
+  // TODO: Help the compiler do the div and mod at compile time or get rid of
+  // them.
+  Value::LargestUInt maxIntegerValue = isNegative
+    ? Value::LargestUInt(Value::maxLargestInt) + 1
+    : Value::maxLargestUInt;
   Value::LargestUInt threshold = maxIntegerValue / 10;
   Value::LargestUInt value = 0;
   while (current < token.end_) {
     Char c = *current++;
     if (c < '0' || c > '9')
-      return decodeDouble(token, decoded);
+      return this->decodeDouble(token, decoded);
     Value::UInt digit(static_cast<Value::UInt>(c - '0'));
     if (value >= threshold) {
       // We've hit or exceeded the max value divided by 10 (rounded down). If
@@ -589,7 +641,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
       // Otherwise treat this number as a double to avoid overflow.
       if (value > threshold || current != token.end_ ||
           digit > maxIntegerValue % 10) {
-        return decodeDouble(token, decoded);
+        return this->decodeDouble(token, decoded);
       }
     }
     value = value * 10 + digit;
@@ -605,40 +657,44 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
   return true;
 }
 
-bool Reader::decodeDouble(Token& token) {
+bool Reader::decodeDouble(Token& token)
+{
   Value decoded;
-  if (!decodeDouble(token, decoded))
+  if (!this->decodeDouble(token, decoded))
     return false;
-  currentValue().swapPayload(decoded);
-  currentValue().setOffsetStart(token.start_ - begin_);
-  currentValue().setOffsetLimit(token.end_ - begin_);
+  this->currentValue().swapPayload(decoded);
+  this->currentValue().setOffsetStart(token.start_ - this->begin_);
+  this->currentValue().setOffsetLimit(token.end_ - this->begin_);
   return true;
 }
 
-bool Reader::decodeDouble(Token& token, Value& decoded) {
+bool Reader::decodeDouble(Token& token, Value& decoded)
+{
   double value = 0;
   JSONCPP_STRING buffer(token.start_, token.end_);
   JSONCPP_ISTRINGSTREAM is(buffer);
   if (!(is >> value))
-    return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
-                        "' is not a number.",
-                    token);
+    return this->addError("'" + JSONCPP_STRING(token.start_, token.end_) +
+                            "' is not a number.",
+                          token);
   decoded = value;
   return true;
 }
 
-bool Reader::decodeString(Token& token) {
+bool Reader::decodeString(Token& token)
+{
   JSONCPP_STRING decoded_string;
-  if (!decodeString(token, decoded_string))
+  if (!this->decodeString(token, decoded_string))
     return false;
   Value decoded(decoded_string);
-  currentValue().swapPayload(decoded);
-  currentValue().setOffsetStart(token.start_ - begin_);
-  currentValue().setOffsetLimit(token.end_ - begin_);
+  this->currentValue().swapPayload(decoded);
+  this->currentValue().setOffsetStart(token.start_ - this->begin_);
+  this->currentValue().setOffsetLimit(token.end_ - this->begin_);
   return true;
 }
 
-bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
+bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded)
+{
   decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
   Location current = token.start_ + 1; // skip '"'
   Location end = token.end_ - 1;       // do not include '"'
@@ -648,41 +704,43 @@ bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
       break;
     else if (c == '\\') {
       if (current == end)
-        return addError("Empty escape sequence in string", token, current);
+        return this->addError("Empty escape sequence in string", token,
+                              current);
       Char escape = *current++;
       switch (escape) {
-      case '"':
-        decoded += '"';
-        break;
-      case '/':
-        decoded += '/';
-        break;
-      case '\\':
-        decoded += '\\';
-        break;
-      case 'b':
-        decoded += '\b';
-        break;
-      case 'f':
-        decoded += '\f';
-        break;
-      case 'n':
-        decoded += '\n';
-        break;
-      case 'r':
-        decoded += '\r';
-        break;
-      case 't':
-        decoded += '\t';
-        break;
-      case 'u': {
-        unsigned int unicode;
-        if (!decodeUnicodeCodePoint(token, current, end, unicode))
-          return false;
-        decoded += codePointToUTF8(unicode);
-      } break;
-      default:
-        return addError("Bad escape sequence in string", token, current);
+        case '"':
+          decoded += '"';
+          break;
+        case '/':
+          decoded += '/';
+          break;
+        case '\\':
+          decoded += '\\';
+          break;
+        case 'b':
+          decoded += '\b';
+          break;
+        case 'f':
+          decoded += '\f';
+          break;
+        case 'n':
+          decoded += '\n';
+          break;
+        case 'r':
+          decoded += '\r';
+          break;
+        case 't':
+          decoded += '\t';
+          break;
+        case 'u': {
+          unsigned int unicode;
+          if (!this->decodeUnicodeCodePoint(token, current, end, unicode))
+            return false;
+          decoded += codePointToUTF8(unicode);
+        } break;
+        default:
+          return this->addError("Bad escape sequence in string", token,
+                                current);
       }
     } else {
       decoded += c;
@@ -691,44 +749,43 @@ bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
   return true;
 }
 
-bool Reader::decodeUnicodeCodePoint(Token& token,
-                                    Location& current,
-                                    Location end,
-                                    unsigned int& unicode) {
+bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
+                                    Location end, unsigned int& unicode)
+{
 
-  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+  if (!this->decodeUnicodeEscapeSequence(token, current, end, unicode))
     return false;
   if (unicode >= 0xD800 && unicode <= 0xDBFF) {
     // surrogate pairs
     if (end - current < 6)
-      return addError(
-          "additional six characters expected to parse unicode surrogate pair.",
-          token,
-          current);
+      return this->addError(
+        "additional six characters expected to parse unicode surrogate pair.",
+        token, current);
     unsigned int surrogatePair;
     if (*(current++) == '\\' && *(current++) == 'u') {
-      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
-        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      if (this->decodeUnicodeEscapeSequence(token, current, end,
+                                            surrogatePair)) {
+        unicode =
+          0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
       } else
         return false;
     } else
-      return addError("expecting another \\u token to begin the second half of "
-                      "a unicode surrogate pair",
-                      token,
-                      current);
+      return this->addError(
+        "expecting another \\u token to begin the second half of "
+        "a unicode surrogate pair",
+        token, current);
   }
   return true;
 }
 
-bool Reader::decodeUnicodeEscapeSequence(Token& token,
-                                         Location& current,
+bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
                                          Location end,
-                                         unsigned int& ret_unicode) {
+                                         unsigned int& ret_unicode)
+{
   if (end - current < 4)
-    return addError(
-        "Bad unicode escape sequence in string: four digits expected.",
-        token,
-        current);
+    return this->addError(
+      "Bad unicode escape sequence in string: four digits expected.", token,
+      current);
   int unicode = 0;
   for (int index = 0; index < 4; ++index) {
     Char c = *current++;
@@ -740,60 +797,65 @@ bool Reader::decodeUnicodeEscapeSequence(Token& token,
     else if (c >= 'A' && c <= 'F')
       unicode += c - 'A' + 10;
     else
-      return addError(
-          "Bad unicode escape sequence in string: hexadecimal digit expected.",
-          token,
-          current);
+      return this->addError(
+        "Bad unicode escape sequence in string: hexadecimal digit expected.",
+        token, current);
   }
   ret_unicode = static_cast<unsigned int>(unicode);
   return true;
 }
 
-bool
-Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
+bool Reader::addError(const JSONCPP_STRING& message, Token& token,
+                      Location extra)
+{
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
   info.extra_ = extra;
-  errors_.push_back(info);
+  this->errors_.push_back(info);
   return false;
 }
 
-bool Reader::recoverFromError(TokenType skipUntilToken) {
-  size_t const errorCount = errors_.size();
+bool Reader::recoverFromError(TokenType skipUntilToken)
+{
+  size_t const errorCount = this->errors_.size();
   Token skip;
   for (;;) {
-    if (!readToken(skip))
-      errors_.resize(errorCount); // discard errors caused by recovery
+    if (!this->readToken(skip))
+      this->errors_.resize(errorCount); // discard errors caused by recovery
     if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
       break;
   }
-  errors_.resize(errorCount);
+  this->errors_.resize(errorCount);
   return false;
 }
 
-bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,
-                                Token& token,
-                                TokenType skipUntilToken) {
-  addError(message, token);
-  return recoverFromError(skipUntilToken);
+bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, Token& token,
+                                TokenType skipUntilToken)
+{
+  this->addError(message, token);
+  return this->recoverFromError(skipUntilToken);
 }
 
-Value& Reader::currentValue() { return *(nodes_.top()); }
+Value& Reader::currentValue()
+{
+  return *(this->nodes_.top());
+}
 
-Reader::Char Reader::getNextChar() {
-  if (current_ == end_)
+Reader::Char Reader::getNextChar()
+{
+  if (this->current_ == this->end_)
     return 0;
-  return *current_++;
+  return *this->current_++;
 }
 
-void Reader::getLocationLineAndColumn(Location location,
-                                      int& line,
-                                      int& column) const {
-  Location current = begin_;
+void Reader::getLocationLineAndColumn(Location location, int& line,
+                                      int& column) const
+{
+  Location current = this->begin_;
   Location lastLineStart = current;
   line = 0;
-  while (current < location && current != end_) {
+  while (current < location && current != this->end_) {
     Char c = *current++;
     if (c == '\r') {
       if (*current == '\n')
@@ -810,91 +872,96 @@ void Reader::getLocationLineAndColumn(Location location,
   ++line;
 }
 
-JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {
+JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const
+{
   int line, column;
-  getLocationLineAndColumn(location, line, column);
+  this->getLocationLineAndColumn(location, line, column);
   char buffer[18 + 16 + 16 + 1];
   snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
   return buffer;
 }
 
 // Deprecated. Preserved for backward compatibility
-JSONCPP_STRING Reader::getFormatedErrorMessages() const {
-  return getFormattedErrorMessages();
+JSONCPP_STRING Reader::getFormatedErrorMessages() const
+{
+  return this->getFormattedErrorMessages();
 }
 
-JSONCPP_STRING Reader::getFormattedErrorMessages() const {
+JSONCPP_STRING Reader::getFormattedErrorMessages() const
+{
   JSONCPP_STRING formattedMessage;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
+  for (Errors::const_iterator itError = this->errors_.begin();
+       itError != this->errors_.end(); ++itError) {
     const ErrorInfo& error = *itError;
     formattedMessage +=
-        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+      "* " + this->getLocationLineAndColumn(error.token_.start_) + "\n";
     formattedMessage += "  " + error.message_ + "\n";
     if (error.extra_)
-      formattedMessage +=
-          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+      formattedMessage += "See " +
+        this->getLocationLineAndColumn(error.extra_) + " for detail.\n";
   }
   return formattedMessage;
 }
 
-std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
+std::vector<Reader::StructuredError> Reader::getStructuredErrors() const
+{
   std::vector<Reader::StructuredError> allErrors;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
+  for (Errors::const_iterator itError = this->errors_.begin();
+       itError != this->errors_.end(); ++itError) {
     const ErrorInfo& error = *itError;
     Reader::StructuredError structured;
-    structured.offset_start = error.token_.start_ - begin_;
-    structured.offset_limit = error.token_.end_ - begin_;
+    structured.offset_start = error.token_.start_ - this->begin_;
+    structured.offset_limit = error.token_.end_ - this->begin_;
     structured.message = error.message_;
     allErrors.push_back(structured);
   }
   return allErrors;
 }
 
-bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {
-  ptrdiff_t const length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length)
+bool Reader::pushError(const Value& value, const JSONCPP_STRING& message)
+{
+  ptrdiff_t const length = this->end_ - this->begin_;
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
     return false;
   Token token;
   token.type_ = tokenError;
-  token.start_ = begin_ + value.getOffsetStart();
-  token.end_ = end_ + value.getOffsetLimit();
+  token.start_ = this->begin_ + value.getOffsetStart();
+  token.end_ = this->end_ + value.getOffsetLimit();
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
   info.extra_ = 0;
-  errors_.push_back(info);
+  this->errors_.push_back(info);
   return true;
 }
 
-bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
-  ptrdiff_t const length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length
-    || extra.getOffsetLimit() > length)
+bool Reader::pushError(const Value& value, const JSONCPP_STRING& message,
+                       const Value& extra)
+{
+  ptrdiff_t const length = this->end_ - this->begin_;
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
+      extra.getOffsetLimit() > length)
     return false;
   Token token;
   token.type_ = tokenError;
-  token.start_ = begin_ + value.getOffsetStart();
-  token.end_ = begin_ + value.getOffsetLimit();
+  token.start_ = this->begin_ + value.getOffsetStart();
+  token.end_ = this->begin_ + value.getOffsetLimit();
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
-  info.extra_ = begin_ + extra.getOffsetStart();
-  errors_.push_back(info);
+  info.extra_ = this->begin_ + extra.getOffsetStart();
+  this->errors_.push_back(info);
   return true;
 }
 
-bool Reader::good() const {
-  return !errors_.size();
+bool Reader::good() const
+{
+  return !this->errors_.size();
 }
 
 // exact copy of Features
-class OurFeatures {
+class OurFeatures
+{
 public:
   static OurFeatures all();
   bool allowComments_;
@@ -906,43 +973,48 @@ public:
   bool rejectDupKeys_;
   bool allowSpecialFloats_;
   int stackLimit_;
-};  // OurFeatures
+}; // OurFeatures
 
 // exact copy of Implementation of class Features
 // ////////////////////////////////
 
-OurFeatures OurFeatures::all() { return OurFeatures(); }
+OurFeatures OurFeatures::all()
+{
+  return OurFeatures();
+}
 
 // Implementation of class Reader
 // ////////////////////////////////
 
 // exact copy of Reader, renamed to OurReader
-class OurReader {
+class OurReader
+{
 public:
   typedef char Char;
   typedef const Char* Location;
-  struct StructuredError {
+  struct StructuredError
+  {
     ptrdiff_t offset_start;
     ptrdiff_t offset_limit;
     JSONCPP_STRING message;
   };
 
   OurReader(OurFeatures const& features);
-  bool parse(const char* beginDoc,
-             const char* endDoc,
-             Value& root,
+  bool parse(const char* beginDoc, const char* endDoc, Value& root,
              bool collectComments = true);
   JSONCPP_STRING getFormattedErrorMessages() const;
   std::vector<StructuredError> getStructuredErrors() const;
   bool pushError(const Value& value, const JSONCPP_STRING& message);
-  bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
+  bool pushError(const Value& value, const JSONCPP_STRING& message,
+                 const Value& extra);
   bool good() const;
 
 private:
-  OurReader(OurReader const&);  // no impl
-  void operator=(OurReader const&);  // no impl
+  OurReader(OurReader const&);      // no impl
+  void operator=(OurReader const&); // no impl
 
-  enum TokenType {
+  enum TokenType
+  {
     tokenEndOfStream = 0,
     tokenObjectBegin,
     tokenObjectEnd,
@@ -962,14 +1034,16 @@ private:
     tokenError
   };
 
-  class Token {
+  class Token
+  {
   public:
     TokenType type_;
     Location start_;
     Location end_;
   };
 
-  class ErrorInfo {
+  class ErrorInfo
+  {
   public:
     Token token_;
     JSONCPP_STRING message_;
@@ -996,24 +1070,20 @@ private:
   bool decodeString(Token& token, JSONCPP_STRING& decoded);
   bool decodeDouble(Token& token);
   bool decodeDouble(Token& token, Value& decoded);
-  bool decodeUnicodeCodePoint(Token& token,
-                              Location& current,
-                              Location end,
+  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
                               unsigned int& unicode);
-  bool decodeUnicodeEscapeSequence(Token& token,
-                                   Location& current,
-                                   Location end,
-                                   unsigned int& unicode);
-  bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
+  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
+                                   Location end, unsigned int& unicode);
+  bool addError(const JSONCPP_STRING& message, Token& token,
+                Location extra = 0);
   bool recoverFromError(TokenType skipUntilToken);
-  bool addErrorAndRecover(const JSONCPP_STRING& message,
-                          Token& token,
+  bool addErrorAndRecover(const JSONCPP_STRING& message, Token& token,
                           TokenType skipUntilToken);
   void skipUntilSpace();
   Value& currentValue();
   Char getNextChar();
-  void
-  getLocationLineAndColumn(Location location, int& line, int& column) const;
+  void getLocationLineAndColumn(Location location, int& line,
+                                int& column) const;
   JSONCPP_STRING getLocationLineAndColumn(Location location) const;
   void addComment(Location begin, Location end, CommentPlacement placement);
   void skipCommentTokens(Token& token);
@@ -1034,11 +1104,13 @@ private:
 
   OurFeatures const features_;
   bool collectComments_;
-};  // OurReader
+}; // OurReader
 
 // complete copy of Read impl, for OurReader
 
-bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) {
+bool OurReader::containsNewLine(OurReader::Location begin,
+                                OurReader::Location end)
+{
   for (; begin < end; ++begin)
     if (*begin == '\n' || *begin == '\r')
       return true;
@@ -1046,315 +1118,322 @@ bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location e
 }
 
 OurReader::OurReader(OurFeatures const& features)
-    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
-      lastValue_(), commentsBefore_(),
-      features_(features), collectComments_() {
+  : errors_()
+  , document_()
+  , begin_()
+  , end_()
+  , current_()
+  , lastValueEnd_()
+  , lastValue_()
+  , commentsBefore_()
+  , features_(features)
+  , collectComments_()
+{
 }
 
-bool OurReader::parse(const char* beginDoc,
-                   const char* endDoc,
-                   Value& root,
-                   bool collectComments) {
-  if (!features_.allowComments_) {
+bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
+                      bool collectComments)
+{
+  if (!this->features_.allowComments_) {
     collectComments = false;
   }
 
-  begin_ = beginDoc;
-  end_ = endDoc;
-  collectComments_ = collectComments;
-  current_ = begin_;
-  lastValueEnd_ = 0;
-  lastValue_ = 0;
-  commentsBefore_.clear();
-  errors_.clear();
-  while (!nodes_.empty())
-    nodes_.pop();
-  nodes_.push(&root);
-
-  bool successful = readValue();
+  this->begin_ = beginDoc;
+  this->end_ = endDoc;
+  this->collectComments_ = collectComments;
+  this->current_ = this->begin_;
+  this->lastValueEnd_ = 0;
+  this->lastValue_ = 0;
+  this->commentsBefore_.clear();
+  this->errors_.clear();
+  while (!this->nodes_.empty())
+    this->nodes_.pop();
+  this->nodes_.push(&root);
+
+  bool successful = this->readValue();
   Token token;
-  skipCommentTokens(token);
-  if (features_.failIfExtra_) {
-    if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
-      addError("Extra non-whitespace after JSON value.", token);
+  this->skipCommentTokens(token);
+  if (this->features_.failIfExtra_) {
+    if ((this->features_.strictRoot_ || token.type_ != tokenError) &&
+        token.type_ != tokenEndOfStream) {
+      this->addError("Extra non-whitespace after JSON value.", token);
       return false;
     }
   }
-  if (collectComments_ && !commentsBefore_.empty())
-    root.setComment(commentsBefore_, commentAfter);
-  if (features_.strictRoot_) {
+  if (this->collectComments_ && !this->commentsBefore_.empty())
+    root.setComment(this->commentsBefore_, commentAfter);
+  if (this->features_.strictRoot_) {
     if (!root.isArray() && !root.isObject()) {
-      // Set error location to start of doc, ideally should be first token found
-      // in doc
+      // Set error location to start of doc, ideally should be first token
+      // found in doc
       token.type_ = tokenError;
       token.start_ = beginDoc;
       token.end_ = endDoc;
-      addError(
-          "A valid JSON document must be either an array or an object value.",
-          token);
+      this->addError(
+        "A valid JSON document must be either an array or an object value.",
+        token);
       return false;
     }
   }
   return successful;
 }
 
-bool OurReader::readValue() {
+bool OurReader::readValue()
+{
   //  To preserve the old behaviour we cast size_t to int.
-  if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
+  if (static_cast<int>(this->nodes_.size()) > this->features_.stackLimit_)
+    throwRuntimeError("Exceeded stackLimit in readValue().");
   Token token;
-  skipCommentTokens(token);
+  this->skipCommentTokens(token);
   bool successful = true;
 
-  if (collectComments_ && !commentsBefore_.empty()) {
-    currentValue().setComment(commentsBefore_, commentBefore);
-    commentsBefore_.clear();
+  if (this->collectComments_ && !this->commentsBefore_.empty()) {
+    this->currentValue().setComment(this->commentsBefore_, commentBefore);
+    this->commentsBefore_.clear();
   }
 
   switch (token.type_) {
-  case tokenObjectBegin:
-    successful = readObject(token);
-    currentValue().setOffsetLimit(current_ - begin_);
-    break;
-  case tokenArrayBegin:
-    successful = readArray(token);
-    currentValue().setOffsetLimit(current_ - begin_);
-    break;
-  case tokenNumber:
-    successful = decodeNumber(token);
-    break;
-  case tokenString:
-    successful = decodeString(token);
-    break;
-  case tokenTrue:
-    {
-    Value v(true);
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenFalse:
-    {
-    Value v(false);
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNull:
-    {
-    Value v;
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNaN:
-    {
-    Value v(std::numeric_limits<double>::quiet_NaN());
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenPosInf:
-    {
-    Value v(std::numeric_limits<double>::infinity());
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenNegInf:
-    {
-    Value v(-std::numeric_limits<double>::infinity());
-    currentValue().swapPayload(v);
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    }
-    break;
-  case tokenArraySeparator:
-  case tokenObjectEnd:
-  case tokenArrayEnd:
-    if (features_.allowDroppedNullPlaceholders_) {
-      // "Un-read" the current token and mark the current value as a null
-      // token.
-      current_--;
-      Value v;
-      currentValue().swapPayload(v);
-      currentValue().setOffsetStart(current_ - begin_ - 1);
-      currentValue().setOffsetLimit(current_ - begin_);
+    case tokenObjectBegin:
+      successful = this->readObject(token);
+      this->currentValue().setOffsetLimit(this->current_ - this->begin_);
+      break;
+    case tokenArrayBegin:
+      successful = this->readArray(token);
+      this->currentValue().setOffsetLimit(this->current_ - this->begin_);
+      break;
+    case tokenNumber:
+      successful = this->decodeNumber(token);
       break;
-    } // else, fall through ...
-  default:
-    currentValue().setOffsetStart(token.start_ - begin_);
-    currentValue().setOffsetLimit(token.end_ - begin_);
-    return addError("Syntax error: value, object or array expected.", token);
+    case tokenString:
+      successful = this->decodeString(token);
+      break;
+    case tokenTrue: {
+      Value v(true);
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenFalse: {
+      Value v(false);
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenNull: {
+      Value v;
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenNaN: {
+      Value v(std::numeric_limits<double>::quiet_NaN());
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenPosInf: {
+      Value v(std::numeric_limits<double>::infinity());
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenNegInf: {
+      Value v(-std::numeric_limits<double>::infinity());
+      this->currentValue().swapPayload(v);
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+    } break;
+    case tokenArraySeparator:
+    case tokenObjectEnd:
+    case tokenArrayEnd:
+      if (this->features_.allowDroppedNullPlaceholders_) {
+        // "Un-read" the current token and mark the current value as a null
+        // token.
+        this->current_--;
+        Value v;
+        this->currentValue().swapPayload(v);
+        this->currentValue().setOffsetStart(this->current_ - this->begin_ - 1);
+        this->currentValue().setOffsetLimit(this->current_ - this->begin_);
+        break;
+      } // else, fall through ...
+    default:
+      this->currentValue().setOffsetStart(token.start_ - this->begin_);
+      this->currentValue().setOffsetLimit(token.end_ - this->begin_);
+      return this->addError("Syntax error: value, object or array expected.",
+                            token);
   }
 
-  if (collectComments_) {
-    lastValueEnd_ = current_;
-    lastValue_ = &currentValue();
+  if (this->collectComments_) {
+    this->lastValueEnd_ = this->current_;
+    this->lastValue_ = &this->currentValue();
   }
 
   return successful;
 }
 
-void OurReader::skipCommentTokens(Token& token) {
-  if (features_.allowComments_) {
+void OurReader::skipCommentTokens(Token& token)
+{
+  if (this->features_.allowComments_) {
     do {
-      readToken(token);
+      this->readToken(token);
     } while (token.type_ == tokenComment);
   } else {
-    readToken(token);
+    this->readToken(token);
   }
 }
 
-bool OurReader::readToken(Token& token) {
-  skipSpaces();
-  token.start_ = current_;
-  Char c = getNextChar();
+bool OurReader::readToken(Token& token)
+{
+  this->skipSpaces();
+  token.start_ = this->current_;
+  Char c = this->getNextChar();
   bool ok = true;
   switch (c) {
-  case '{':
-    token.type_ = tokenObjectBegin;
-    break;
-  case '}':
-    token.type_ = tokenObjectEnd;
-    break;
-  case '[':
-    token.type_ = tokenArrayBegin;
-    break;
-  case ']':
-    token.type_ = tokenArrayEnd;
-    break;
-  case '"':
-    token.type_ = tokenString;
-    ok = readString();
-    break;
-  case '\'':
-    if (features_.allowSingleQuotes_) {
-    token.type_ = tokenString;
-    ok = readStringSingleQuote();
-    break;
-    } // else continue
-  case '/':
-    token.type_ = tokenComment;
-    ok = readComment();
-    break;
-  case '0':
-  case '1':
-  case '2':
-  case '3':
-  case '4':
-  case '5':
-  case '6':
-  case '7':
-  case '8':
-  case '9':
-    token.type_ = tokenNumber;
-    readNumber(false);
-    break;
-  case '-':
-    if (readNumber(true)) {
+    case '{':
+      token.type_ = tokenObjectBegin;
+      break;
+    case '}':
+      token.type_ = tokenObjectEnd;
+      break;
+    case '[':
+      token.type_ = tokenArrayBegin;
+      break;
+    case ']':
+      token.type_ = tokenArrayEnd;
+      break;
+    case '"':
+      token.type_ = tokenString;
+      ok = this->readString();
+      break;
+    case '\'':
+      if (this->features_.allowSingleQuotes_) {
+        token.type_ = tokenString;
+        ok = this->readStringSingleQuote();
+        break;
+      } // else continue
+    case '/':
+      token.type_ = tokenComment;
+      ok = this->readComment();
+      break;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
       token.type_ = tokenNumber;
-    } else {
-      token.type_ = tokenNegInf;
-      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
-    }
-    break;
-  case 't':
-    token.type_ = tokenTrue;
-    ok = match("rue", 3);
-    break;
-  case 'f':
-    token.type_ = tokenFalse;
-    ok = match("alse", 4);
-    break;
-  case 'n':
-    token.type_ = tokenNull;
-    ok = match("ull", 3);
-    break;
-  case 'N':
-    if (features_.allowSpecialFloats_) {
-      token.type_ = tokenNaN;
-      ok = match("aN", 2);
-    } else {
-      ok = false;
-    }
-    break;
-  case 'I':
-    if (features_.allowSpecialFloats_) {
-      token.type_ = tokenPosInf;
-      ok = match("nfinity", 7);
-    } else {
+      this->readNumber(false);
+      break;
+    case '-':
+      if (this->readNumber(true)) {
+        token.type_ = tokenNumber;
+      } else {
+        token.type_ = tokenNegInf;
+        ok = this->features_.allowSpecialFloats_ && this->match("nfinity", 7);
+      }
+      break;
+    case 't':
+      token.type_ = tokenTrue;
+      ok = this->match("rue", 3);
+      break;
+    case 'f':
+      token.type_ = tokenFalse;
+      ok = this->match("alse", 4);
+      break;
+    case 'n':
+      token.type_ = tokenNull;
+      ok = this->match("ull", 3);
+      break;
+    case 'N':
+      if (this->features_.allowSpecialFloats_) {
+        token.type_ = tokenNaN;
+        ok = this->match("aN", 2);
+      } else {
+        ok = false;
+      }
+      break;
+    case 'I':
+      if (this->features_.allowSpecialFloats_) {
+        token.type_ = tokenPosInf;
+        ok = this->match("nfinity", 7);
+      } else {
+        ok = false;
+      }
+      break;
+    case ',':
+      token.type_ = tokenArraySeparator;
+      break;
+    case ':':
+      token.type_ = tokenMemberSeparator;
+      break;
+    case 0:
+      token.type_ = tokenEndOfStream;
+      break;
+    default:
       ok = false;
-    }
-    break;
-  case ',':
-    token.type_ = tokenArraySeparator;
-    break;
-  case ':':
-    token.type_ = tokenMemberSeparator;
-    break;
-  case 0:
-    token.type_ = tokenEndOfStream;
-    break;
-  default:
-    ok = false;
-    break;
+      break;
   }
   if (!ok)
     token.type_ = tokenError;
-  token.end_ = current_;
+  token.end_ = this->current_;
   return true;
 }
 
-void OurReader::skipSpaces() {
-  while (current_ != end_) {
-    Char c = *current_;
+void OurReader::skipSpaces()
+{
+  while (this->current_ != this->end_) {
+    Char c = *this->current_;
     if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
-      ++current_;
+      ++this->current_;
     else
       break;
   }
 }
 
-bool OurReader::match(Location pattern, int patternLength) {
-  if (end_ - current_ < patternLength)
+bool OurReader::match(Location pattern, int patternLength)
+{
+  if (this->end_ - this->current_ < patternLength)
     return false;
   int index = patternLength;
   while (index--)
-    if (current_[index] != pattern[index])
+    if (this->current_[index] != pattern[index])
       return false;
-  current_ += patternLength;
+  this->current_ += patternLength;
   return true;
 }
 
-bool OurReader::readComment() {
-  Location commentBegin = current_ - 1;
-  Char c = getNextChar();
+bool OurReader::readComment()
+{
+  Location commentBegin = this->current_ - 1;
+  Char c = this->getNextChar();
   bool successful = false;
   if (c == '*')
-    successful = readCStyleComment();
+    successful = this->readCStyleComment();
   else if (c == '/')
-    successful = readCppStyleComment();
+    successful = this->readCppStyleComment();
   if (!successful)
     return false;
 
-  if (collectComments_) {
+  if (this->collectComments_) {
     CommentPlacement placement = commentBefore;
-    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
-      if (c != '*' || !containsNewLine(commentBegin, current_))
+    if (this->lastValueEnd_ &&
+        !containsNewLine(this->lastValueEnd_, commentBegin)) {
+      if (c != '*' || !containsNewLine(commentBegin, this->current_))
         placement = commentAfterOnSameLine;
     }
 
-    addComment(commentBegin, current_, placement);
+    this->addComment(commentBegin, this->current_, placement);
   }
   return true;
 }
 
-JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) {
+JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin,
+                                       OurReader::Location end)
+{
   JSONCPP_STRING normalized;
   normalized.reserve(static_cast<size_t>(end - begin));
   OurReader::Location current = begin;
@@ -1362,8 +1441,8 @@ JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Loc
     char c = *current++;
     if (c == '\r') {
       if (current != end && *current == '\n')
-         // convert dos EOL
-         ++current;
+        // convert dos EOL
+        ++current;
       // convert Mac EOL
       normalized += '\n';
     } else {
@@ -1373,36 +1452,39 @@ JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Loc
   return normalized;
 }
 
-void
-OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
-  assert(collectComments_);
+void OurReader::addComment(Location begin, Location end,
+                           CommentPlacement placement)
+{
+  assert(this->collectComments_);
   const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
   if (placement == commentAfterOnSameLine) {
-    assert(lastValue_ != 0);
-    lastValue_->setComment(normalized, placement);
+    assert(this->lastValue_ != 0);
+    this->lastValue_->setComment(normalized, placement);
   } else {
-    commentsBefore_ += normalized;
+    this->commentsBefore_ += normalized;
   }
 }
 
-bool OurReader::readCStyleComment() {
-  while ((current_ + 1) < end_) {
-    Char c = getNextChar();
-    if (c == '*' && *current_ == '/')
+bool OurReader::readCStyleComment()
+{
+  while ((this->current_ + 1) < this->end_) {
+    Char c = this->getNextChar();
+    if (c == '*' && *this->current_ == '/')
       break;
   }
-  return getNextChar() == '/';
+  return this->getNextChar() == '/';
 }
 
-bool OurReader::readCppStyleComment() {
-  while (current_ != end_) {
-    Char c = getNextChar();
+bool OurReader::readCppStyleComment()
+{
+  while (this->current_ != this->end_) {
+    Char c = this->getNextChar();
     if (c == '\n')
       break;
     if (c == '\r') {
       // Consume DOS EOL. It will be normalized in addComment.
-      if (current_ != end_ && *current_ == '\n')
-        getNextChar();
+      if (this->current_ != this->end_ && *this->current_ == '\n')
+        this->getNextChar();
       // Break on Moc OS 9 EOL.
       break;
     }
@@ -1410,150 +1492,156 @@ bool OurReader::readCppStyleComment() {
   return true;
 }
 
-bool OurReader::readNumber(bool checkInf) {
-  const char *p = current_;
-  if (checkInf && p != end_ && *p == 'I') {
-    current_ = ++p;
+bool OurReader::readNumber(bool checkInf)
+{
+  const char* p = this->current_;
+  if (checkInf && p != this->end_ && *p == 'I') {
+    this->current_ = ++p;
     return false;
   }
   char c = '0'; // stopgap for already consumed character
   // integral part
   while (c >= '0' && c <= '9')
-    c = (current_ = p) < end_ ? *p++ : '\0';
+    c = (this->current_ = p) < this->end_ ? *p++ : '\0';
   // fractional part
   if (c == '.') {
-    c = (current_ = p) < end_ ? *p++ : '\0';
+    c = (this->current_ = p) < this->end_ ? *p++ : '\0';
     while (c >= '0' && c <= '9')
-      c = (current_ = p) < end_ ? *p++ : '\0';
+      c = (this->current_ = p) < this->end_ ? *p++ : '\0';
   }
   // exponential part
   if (c == 'e' || c == 'E') {
-    c = (current_ = p) < end_ ? *p++ : '\0';
+    c = (this->current_ = p) < this->end_ ? *p++ : '\0';
     if (c == '+' || c == '-')
-      c = (current_ = p) < end_ ? *p++ : '\0';
+      c = (this->current_ = p) < this->end_ ? *p++ : '\0';
     while (c >= '0' && c <= '9')
-      c = (current_ = p) < end_ ? *p++ : '\0';
+      c = (this->current_ = p) < this->end_ ? *p++ : '\0';
   }
   return true;
 }
-bool OurReader::readString() {
+bool OurReader::readString()
+{
   Char c = 0;
-  while (current_ != end_) {
-    c = getNextChar();
+  while (this->current_ != this->end_) {
+    c = this->getNextChar();
     if (c == '\\')
-      getNextChar();
+      this->getNextChar();
     else if (c == '"')
       break;
   }
   return c == '"';
 }
 
-
-bool OurReader::readStringSingleQuote() {
+bool OurReader::readStringSingleQuote()
+{
   Char c = 0;
-  while (current_ != end_) {
-    c = getNextChar();
+  while (this->current_ != this->end_) {
+    c = this->getNextChar();
     if (c == '\\')
-      getNextChar();
+      this->getNextChar();
     else if (c == '\'')
       break;
   }
   return c == '\'';
 }
 
-bool OurReader::readObject(Token& tokenStart) {
+bool OurReader::readObject(Token& tokenStart)
+{
   Token tokenName;
   JSONCPP_STRING name;
   Value init(objectValue);
-  currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
-  while (readToken(tokenName)) {
+  this->currentValue().swapPayload(init);
+  this->currentValue().setOffsetStart(tokenStart.start_ - this->begin_);
+  while (this->readToken(tokenName)) {
     bool initialTokenOk = true;
     while (tokenName.type_ == tokenComment && initialTokenOk)
-      initialTokenOk = readToken(tokenName);
+      initialTokenOk = this->readToken(tokenName);
     if (!initialTokenOk)
       break;
     if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
       return true;
     name.clear();
     if (tokenName.type_ == tokenString) {
-      if (!decodeString(tokenName, name))
-        return recoverFromError(tokenObjectEnd);
-    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      if (!this->decodeString(tokenName, name))
+        return this->recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber &&
+               this->features_.allowNumericKeys_) {
       Value numberName;
-      if (!decodeNumber(tokenName, numberName))
-        return recoverFromError(tokenObjectEnd);
+      if (!this->decodeNumber(tokenName, numberName))
+        return this->recoverFromError(tokenObjectEnd);
       name = numberName.asString();
     } else {
       break;
     }
 
     Token colon;
-    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
-      return addErrorAndRecover(
-          "Missing ':' after object member name", colon, tokenObjectEnd);
+    if (!this->readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return this->addErrorAndRecover("Missing ':' after object member name",
+                                      colon, tokenObjectEnd);
     }
-    if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
-    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
+    if (name.length() >= (1U << 30))
+      throwRuntimeError("keylength >= 2^30");
+    if (this->features_.rejectDupKeys_ &&
+        this->currentValue().isMember(name)) {
       JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
-      return addErrorAndRecover(
-          msg, tokenName, tokenObjectEnd);
+      return this->addErrorAndRecover(msg, tokenName, tokenObjectEnd);
     }
-    Value& value = currentValue()[name];
-    nodes_.push(&value);
-    bool ok = readValue();
-    nodes_.pop();
+    Value& value = this->currentValue()[name];
+    this->nodes_.push(&value);
+    bool ok = this->readValue();
+    this->nodes_.pop();
     if (!ok) // error already set
-      return recoverFromError(tokenObjectEnd);
+      return this->recoverFromError(tokenObjectEnd);
 
     Token comma;
-    if (!readToken(comma) ||
+    if (!this->readToken(comma) ||
         (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
          comma.type_ != tokenComment)) {
-      return addErrorAndRecover(
-          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+      return this->addErrorAndRecover(
+        "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
     }
     bool finalizeTokenOk = true;
     while (comma.type_ == tokenComment && finalizeTokenOk)
-      finalizeTokenOk = readToken(comma);
+      finalizeTokenOk = this->readToken(comma);
     if (comma.type_ == tokenObjectEnd)
       return true;
   }
-  return addErrorAndRecover(
-      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+  return this->addErrorAndRecover("Missing '}' or object member name",
+                                  tokenName, tokenObjectEnd);
 }
 
-bool OurReader::readArray(Token& tokenStart) {
+bool OurReader::readArray(Token& tokenStart)
+{
   Value init(arrayValue);
-  currentValue().swapPayload(init);
-  currentValue().setOffsetStart(tokenStart.start_ - begin_);
-  skipSpaces();
-  if (current_ != end_ && *current_ == ']') // empty array
+  this->currentValue().swapPayload(init);
+  this->currentValue().setOffsetStart(tokenStart.start_ - this->begin_);
+  this->skipSpaces();
+  if (this->current_ != this->end_ && *this->current_ == ']') // empty array
   {
     Token endArray;
-    readToken(endArray);
+    this->readToken(endArray);
     return true;
   }
   int index = 0;
   for (;;) {
-    Value& value = currentValue()[index++];
-    nodes_.push(&value);
-    bool ok = readValue();
-    nodes_.pop();
+    Value& value = this->currentValue()[index++];
+    this->nodes_.push(&value);
+    bool ok = this->readValue();
+    this->nodes_.pop();
     if (!ok) // error already set
-      return recoverFromError(tokenArrayEnd);
+      return this->recoverFromError(tokenArrayEnd);
 
     Token token;
     // Accept Comment after last item in the array.
-    ok = readToken(token);
+    ok = this->readToken(token);
     while (token.type_ == tokenComment && ok) {
-      ok = readToken(token);
+      ok = this->readToken(token);
     }
     bool badTokenType =
-        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+      (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
     if (!ok || badTokenType) {
-      return addErrorAndRecover(
-          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+      return this->addErrorAndRecover(
+        "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
     }
     if (token.type_ == tokenArrayEnd)
       break;
@@ -1561,17 +1649,19 @@ bool OurReader::readArray(Token& tokenStart) {
   return true;
 }
 
-bool OurReader::decodeNumber(Token& token) {
+bool OurReader::decodeNumber(Token& token)
+{
   Value decoded;
-  if (!decodeNumber(token, decoded))
+  if (!this->decodeNumber(token, decoded))
     return false;
-  currentValue().swapPayload(decoded);
-  currentValue().setOffsetStart(token.start_ - begin_);
-  currentValue().setOffsetLimit(token.end_ - begin_);
+  this->currentValue().swapPayload(decoded);
+  this->currentValue().setOffsetStart(token.start_ - this->begin_);
+  this->currentValue().setOffsetLimit(token.end_ - this->begin_);
   return true;
 }
 
-bool OurReader::decodeNumber(Token& token, Value& decoded) {
+bool OurReader::decodeNumber(Token& token, Value& decoded)
+{
   // Attempts to parse the number as an integer. If the number is
   // larger than the maximum supported value of an integer then
   // we decode the number as a double.
@@ -1579,16 +1669,17 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
   bool isNegative = *current == '-';
   if (isNegative)
     ++current;
-  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
-  Value::LargestUInt maxIntegerValue =
-      isNegative ? Value::LargestUInt(Value::minLargestInt)
-                 : Value::maxLargestUInt;
+  // TODO: Help the compiler do the div and mod at compile time or get rid of
+  // them.
+  Value::LargestUInt maxIntegerValue = isNegative
+    ? Value::LargestUInt(Value::minLargestInt)
+    : Value::maxLargestUInt;
   Value::LargestUInt threshold = maxIntegerValue / 10;
   Value::LargestUInt value = 0;
   while (current < token.end_) {
     Char c = *current++;
     if (c < '0' || c > '9')
-      return decodeDouble(token, decoded);
+      return this->decodeDouble(token, decoded);
     Value::UInt digit(static_cast<Value::UInt>(c - '0'));
     if (value >= threshold) {
       // We've hit or exceeded the max value divided by 10 (rounded down). If
@@ -1597,7 +1688,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
       // Otherwise treat this number as a double to avoid overflow.
       if (value > threshold || current != token.end_ ||
           digit > maxIntegerValue % 10) {
-        return decodeDouble(token, decoded);
+        return this->decodeDouble(token, decoded);
       }
     }
     value = value * 10 + digit;
@@ -1611,17 +1702,19 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
   return true;
 }
 
-bool OurReader::decodeDouble(Token& token) {
+bool OurReader::decodeDouble(Token& token)
+{
   Value decoded;
-  if (!decodeDouble(token, decoded))
+  if (!this->decodeDouble(token, decoded))
     return false;
-  currentValue().swapPayload(decoded);
-  currentValue().setOffsetStart(token.start_ - begin_);
-  currentValue().setOffsetLimit(token.end_ - begin_);
+  this->currentValue().swapPayload(decoded);
+  this->currentValue().setOffsetStart(token.start_ - this->begin_);
+  this->currentValue().setOffsetLimit(token.end_ - this->begin_);
   return true;
 }
 
-bool OurReader::decodeDouble(Token& token, Value& decoded) {
+bool OurReader::decodeDouble(Token& token, Value& decoded)
+{
   double value = 0;
   const int bufferSize = 32;
   int count;
@@ -1629,7 +1722,7 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) {
 
   // Sanity check to avoid buffer overflow exploits.
   if (length < 0) {
-    return addError("Unable to parse token length", token);
+    return this->addError("Unable to parse token length", token);
   }
   size_t const ulength = static_cast<size_t>(length);
 
@@ -1652,25 +1745,27 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) {
   }
 
   if (count != 1)
-    return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
-                        "' is not a number.",
-                    token);
+    return this->addError("'" + JSONCPP_STRING(token.start_, token.end_) +
+                            "' is not a number.",
+                          token);
   decoded = value;
   return true;
 }
 
-bool OurReader::decodeString(Token& token) {
+bool OurReader::decodeString(Token& token)
+{
   JSONCPP_STRING decoded_string;
-  if (!decodeString(token, decoded_string))
+  if (!this->decodeString(token, decoded_string))
     return false;
   Value decoded(decoded_string);
-  currentValue().swapPayload(decoded);
-  currentValue().setOffsetStart(token.start_ - begin_);
-  currentValue().setOffsetLimit(token.end_ - begin_);
+  this->currentValue().swapPayload(decoded);
+  this->currentValue().setOffsetStart(token.start_ - this->begin_);
+  this->currentValue().setOffsetLimit(token.end_ - this->begin_);
   return true;
 }
 
-bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
+bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded)
+{
   decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
   Location current = token.start_ + 1; // skip '"'
   Location end = token.end_ - 1;       // do not include '"'
@@ -1680,41 +1775,43 @@ bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
       break;
     else if (c == '\\') {
       if (current == end)
-        return addError("Empty escape sequence in string", token, current);
+        return this->addError("Empty escape sequence in string", token,
+                              current);
       Char escape = *current++;
       switch (escape) {
-      case '"':
-        decoded += '"';
-        break;
-      case '/':
-        decoded += '/';
-        break;
-      case '\\':
-        decoded += '\\';
-        break;
-      case 'b':
-        decoded += '\b';
-        break;
-      case 'f':
-        decoded += '\f';
-        break;
-      case 'n':
-        decoded += '\n';
-        break;
-      case 'r':
-        decoded += '\r';
-        break;
-      case 't':
-        decoded += '\t';
-        break;
-      case 'u': {
-        unsigned int unicode;
-        if (!decodeUnicodeCodePoint(token, current, end, unicode))
-          return false;
-        decoded += codePointToUTF8(unicode);
-      } break;
-      default:
-        return addError("Bad escape sequence in string", token, current);
+        case '"':
+          decoded += '"';
+          break;
+        case '/':
+          decoded += '/';
+          break;
+        case '\\':
+          decoded += '\\';
+          break;
+        case 'b':
+          decoded += '\b';
+          break;
+        case 'f':
+          decoded += '\f';
+          break;
+        case 'n':
+          decoded += '\n';
+          break;
+        case 'r':
+          decoded += '\r';
+          break;
+        case 't':
+          decoded += '\t';
+          break;
+        case 'u': {
+          unsigned int unicode;
+          if (!this->decodeUnicodeCodePoint(token, current, end, unicode))
+            return false;
+          decoded += codePointToUTF8(unicode);
+        } break;
+        default:
+          return this->addError("Bad escape sequence in string", token,
+                                current);
       }
     } else {
       decoded += c;
@@ -1723,45 +1820,44 @@ bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
   return true;
 }
 
-bool OurReader::decodeUnicodeCodePoint(Token& token,
-                                    Location& current,
-                                    Location end,
-                                    unsigned int& unicode) {
+bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
+                                       Location end, unsigned int& unicode)
+{
 
   unicode = 0; // Convince scanbuild this is always initialized before use.
-  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+  if (!this->decodeUnicodeEscapeSequence(token, current, end, unicode))
     return false;
   if (unicode >= 0xD800 && unicode <= 0xDBFF) {
     // surrogate pairs
     if (end - current < 6)
-      return addError(
-          "additional six characters expected to parse unicode surrogate pair.",
-          token,
-          current);
+      return this->addError(
+        "additional six characters expected to parse unicode surrogate pair.",
+        token, current);
     unsigned int surrogatePair;
     if (*(current++) == '\\' && *(current++) == 'u') {
-      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
-        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      if (this->decodeUnicodeEscapeSequence(token, current, end,
+                                            surrogatePair)) {
+        unicode =
+          0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
       } else
         return false;
     } else
-      return addError("expecting another \\u token to begin the second half of "
-                      "a unicode surrogate pair",
-                      token,
-                      current);
+      return this->addError(
+        "expecting another \\u token to begin the second half of "
+        "a unicode surrogate pair",
+        token, current);
   }
   return true;
 }
 
-bool OurReader::decodeUnicodeEscapeSequence(Token& token,
-                                         Location& current,
-                                         Location end,
-                                         unsigned int& ret_unicode) {
+bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
+                                            Location end,
+                                            unsigned int& ret_unicode)
+{
   if (end - current < 4)
-    return addError(
-        "Bad unicode escape sequence in string: four digits expected.",
-        token,
-        current);
+    return this->addError(
+      "Bad unicode escape sequence in string: four digits expected.", token,
+      current);
   int unicode = 0;
   for (int index = 0; index < 4; ++index) {
     Char c = *current++;
@@ -1773,60 +1869,65 @@ bool OurReader::decodeUnicodeEscapeSequence(Token& token,
     else if (c >= 'A' && c <= 'F')
       unicode += c - 'A' + 10;
     else
-      return addError(
-          "Bad unicode escape sequence in string: hexadecimal digit expected.",
-          token,
-          current);
+      return this->addError(
+        "Bad unicode escape sequence in string: hexadecimal digit expected.",
+        token, current);
   }
   ret_unicode = static_cast<unsigned int>(unicode);
   return true;
 }
 
-bool
-OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
+bool OurReader::addError(const JSONCPP_STRING& message, Token& token,
+                         Location extra)
+{
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
   info.extra_ = extra;
-  errors_.push_back(info);
+  this->errors_.push_back(info);
   return false;
 }
 
-bool OurReader::recoverFromError(TokenType skipUntilToken) {
-  size_t errorCount = errors_.size();
+bool OurReader::recoverFromError(TokenType skipUntilToken)
+{
+  size_t errorCount = this->errors_.size();
   Token skip;
   for (;;) {
-    if (!readToken(skip))
-      errors_.resize(errorCount); // discard errors caused by recovery
+    if (!this->readToken(skip))
+      this->errors_.resize(errorCount); // discard errors caused by recovery
     if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
       break;
   }
-  errors_.resize(errorCount);
+  this->errors_.resize(errorCount);
   return false;
 }
 
-bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
-                                Token& token,
-                                TokenType skipUntilToken) {
-  addError(message, token);
-  return recoverFromError(skipUntilToken);
+bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, Token& token,
+                                   TokenType skipUntilToken)
+{
+  this->addError(message, token);
+  return this->recoverFromError(skipUntilToken);
 }
 
-Value& OurReader::currentValue() { return *(nodes_.top()); }
+Value& OurReader::currentValue()
+{
+  return *(this->nodes_.top());
+}
 
-OurReader::Char OurReader::getNextChar() {
-  if (current_ == end_)
+OurReader::Char OurReader::getNextChar()
+{
+  if (this->current_ == this->end_)
     return 0;
-  return *current_++;
+  return *this->current_++;
 }
 
-void OurReader::getLocationLineAndColumn(Location location,
-                                      int& line,
-                                      int& column) const {
-  Location current = begin_;
+void OurReader::getLocationLineAndColumn(Location location, int& line,
+                                         int& column) const
+{
+  Location current = this->begin_;
   Location lastLineStart = current;
   line = 0;
-  while (current < location && current != end_) {
+  while (current < location && current != this->end_) {
     Char c = *current++;
     if (c == '\r') {
       if (*current == '\n')
@@ -1843,101 +1944,105 @@ void OurReader::getLocationLineAndColumn(Location location,
   ++line;
 }
 
-JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
+JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const
+{
   int line, column;
-  getLocationLineAndColumn(location, line, column);
+  this->getLocationLineAndColumn(location, line, column);
   char buffer[18 + 16 + 16 + 1];
   snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
   return buffer;
 }
 
-JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
+JSONCPP_STRING OurReader::getFormattedErrorMessages() const
+{
   JSONCPP_STRING formattedMessage;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
+  for (Errors::const_iterator itError = this->errors_.begin();
+       itError != this->errors_.end(); ++itError) {
     const ErrorInfo& error = *itError;
     formattedMessage +=
-        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+      "* " + this->getLocationLineAndColumn(error.token_.start_) + "\n";
     formattedMessage += "  " + error.message_ + "\n";
     if (error.extra_)
-      formattedMessage +=
-          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+      formattedMessage += "See " +
+        this->getLocationLineAndColumn(error.extra_) + " for detail.\n";
   }
   return formattedMessage;
 }
 
-std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
+std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const
+{
   std::vector<OurReader::StructuredError> allErrors;
-  for (Errors::const_iterator itError = errors_.begin();
-       itError != errors_.end();
-       ++itError) {
+  for (Errors::const_iterator itError = this->errors_.begin();
+       itError != this->errors_.end(); ++itError) {
     const ErrorInfo& error = *itError;
     OurReader::StructuredError structured;
-    structured.offset_start = error.token_.start_ - begin_;
-    structured.offset_limit = error.token_.end_ - begin_;
+    structured.offset_start = error.token_.start_ - this->begin_;
+    structured.offset_limit = error.token_.end_ - this->begin_;
     structured.message = error.message_;
     allErrors.push_back(structured);
   }
   return allErrors;
 }
 
-bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
-  ptrdiff_t length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length)
+bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message)
+{
+  ptrdiff_t length = this->end_ - this->begin_;
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
     return false;
   Token token;
   token.type_ = tokenError;
-  token.start_ = begin_ + value.getOffsetStart();
-  token.end_ = end_ + value.getOffsetLimit();
+  token.start_ = this->begin_ + value.getOffsetStart();
+  token.end_ = this->end_ + value.getOffsetLimit();
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
   info.extra_ = 0;
-  errors_.push_back(info);
+  this->errors_.push_back(info);
   return true;
 }
 
-bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
-  ptrdiff_t length = end_ - begin_;
-  if(value.getOffsetStart() > length
-    || value.getOffsetLimit() > length
-    || extra.getOffsetLimit() > length)
+bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message,
+                          const Value& extra)
+{
+  ptrdiff_t length = this->end_ - this->begin_;
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
+      extra.getOffsetLimit() > length)
     return false;
   Token token;
   token.type_ = tokenError;
-  token.start_ = begin_ + value.getOffsetStart();
-  token.end_ = begin_ + value.getOffsetLimit();
+  token.start_ = this->begin_ + value.getOffsetStart();
+  token.end_ = this->begin_ + value.getOffsetLimit();
   ErrorInfo info;
   info.token_ = token;
   info.message_ = message;
-  info.extra_ = begin_ + extra.getOffsetStart();
-  errors_.push_back(info);
+  info.extra_ = this->begin_ + extra.getOffsetStart();
+  this->errors_.push_back(info);
   return true;
 }
 
-bool OurReader::good() const {
-  return !errors_.size();
+bool OurReader::good() const
+{
+  return !this->errors_.size();
 }
 
-
-class OurCharReader : public CharReader {
+class OurCharReader : public CharReader
+{
   bool const collectComments_;
   OurReader reader_;
+
 public:
-  OurCharReader(
-    bool collectComments,
-    OurFeatures const& features)
-  : collectComments_(collectComments)
-  , reader_(features)
-  {}
-  bool parse(
-      char const* beginDoc, char const* endDoc,
-      Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
-    bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
+  OurCharReader(bool collectComments, OurFeatures const& features)
+    : collectComments_(collectComments)
+    , reader_(features)
+  {
+  }
+  bool parse(char const* beginDoc, char const* endDoc, Value* root,
+             JSONCPP_STRING* errs) JSONCPP_OVERRIDE
+  {
+    bool ok =
+      this->reader_.parse(beginDoc, endDoc, *root, this->collectComments_);
     if (errs) {
-      *errs = reader_.getFormattedErrorMessages();
+      *errs = this->reader_.getFormattedErrorMessages();
     }
     return ok;
   }
@@ -1945,23 +2050,26 @@ public:
 
 CharReaderBuilder::CharReaderBuilder()
 {
-  setDefaults(&settings_);
+  setDefaults(&this->settings_);
 }
 CharReaderBuilder::~CharReaderBuilder()
-{}
+{
+}
 CharReader* CharReaderBuilder::newCharReader() const
 {
-  bool collectComments = settings_["collectComments"].asBool();
+  bool collectComments = this->settings_["collectComments"].asBool();
   OurFeatures features = OurFeatures::all();
-  features.allowComments_ = settings_["allowComments"].asBool();
-  features.strictRoot_ = settings_["strictRoot"].asBool();
-  features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
-  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
-  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
-  features.stackLimit_ = settings_["stackLimit"].asInt();
-  features.failIfExtra_ = settings_["failIfExtra"].asBool();
-  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
-  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
+  features.allowComments_ = this->settings_["allowComments"].asBool();
+  features.strictRoot_ = this->settings_["strictRoot"].asBool();
+  features.allowDroppedNullPlaceholders_ =
+    this->settings_["allowDroppedNullPlaceholders"].asBool();
+  features.allowNumericKeys_ = this->settings_["allowNumericKeys"].asBool();
+  features.allowSingleQuotes_ = this->settings_["allowSingleQuotes"].asBool();
+  features.stackLimit_ = this->settings_["stackLimit"].asInt();
+  features.failIfExtra_ = this->settings_["failIfExtra"].asBool();
+  features.rejectDupKeys_ = this->settings_["rejectDupKeys"].asBool();
+  features.allowSpecialFloats_ =
+    this->settings_["allowSpecialFloats"].asBool();
   return new OurCharReader(collectComments, features);
 }
 static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
@@ -1981,28 +2089,29 @@ static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
 bool CharReaderBuilder::validate(Json::Value* invalid) const
 {
   Json::Value my_invalid;
-  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
+  if (!invalid)
+    invalid = &my_invalid; // so we do not need to test for NULL
   Json::Value& inv = *invalid;
   std::set<JSONCPP_STRING> valid_keys;
   getValidReaderKeys(&valid_keys);
-  Value::Members keys = settings_.getMemberNames();
+  Value::Members keys = this->settings_.getMemberNames();
   size_t n = keys.size();
   for (size_t i = 0; i < n; ++i) {
     JSONCPP_STRING const& key = keys[i];
     if (valid_keys.find(key) == valid_keys.end()) {
-      inv[key] = settings_[key];
+      inv[key] = this->settings_[key];
     }
   }
   return 0u == inv.size();
 }
 Value& CharReaderBuilder::operator[](JSONCPP_STRING key)
 {
-  return settings_[key];
+  return this->settings_[key];
 }
 // static
 void CharReaderBuilder::strictMode(Json::Value* settings)
 {
-//! [CharReaderBuilderStrictMode]
+  //! [CharReaderBuilderStrictMode]
   (*settings)["allowComments"] = false;
   (*settings)["strictRoot"] = true;
   (*settings)["allowDroppedNullPlaceholders"] = false;
@@ -2012,12 +2121,12 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
   (*settings)["failIfExtra"] = true;
   (*settings)["rejectDupKeys"] = true;
   (*settings)["allowSpecialFloats"] = false;
-//! [CharReaderBuilderStrictMode]
+  //! [CharReaderBuilderStrictMode]
 }
 // static
 void CharReaderBuilder::setDefaults(Json::Value* settings)
 {
-//! [CharReaderBuilderDefaults]
+  //! [CharReaderBuilderDefaults]
   (*settings)["collectComments"] = true;
   (*settings)["allowComments"] = true;
   (*settings)["strictRoot"] = false;
@@ -2028,15 +2137,14 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
   (*settings)["failIfExtra"] = false;
   (*settings)["rejectDupKeys"] = false;
   (*settings)["allowSpecialFloats"] = false;
-//! [CharReaderBuilderDefaults]
+  //! [CharReaderBuilderDefaults]
 }
 
 //////////////////////////////////
 // global functions
 
-bool parseFromStream(
-    CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
-    Value* root, JSONCPP_STRING* errs)
+bool parseFromStream(CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
+                     Value* root, JSONCPP_STRING* errs)
 {
   JSONCPP_OSTRINGSTREAM ssin;
   ssin << sin.rdbuf();
@@ -2048,14 +2156,13 @@ bool parseFromStream(
   return reader->parse(begin, end, root, errs);
 }
 
-JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
+JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root)
+{
   CharReaderBuilder b;
   JSONCPP_STRING errs;
   bool ok = parseFromStream(b, sin, &root, &errs);
   if (!ok) {
-    fprintf(stderr,
-            "Error from reader: %s",
-            errs.c_str());
+    fprintf(stderr, "Error from reader: %s", errs.c_str());
 
     throwRuntimeError(errs);
   }
index f271e57..eadb1c3 100644 (file)
@@ -1,23 +1,25 @@
 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
 // Distributed under MIT license, or public domain if desired and
 // recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+// See file LICENSE for detail or copy at
+// http://jsoncpp.sourceforge.net/LICENSE
 
 #if !defined(JSON_IS_AMALGAMATION)
-#include <json/assertions.h>
-#include <json/value.h>
-#include <json/writer.h>
+#  include <json/assertions.h>
+#  include <json/value.h>
+#  include <json/writer.h>
 #endif // if !defined(JSON_IS_AMALGAMATION)
-#include <math.h>
 #include <sstream>
 #include <utility>
-#include <string.h>
+
 #include <assert.h>
+#include <math.h>
+#include <string.h>
 #ifdef JSON_USE_CPPTL
-#include <cpptl/conststring.h>
+#  include <cpptl/conststring.h>
 #endif
-#include <cstddef> // size_t
 #include <algorithm> // min()
+#include <cstddef>   // size_t
 
 #define JSON_ASSERT_UNREACHABLE assert(false)
 
@@ -27,24 +29,24 @@ namespace Json {
 // kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
 // 8 (instead of 4) as a bit of future-proofing.
 #if defined(__ARMEL__)
-#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#  define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
 #else
-#define ALIGNAS(byte_alignment)
+#  define ALIGNAS(byte_alignment)
 #endif
-//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
-//const unsigned char& kNullRef = kNull[0];
-//const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
-//const Value& Value::nullRef = null;
+// static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
+// const unsigned char& kNullRef = kNull[0];
+// const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
+// const Value& Value::nullRef = null;
 
 // static
 Value const& Value::nullSingleton()
 {
- static Value const nullStatic;
- return nullStatic;
 static Value const nullStatic;
 return nullStatic;
 }
 
-// for backwards compatibility, we'll leave these global references around, but DO NOT
-// use them in JSONCPP library code any more!
+// for backwards compatibility, we'll leave these global references around, but
+// DO NOT use them in JSONCPP library code any more!
 Value const& Value::null = Value::nullSingleton();
 Value const& Value::nullRef = Value::nullSingleton();
 
@@ -66,23 +68,29 @@ const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
 
 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
 template <typename T, typename U>
-static inline bool InRange(double d, T min, U max) {
+static inline bool InRange(double d, T min, U max)
+{
   // The casts can lose precision, but we are looking only for
   // an approximate range. Might fail on edge cases though. ~cdunn
-  //return d >= static_cast<double>(min) && d <= static_cast<double>(max);
+  // return d >= static_cast<double>(min) && d <= static_cast<double>(max);
   return d >= min && d <= max;
 }
 #else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-static inline double integerToDouble(Json::UInt64 value) {
-  return static_cast<double>(Int64(value / 2)) * 2.0 + static_cast<double>(Int64(value & 1));
+static inline double integerToDouble(Json::UInt64 value)
+{
+  return static_cast<double>(Int64(value / 2)) * 2.0 +
+    static_cast<double>(Int64(value & 1));
 }
 
-template <typename T> static inline double integerToDouble(T value) {
+template <typename T>
+static inline double integerToDouble(T value)
+{
   return static_cast<double>(value);
 }
 
 template <typename T, typename U>
-static inline bool InRange(double d, T min, U max) {
+static inline bool InRange(double d, T min, U max)
+{
   return d >= integerToDouble(min) && d <= integerToDouble(max);
 }
 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
@@ -94,8 +102,7 @@ static inline bool InRange(double d, T min, U max) {
  *               computed using strlen(value).
  * @return Pointer on the duplicate instance of string.
  */
-static inline char* duplicateStringValue(const char* value,
-                                         size_t length)
+static inline char* duplicateStringValue(const char* value, size_t length)
 {
   // Avoid an integer overflow in the call to malloc below by limiting length
   // to a sane value.
@@ -104,9 +111,8 @@ static inline char* duplicateStringValue(const char* value,
 
   char* newString = static_cast<char*>(malloc(length + 1));
   if (newString == NULL) {
-    throwRuntimeError(
-        "in Json::Value::duplicateStringValue(): "
-        "Failed to allocate string value buffer");
+    throwRuntimeError("in Json::Value::duplicateStringValue(): "
+                      "Failed to allocate string value buffer");
   }
   memcpy(newString, value, length);
   newString[length] = 0;
@@ -115,30 +121,30 @@ static inline char* duplicateStringValue(const char* value,
 
 /* Record the length as a prefix.
  */
-static inline char* duplicateAndPrefixStringValue(
-    const char* value,
-    unsigned int length)
+static inline char* duplicateAndPrefixStringValue(const char* value,
+                                                  unsigned int length)
 {
   // Avoid an integer overflow in the call to malloc below by limiting length
   // to a sane value.
-  JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) - sizeof(unsigned) - 1U,
+  JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
+                          sizeof(unsigned) - 1U,
                       "in Json::Value::duplicateAndPrefixStringValue(): "
                       "length too big for prefixing");
-  unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
+  unsigned actualLength =
+    length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
   char* newString = static_cast<char*>(malloc(actualLength));
   if (newString == 0) {
-    throwRuntimeError(
-        "in Json::Value::duplicateAndPrefixStringValue(): "
-        "Failed to allocate string value buffer");
+    throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
+                      "Failed to allocate string value buffer");
   }
   *reinterpret_cast<unsigned*>(newString) = length;
   memcpy(newString + sizeof(unsigned), value, length);
-  newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
+  newString[actualLength - 1U] =
+    0; // to avoid buffer over-run accidents by users later
   return newString;
 }
-inline static void decodePrefixedString(
-    bool isPrefixed, char const* prefixed,
-    unsigned* length, char const** value)
+inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
+                                        unsigned* length, char const** value)
 {
   if (!isPrefixed) {
     *length = static_cast<unsigned>(strlen(prefixed));
@@ -148,10 +154,12 @@ inline static void decodePrefixedString(
     *value = prefixed + sizeof(unsigned);
   }
 }
-/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
+/** Free the string duplicated by
+ * duplicateStringValue()/duplicateAndPrefixStringValue().
  */
 #if JSONCPP_USING_SECURE_MEMORY
-static inline void releasePrefixedStringValue(char* value) {
+static inline void releasePrefixedStringValue(char* value)
+{
   unsigned length = 0;
   char const* valueDecoded;
   decodePrefixedString(true, value, &length, &valueDecoded);
@@ -159,17 +167,20 @@ static inline void releasePrefixedStringValue(char* value) {
   memset(value, 0, size);
   free(value);
 }
-static inline void releaseStringValue(char* value, unsigned length) {
+static inline void releaseStringValue(char* value, unsigned length)
+{
   // length==0 => we allocated the strings memory
-  size_t size = (length==0) ? strlen(value) : length;
+  size_t size = (length == 0) ? strlen(value) : length;
   memset(value, 0, size);
   free(value);
 }
-#else // !JSONCPP_USING_SECURE_MEMORY
-static inline void releasePrefixedStringValue(char* value) {
+#else  // !JSONCPP_USING_SECURE_MEMORY
+static inline void releasePrefixedStringValue(char* value)
+{
   free(value);
 }
-static inline void releaseStringValue(char* value, unsigned) {
+static inline void releaseStringValue(char* value, unsigned)
+{
   free(value);
 }
 #endif // JSONCPP_USING_SECURE_MEMORY
@@ -185,26 +196,30 @@ static inline void releaseStringValue(char* value, unsigned) {
 // //////////////////////////////////////////////////////////////////
 #if !defined(JSON_IS_AMALGAMATION)
 
-#include "json_valueiterator.inl"
+#  include "json_valueiterator.inl"
 #endif // if !defined(JSON_IS_AMALGAMATION)
 
 namespace Json {
 
 Exception::Exception(JSONCPP_STRING const& msg)
   : msg_(msg)
-{}
+{
+}
 Exception::~Exception() JSONCPP_NOEXCEPT
-{}
+{
+}
 char const* Exception::what() const JSONCPP_NOEXCEPT
 {
-  return msg_.c_str();
+  return this->msg_.c_str();
 }
 RuntimeError::RuntimeError(JSONCPP_STRING const& msg)
   : Exception(msg)
-{}
+{
+}
 LogicError::LogicError(JSONCPP_STRING const& msg)
   : Exception(msg)
-{}
+{
+}
 JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg)
 {
   throw RuntimeError(msg);
@@ -222,25 +237,29 @@ JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg)
 // //////////////////////////////////////////////////////////////////
 // //////////////////////////////////////////////////////////////////
 
-Value::CommentInfo::CommentInfo() : comment_(0)
-{}
+Value::CommentInfo::CommentInfo()
+  : comment_(0)
+{
+}
 
-Value::CommentInfo::~CommentInfo() {
-  if (comment_)
-    releaseStringValue(comment_, 0u);
+Value::CommentInfo::~CommentInfo()
+{
+  if (this->comment_)
+    releaseStringValue(this->comment_, 0u);
 }
 
-void Value::CommentInfo::setComment(const char* text, size_t len) {
-  if (comment_) {
-    releaseStringValue(comment_, 0u);
-    comment_ = 0;
+void Value::CommentInfo::setComment(const char* text, size_t len)
+{
+  if (this->comment_) {
+    releaseStringValue(this->comment_, 0u);
+    this->comment_ = 0;
   }
   JSON_ASSERT(text != 0);
   JSON_ASSERT_MESSAGE(
-      text[0] == '\0' || text[0] == '/',
-      "in Json::Value::setComment(): Comments must start with /");
+    text[0] == '\0' || text[0] == '/',
+    "in Json::Value::setComment(): Comments must start with /");
   // It seems that /**/ style comments are acceptable as well.
-  comment_ = duplicateStringValue(text, len);
+  this->comment_ = duplicateStringValue(text, len);
 }
 
 // //////////////////////////////////////////////////////////////////
@@ -254,91 +273,130 @@ void Value::CommentInfo::setComment(const char* text, size_t len) {
 // Notes: policy_ indicates if the string was allocated when
 // a string is stored.
 
-Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
+Value::CZString::CZString(ArrayIndex aindex)
+  : cstr_(0)
+  , index_(aindex)
+{
+}
 
-Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
-    : cstr_(str) {
+Value::CZString::CZString(char const* str, unsigned ulength,
+                          DuplicationPolicy allocate)
+  : cstr_(str)
+{
   // allocate != duplicate
-  storage_.policy_ = allocate & 0x3;
-  storage_.length_ = ulength & 0x3FFFFFFF;
+  this->storage_.policy_ = allocate & 0x3;
+  this->storage_.length_ = ulength & 0x3FFFFFFF;
 }
 
-Value::CZString::CZString(const CZString& other) {
-  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0
-                                ? duplicateStringValue(other.cstr_, other.storage_.length_)
-                                : other.cstr_);
-  storage_.policy_ = static_cast<unsigned>(other.cstr_
-                 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
-                     ? noDuplication : duplicate)
-                 : static_cast<DuplicationPolicy>(other.storage_.policy_)) & 3U;
-  storage_.length_ = other.storage_.length_;
+Value::CZString::CZString(const CZString& other)
+{
+  this->cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0
+                   ? duplicateStringValue(other.cstr_, other.storage_.length_)
+                   : other.cstr_);
+  this->storage_.policy_ =
+    static_cast<unsigned>(
+      other.cstr_ ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
+                         noDuplication
+                       ? noDuplication
+                       : duplicate)
+                  : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
+    3U;
+  this->storage_.length_ = other.storage_.length_;
 }
 
 #if JSON_HAS_RVALUE_REFERENCES
 Value::CZString::CZString(CZString&& other)
-  : cstr_(other.cstr_), index_(other.index_) {
+  : cstr_(other.cstr_)
+  , index_(other.index_)
+{
   other.cstr_ = nullptr;
 }
 #endif
 
-Value::CZString::~CZString() {
-  if (cstr_ && storage_.policy_ == duplicate) {
-         releaseStringValue(const_cast<char*>(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary
+Value::CZString::~CZString()
+{
+  if (this->cstr_ && this->storage_.policy_ == duplicate) {
+    releaseStringValue(const_cast<char*>(this->cstr_),
+                       this->storage_.length_ +
+                         1u); //+1 for null terminating character for sake of
+                              //completeness but not actually necessary
   }
 }
 
-void Value::CZString::swap(CZString& other) {
-  std::swap(cstr_, other.cstr_);
-  std::swap(index_, other.index_);
+void Value::CZString::swap(CZString& other)
+{
+  std::swap(this->cstr_, other.cstr_);
+  std::swap(this->index_, other.index_);
 }
 
-Value::CZString& Value::CZString::operator=(const CZString& other) {
-  cstr_ = other.cstr_;
-  index_ = other.index_;
+Value::CZString& Value::CZString::operator=(const CZString& other)
+{
+  this->cstr_ = other.cstr_;
+  this->index_ = other.index_;
   return *this;
 }
 
 #if JSON_HAS_RVALUE_REFERENCES
-Value::CZString& Value::CZString::operator=(CZString&& other) {
-  cstr_ = other.cstr_;
-  index_ = other.index_;
+Value::CZString& Value::CZString::operator=(CZString&& other)
+{
+  this->cstr_ = other.cstr_;
+  this->index_ = other.index_;
   other.cstr_ = nullptr;
   return *this;
 }
 #endif
 
-bool Value::CZString::operator<(const CZString& other) const {
-  if (!cstr_) return index_ < other.index_;
-  //return strcmp(cstr_, other.cstr_) < 0;
+bool Value::CZString::operator<(const CZString& other) const
+{
+  if (!this->cstr_)
+    return this->index_ < other.index_;
+  // return strcmp(cstr_, other.cstr_) < 0;
   // Assume both are strings.
   unsigned this_len = this->storage_.length_;
   unsigned other_len = other.storage_.length_;
   unsigned min_len = std::min<unsigned>(this_len, other_len);
   JSON_ASSERT(this->cstr_ && other.cstr_);
   int comp = memcmp(this->cstr_, other.cstr_, min_len);
-  if (comp < 0) return true;
-  if (comp > 0) return false;
+  if (comp < 0)
+    return true;
+  if (comp > 0)
+    return false;
   return (this_len < other_len);
 }
 
-bool Value::CZString::operator==(const CZString& other) const {
-  if (!cstr_) return index_ == other.index_;
-  //return strcmp(cstr_, other.cstr_) == 0;
+bool Value::CZString::operator==(const CZString& other) const
+{
+  if (!this->cstr_)
+    return this->index_ == other.index_;
+  // return strcmp(cstr_, other.cstr_) == 0;
   // Assume both are strings.
   unsigned this_len = this->storage_.length_;
   unsigned other_len = other.storage_.length_;
-  if (this_len != other_len) return false;
+  if (this_len != other_len)
+    return false;
   JSON_ASSERT(this->cstr_ && other.cstr_);
   int comp = memcmp(this->cstr_, other.cstr_, this_len);
   return comp == 0;
 }
 
-ArrayIndex Value::CZString::index() const { return index_; }
+ArrayIndex Value::CZString::index() const
+{
+  return this->index_;
+}
 
-//const char* Value::CZString::c_str() const { return cstr_; }
-const char* Value::CZString::data() const { return cstr_; }
-unsigned Value::CZString::length() const { return storage_.length_; }
-bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
+// const char* Value::CZString::c_str() const { return cstr_; }
+const char* Value::CZString::data() const
+{
+  return this->cstr_;
+}
+unsigned Value::CZString::length() const
+{
+  return this->storage_.length_;
+}
+bool Value::CZString::isStaticString() const
+{
+  return this->storage_.policy_ == noDuplication;
+}
 
 // //////////////////////////////////////////////////////////////////
 // //////////////////////////////////////////////////////////////////
@@ -352,210 +410,238 @@ bool Value::CZString::isStaticString() const { return storage_.policy_ == noDupl
  * memset( this, 0, sizeof(Value) )
  * This optimization is used in ValueInternalMap fast allocator.
  */
-Value::Value(ValueType vtype) {
+Value::Value(ValueType vtype)
+{
   static char const emptyString[] = "";
-  initBasic(vtype);
+  this->initBasic(vtype);
   switch (vtype) {
-  case nullValue:
-    break;
-  case intValue:
-  case uintValue:
-    value_.int_ = 0;
-    break;
-  case realValue:
-    value_.real_ = 0.0;
-    break;
-  case stringValue:
-    // allocated_ == false, so this is safe.
-    value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
-    break;
-  case arrayValue:
-  case objectValue:
-    value_.map_ = new ObjectValues();
-    break;
-  case booleanValue:
-    value_.bool_ = false;
-    break;
-  default:
-    JSON_ASSERT_UNREACHABLE;
+    case nullValue:
+      break;
+    case intValue:
+    case uintValue:
+      this->value_.int_ = 0;
+      break;
+    case realValue:
+      this->value_.real_ = 0.0;
+      break;
+    case stringValue:
+      // allocated_ == false, so this is safe.
+      this->value_.string_ =
+        const_cast<char*>(static_cast<char const*>(emptyString));
+      break;
+    case arrayValue:
+    case objectValue:
+      this->value_.map_ = new ObjectValues();
+      break;
+    case booleanValue:
+      this->value_.bool_ = false;
+      break;
+    default:
+      JSON_ASSERT_UNREACHABLE;
   }
 }
 
-Value::Value(Int value) {
-  initBasic(intValue);
-  value_.int_ = value;
+Value::Value(Int value)
+{
+  this->initBasic(intValue);
+  this->value_.int_ = value;
 }
 
-Value::Value(UInt value) {
-  initBasic(uintValue);
-  value_.uint_ = value;
+Value::Value(UInt value)
+{
+  this->initBasic(uintValue);
+  this->value_.uint_ = value;
 }
 #if defined(JSON_HAS_INT64)
-Value::Value(Int64 value) {
-  initBasic(intValue);
-  value_.int_ = value;
+Value::Value(Int64 value)
+{
+  this->initBasic(intValue);
+  this->value_.int_ = value;
 }
-Value::Value(UInt64 value) {
-  initBasic(uintValue);
-  value_.uint_ = value;
+Value::Value(UInt64 value)
+{
+  this->initBasic(uintValue);
+  this->value_.uint_ = value;
 }
 #endif // defined(JSON_HAS_INT64)
 
-Value::Value(double value) {
-  initBasic(realValue);
-  value_.real_ = value;
+Value::Value(double value)
+{
+  this->initBasic(realValue);
+  this->value_.real_ = value;
 }
 
-Value::Value(const char* value) {
-  initBasic(stringValue, true);
+Value::Value(const char* value)
+{
+  this->initBasic(stringValue, true);
   JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor");
-  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
+  this->value_.string_ =
+    duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
 }
 
-Value::Value(const char* beginValue, const char* endValue) {
-  initBasic(stringValue, true);
-  value_.string_ =
-      duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
+Value::Value(const char* beginValue, const char* endValue)
+{
+  this->initBasic(stringValue, true);
+  this->value_.string_ = duplicateAndPrefixStringValue(
+    beginValue, static_cast<unsigned>(endValue - beginValue));
 }
 
-Value::Value(const JSONCPP_STRING& value) {
-  initBasic(stringValue, true);
-  value_.string_ =
-      duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
+Value::Value(const JSONCPP_STRING& value)
+{
+  this->initBasic(stringValue, true);
+  this->value_.string_ = duplicateAndPrefixStringValue(
+    value.data(), static_cast<unsigned>(value.length()));
 }
 
-Value::Value(const StaticString& value) {
-  initBasic(stringValue);
-  value_.string_ = const_cast<char*>(value.c_str());
+Value::Value(const StaticString& value)
+{
+  this->initBasic(stringValue);
+  this->value_.string_ = const_cast<char*>(value.c_str());
 }
 
 #ifdef JSON_USE_CPPTL
-Value::Value(const CppTL::ConstString& value) {
+Value::Value(const CppTL::ConstString& value)
+{
   initBasic(stringValue, true);
-  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
+  value_.string_ = duplicateAndPrefixStringValue(
+    value, static_cast<unsigned>(value.length()));
 }
 #endif
 
-Value::Value(bool value) {
-  initBasic(booleanValue);
-  value_.bool_ = value;
+Value::Value(bool value)
+{
+  this->initBasic(booleanValue);
+  this->value_.bool_ = value;
 }
 
 Value::Value(Value const& other)
-    : type_(other.type_), allocated_(false)
-      ,
-      comments_(0), start_(other.start_), limit_(other.limit_)
-{
-  switch (type_) {
-  case nullValue:
-  case intValue:
-  case uintValue:
-  case realValue:
-  case booleanValue:
-    value_ = other.value_;
-    break;
-  case stringValue:
-    if (other.value_.string_ && other.allocated_) {
-      unsigned len;
-      char const* str;
-      decodePrefixedString(other.allocated_, other.value_.string_,
-          &len, &str);
-      value_.string_ = duplicateAndPrefixStringValue(str, len);
-      allocated_ = true;
-    } else {
-      value_.string_ = other.value_.string_;
-      allocated_ = false;
-    }
-    break;
-  case arrayValue:
-  case objectValue:
-    value_.map_ = new ObjectValues(*other.value_.map_);
-    break;
-  default:
-    JSON_ASSERT_UNREACHABLE;
+  : type_(other.type_)
+  , allocated_(false)
+  , comments_(0)
+  , start_(other.start_)
+  , limit_(other.limit_)
+{
+  switch (this->type_) {
+    case nullValue:
+    case intValue:
+    case uintValue:
+    case realValue:
+    case booleanValue:
+      this->value_ = other.value_;
+      break;
+    case stringValue:
+      if (other.value_.string_ && other.allocated_) {
+        unsigned len;
+        char const* str;
+        decodePrefixedString(other.allocated_, other.value_.string_, &len,
+                             &str);
+        this->value_.string_ = duplicateAndPrefixStringValue(str, len);
+        this->allocated_ = true;
+      } else {
+        this->value_.string_ = other.value_.string_;
+        this->allocated_ = false;
+      }
+      break;
+    case arrayValue:
+    case objectValue:
+      this->value_.map_ = new ObjectValues(*other.value_.map_);
+      break;
+    default:
+      JSON_ASSERT_UNREACHABLE;
   }
   if (other.comments_) {
-    comments_ = new CommentInfo[numberOfCommentPlacement];
+    this->comments_ = new CommentInfo[numberOfCommentPlacement];
     for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
       const CommentInfo& otherComment = other.comments_[comment];
       if (otherComment.comment_)
-        comments_[comment].setComment(
-            otherComment.comment_, strlen(otherComment.comment_));
+        this->comments_[comment].setComment(otherComment.comment_,
+                                            strlen(otherComment.comment_));
     }
   }
 }
 
 #if JSON_HAS_RVALUE_REFERENCES
 // Move constructor
-Value::Value(Value&& other) {
-  initBasic(nullValue);
-  swap(other);
+Value::Value(Value&& other)
+{
+  this->initBasic(nullValue);
+  this->swap(other);
 }
 #endif
 
-Value::~Value() {
-  switch (type_) {
-  case nullValue:
-  case intValue:
-  case uintValue:
-  case realValue:
-  case booleanValue:
-    break;
-  case stringValue:
-    if (allocated_)
-      releasePrefixedStringValue(value_.string_);
-    break;
-  case arrayValue:
-  case objectValue:
-    delete value_.map_;
-    break;
-  default:
-    JSON_ASSERT_UNREACHABLE;
+Value::~Value()
+{
+  switch (this->type_) {
+    case nullValue:
+    case intValue:
+    case uintValue:
+    case realValue:
+    case booleanValue:
+      break;
+    case stringValue:
+      if (this->allocated_)
+        releasePrefixedStringValue(this->value_.string_);
+      break;
+    case arrayValue:
+    case objectValue:
+      delete this->value_.map_;
+      break;
+    default:
+      JSON_ASSERT_UNREACHABLE;
   }
 
-  delete[] comments_;
+  delete[] this->comments_;
 
-  value_.uint_ = 0;
+  this->value_.uint_ = 0;
 }
 
-Value& Value::operator=(Value other) {
-  swap(other);
+Value& Value::operator=(Value other)
+{
+  this->swap(other);
   return *this;
 }
 
-void Value::swapPayload(Value& other) {
-  ValueType temp = type_;
-  type_ = other.type_;
+void Value::swapPayload(Value& other)
+{
+  ValueType temp = this->type_;
+  this->type_ = other.type_;
   other.type_ = temp;
-  std::swap(value_, other.value_);
-  int temp2 = allocated_;
-  allocated_ = other.allocated_;
+  std::swap(this->value_, other.value_);
+  int temp2 = this->allocated_;
+  this->allocated_ = other.allocated_;
   other.allocated_ = temp2 & 0x1;
 }
 
-void Value::copyPayload(const Value& other) {
-  type_ = other.type_;
-  value_ = other.value_;
-  allocated_ = other.allocated_;
+void Value::copyPayload(const Value& other)
+{
+  this->type_ = other.type_;
+  this->value_ = other.value_;
+  this->allocated_ = other.allocated_;
 }
 
-void Value::swap(Value& other) {
-  swapPayload(other);
-  std::swap(comments_, other.comments_);
-  std::swap(start_, other.start_);
-  std::swap(limit_, other.limit_);
+void Value::swap(Value& other)
+{
+  this->swapPayload(other);
+  std::swap(this->comments_, other.comments_);
+  std::swap(this->start_, other.start_);
+  std::swap(this->limit_, other.limit_);
 }
 
-void Value::copy(const Value& other) {
-  copyPayload(other);
-  comments_ = other.comments_;
-  start_ = other.start_;
-  limit_ = other.limit_;
+void Value::copy(const Value& other)
+{
+  this->copyPayload(other);
+  this->comments_ = other.comments_;
+  this->start_ = other.start_;
+  this->limit_ = other.limit_;
 }
 
-ValueType Value::type() const { return type_; }
+ValueType Value::type() const
+{
+  return this->type_;
+}
 
-int Value::compare(const Value& other) const {
+int Value::compare(const Value& other) const
+{
   if (*this < other)
     return -1;
   if (*this > other)
@@ -563,509 +649,568 @@ int Value::compare(const Value& other) const {
   return 0;
 }
 
-bool Value::operator<(const Value& other) const {
-  int typeDelta = type_ - other.type_;
+bool Value::operator<(const Value& other) const
+{
+  int typeDelta = this->type_ - other.type_;
   if (typeDelta)
     return typeDelta < 0 ? true : false;
-  switch (type_) {
-  case nullValue:
-    return false;
-  case intValue:
-    return value_.int_ < other.value_.int_;
-  case uintValue:
-    return value_.uint_ < other.value_.uint_;
-  case realValue:
-    return value_.real_ < other.value_.real_;
-  case booleanValue:
-    return value_.bool_ < other.value_.bool_;
-  case stringValue:
-  {
-    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
-      if (other.value_.string_) return true;
-      else return false;
+  switch (this->type_) {
+    case nullValue:
+      return false;
+    case intValue:
+      return this->value_.int_ < other.value_.int_;
+    case uintValue:
+      return this->value_.uint_ < other.value_.uint_;
+    case realValue:
+      return this->value_.real_ < other.value_.real_;
+    case booleanValue:
+      return this->value_.bool_ < other.value_.bool_;
+    case stringValue: {
+      if ((this->value_.string_ == 0) || (other.value_.string_ == 0)) {
+        if (other.value_.string_)
+          return true;
+        else
+          return false;
+      }
+      unsigned this_len;
+      unsigned other_len;
+      char const* this_str;
+      char const* other_str;
+      decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
+                           &this_str);
+      decodePrefixedString(other.allocated_, other.value_.string_, &other_len,
+                           &other_str);
+      unsigned min_len = std::min<unsigned>(this_len, other_len);
+      JSON_ASSERT(this_str && other_str);
+      int comp = memcmp(this_str, other_str, min_len);
+      if (comp < 0)
+        return true;
+      if (comp > 0)
+        return false;
+      return (this_len < other_len);
     }
-    unsigned this_len;
-    unsigned other_len;
-    char const* this_str;
-    char const* other_str;
-    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
-    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
-    unsigned min_len = std::min<unsigned>(this_len, other_len);
-    JSON_ASSERT(this_str && other_str);
-    int comp = memcmp(this_str, other_str, min_len);
-    if (comp < 0) return true;
-    if (comp > 0) return false;
-    return (this_len < other_len);
-  }
-  case arrayValue:
-  case objectValue: {
-    int delta = int(value_.map_->size() - other.value_.map_->size());
-    if (delta)
-      return delta < 0;
-    return (*value_.map_) < (*other.value_.map_);
-  }
-  default:
-    JSON_ASSERT_UNREACHABLE;
+    case arrayValue:
+    case objectValue: {
+      int delta = int(this->value_.map_->size() - other.value_.map_->size());
+      if (delta)
+        return delta < 0;
+      return (*this->value_.map_) < (*other.value_.map_);
+    }
+    default:
+      JSON_ASSERT_UNREACHABLE;
   }
   return false; // unreachable
 }
 
-bool Value::operator<=(const Value& other) const { return !(other < *this); }
+bool Value::operator<=(const Value& other) const
+{
+  return !(other < *this);
+}
 
-bool Value::operator>=(const Value& other) const { return !(*this < other); }
+bool Value::operator>=(const Value& other) const
+{
+  return !(*this < other);
+}
 
-bool Value::operator>(const Value& other) const { return other < *this; }
+bool Value::operator>(const Value& other) const
+{
+  return other < *this;
+}
 
-bool Value::operator==(const Value& other) const {
+bool Value::operator==(const Value& other) const
+{
   // if ( type_ != other.type_ )
   // GCC 2.95.3 says:
   // attempt to take address of bit-field structure member `Json::Value::type_'
   // Beats me, but a temp solves the problem.
   int temp = other.type_;
-  if (type_ != temp)
+  if (this->type_ != temp)
     return false;
-  switch (type_) {
-  case nullValue:
-    return true;
-  case intValue:
-    return value_.int_ == other.value_.int_;
-  case uintValue:
-    return value_.uint_ == other.value_.uint_;
-  case realValue:
-    return value_.real_ == other.value_.real_;
-  case booleanValue:
-    return value_.bool_ == other.value_.bool_;
-  case stringValue:
-  {
-    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
-      return (value_.string_ == other.value_.string_);
+  switch (this->type_) {
+    case nullValue:
+      return true;
+    case intValue:
+      return this->value_.int_ == other.value_.int_;
+    case uintValue:
+      return this->value_.uint_ == other.value_.uint_;
+    case realValue:
+      return this->value_.real_ == other.value_.real_;
+    case booleanValue:
+      return this->value_.bool_ == other.value_.bool_;
+    case stringValue: {
+      if ((this->value_.string_ == 0) || (other.value_.string_ == 0)) {
+        return (this->value_.string_ == other.value_.string_);
+      }
+      unsigned this_len;
+      unsigned other_len;
+      char const* this_str;
+      char const* other_str;
+      decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
+                           &this_str);
+      decodePrefixedString(other.allocated_, other.value_.string_, &other_len,
+                           &other_str);
+      if (this_len != other_len)
+        return false;
+      JSON_ASSERT(this_str && other_str);
+      int comp = memcmp(this_str, other_str, this_len);
+      return comp == 0;
     }
-    unsigned this_len;
-    unsigned other_len;
-    char const* this_str;
-    char const* other_str;
-    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
-    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
-    if (this_len != other_len) return false;
-    JSON_ASSERT(this_str && other_str);
-    int comp = memcmp(this_str, other_str, this_len);
-    return comp == 0;
-  }
-  case arrayValue:
-  case objectValue:
-    return value_.map_->size() == other.value_.map_->size() &&
-           (*value_.map_) == (*other.value_.map_);
-  default:
-    JSON_ASSERT_UNREACHABLE;
+    case arrayValue:
+    case objectValue:
+      return this->value_.map_->size() == other.value_.map_->size() &&
+        (*this->value_.map_) == (*other.value_.map_);
+    default:
+      JSON_ASSERT_UNREACHABLE;
   }
   return false; // unreachable
 }
 
-bool Value::operator!=(const Value& other) const { return !(*this == other); }
+bool Value::operator!=(const Value& other) const
+{
+  return !(*this == other);
+}
 
-const char* Value::asCString() const {
+const char* Value::asCString() const
+{
   JSON_ASSERT_MESSAGE(type_ == stringValue,
                       "in Json::Value::asCString(): requires stringValue");
-  if (value_.string_ == 0) return 0;
+  if (this->value_.string_ == 0)
+    return 0;
   unsigned this_len;
   char const* this_str;
-  decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+  decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
+                       &this_str);
   return this_str;
 }
 
 #if JSONCPP_USING_SECURE_MEMORY
-unsigned Value::getCStringLength() const {
+unsigned Value::getCStringLength() const
+{
   JSON_ASSERT_MESSAGE(type_ == stringValue,
-                         "in Json::Value::asCString(): requires stringValue");
-  if (value_.string_ == 0) return 0;
+                      "in Json::Value::asCString(): requires stringValue");
+  if (value_.string_ == 0)
+    return 0;
   unsigned this_len;
   char const* this_str;
-  decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+  decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
+                       &this_str);
   return this_len;
 }
 #endif
 
-bool Value::getString(char const** str, char const** cend) const {
-  if (type_ != stringValue) return false;
-  if (value_.string_ == 0) return false;
+bool Value::getString(char const** str, char const** cend) const
+{
+  if (this->type_ != stringValue)
+    return false;
+  if (this->value_.string_ == 0)
+    return false;
   unsigned length;
   decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
   *cend = *str + length;
   return true;
 }
 
-JSONCPP_STRING Value::asString() const {
-  switch (type_) {
-  case nullValue:
-    return "";
-  case stringValue:
-  {
-    if (value_.string_ == 0) return "";
-    unsigned this_len;
-    char const* this_str;
-    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
-    return JSONCPP_STRING(this_str, this_len);
-  }
-  case booleanValue:
-    return value_.bool_ ? "true" : "false";
-  case intValue:
-    return valueToString(value_.int_);
-  case uintValue:
-    return valueToString(value_.uint_);
-  case realValue:
-    return valueToString(value_.real_);
-  default:
-    JSON_FAIL_MESSAGE("Type is not convertible to string");
+JSONCPP_STRING Value::asString() const
+{
+  switch (this->type_) {
+    case nullValue:
+      return "";
+    case stringValue: {
+      if (this->value_.string_ == 0)
+        return "";
+      unsigned this_len;
+      char const* this_str;
+      decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
+                           &this_str);
+      return JSONCPP_STRING(this_str, this_len);
+    }
+    case booleanValue:
+      return this->value_.bool_ ? "true" : "false";
+    case intValue:
+      return valueToString(this->value_.int_);
+    case uintValue:
+      return valueToString(this->value_.uint_);
+    case realValue:
+      return valueToString(this->value_.real_);
+    default:
+      JSON_FAIL_MESSAGE("Type is not convertible to string");
   }
 }
 
 #ifdef JSON_USE_CPPTL
-CppTL::ConstString Value::asConstString() const {
+CppTL::ConstString Value::asConstString() const
+{
   unsigned len;
   char const* str;
-  decodePrefixedString(allocated_, value_.string_,
-      &len, &str);
+  decodePrefixedString(allocated_, value_.string_, &len, &str);
   return CppTL::ConstString(str, len);
 }
 #endif
 
-Value::Int Value::asInt() const {
-  switch (type_) {
-  case intValue:
-    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
-    return Int(value_.int_);
-  case uintValue:
-    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
-    return Int(value_.uint_);
-  case realValue:
-    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
-                        "double out of Int range");
-    return Int(value_.real_);
-  case nullValue:
-    return 0;
-  case booleanValue:
-    return value_.bool_ ? 1 : 0;
-  default:
-    break;
+Value::Int Value::asInt() const
+{
+  switch (this->type_) {
+    case intValue:
+      JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+      return Int(this->value_.int_);
+    case uintValue:
+      JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+      return Int(this->value_.uint_);
+    case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
+                          "double out of Int range");
+      return Int(this->value_.real_);
+    case nullValue:
+      return 0;
+    case booleanValue:
+      return this->value_.bool_ ? 1 : 0;
+    default:
+      break;
   }
   JSON_FAIL_MESSAGE("Value is not convertible to Int.");
 }
 
-Value::UInt Value::asUInt() const {
-  switch (type_) {
-  case intValue:
-    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
-    return UInt(value_.int_);
-  case uintValue:
-    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
-    return UInt(value_.uint_);
-  case realValue:
-    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
-                        "double out of UInt range");
-    return UInt(value_.real_);
-  case nullValue:
-    return 0;
-  case booleanValue:
-    return value_.bool_ ? 1 : 0;
-  default:
-    break;
+Value::UInt Value::asUInt() const
+{
+  switch (this->type_) {
+    case intValue:
+      JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+      return UInt(this->value_.int_);
+    case uintValue:
+      JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+      return UInt(this->value_.uint_);
+    case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
+                          "double out of UInt range");
+      return UInt(this->value_.real_);
+    case nullValue:
+      return 0;
+    case booleanValue:
+      return this->value_.bool_ ? 1 : 0;
+    default:
+      break;
   }
   JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
 }
 
 #if defined(JSON_HAS_INT64)
 
-Value::Int64 Value::asInt64() const {
-  switch (type_) {
-  case intValue:
-    return Int64(value_.int_);
-  case uintValue:
-    JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
-    return Int64(value_.uint_);
-  case realValue:
-    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
-                        "double out of Int64 range");
-    return Int64(value_.real_);
-  case nullValue:
-    return 0;
-  case booleanValue:
-    return value_.bool_ ? 1 : 0;
-  default:
-    break;
+Value::Int64 Value::asInt64() const
+{
+  switch (this->type_) {
+    case intValue:
+      return Int64(this->value_.int_);
+    case uintValue:
+      JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+      return Int64(this->value_.uint_);
+    case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
+                          "double out of Int64 range");
+      return Int64(this->value_.real_);
+    case nullValue:
+      return 0;
+    case booleanValue:
+      return this->value_.bool_ ? 1 : 0;
+    default:
+      break;
   }
   JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
 }
 
-Value::UInt64 Value::asUInt64() const {
-  switch (type_) {
-  case intValue:
-    JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
-    return UInt64(value_.int_);
-  case uintValue:
-    return UInt64(value_.uint_);
-  case realValue:
-    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
-                        "double out of UInt64 range");
-    return UInt64(value_.real_);
-  case nullValue:
-    return 0;
-  case booleanValue:
-    return value_.bool_ ? 1 : 0;
-  default:
-    break;
+Value::UInt64 Value::asUInt64() const
+{
+  switch (this->type_) {
+    case intValue:
+      JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+      return UInt64(this->value_.int_);
+    case uintValue:
+      return UInt64(this->value_.uint_);
+    case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
+                          "double out of UInt64 range");
+      return UInt64(this->value_.real_);
+    case nullValue:
+      return 0;
+    case booleanValue:
+      return this->value_.bool_ ? 1 : 0;
+    default:
+      break;
   }
   JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
 }
 #endif // if defined(JSON_HAS_INT64)
 
-LargestInt Value::asLargestInt() const {
+LargestInt Value::asLargestInt() const
+{
 #if defined(JSON_NO_INT64)
   return asInt();
 #else
-  return asInt64();
+  return this->asInt64();
 #endif
 }
 
-LargestUInt Value::asLargestUInt() const {
+LargestUInt Value::asLargestUInt() const
+{
 #if defined(JSON_NO_INT64)
   return asUInt();
 #else
-  return asUInt64();
+  return this->asUInt64();
 #endif
 }
 
-double Value::asDouble() const {
-  switch (type_) {
-  case intValue:
-    return static_cast<double>(value_.int_);
-  case uintValue:
+double Value::asDouble() const
+{
+  switch (this->type_) {
+    case intValue:
+      return static_cast<double>(this->value_.int_);
+    case uintValue:
 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-    return static_cast<double>(value_.uint_);
+      return static_cast<double>(this->value_.uint_);
 #else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-    return integerToDouble(value_.uint_);
+      return integerToDouble(value_.uint_);
 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-  case realValue:
-    return value_.real_;
-  case nullValue:
-    return 0.0;
-  case booleanValue:
-    return value_.bool_ ? 1.0 : 0.0;
-  default:
-    break;
+    case realValue:
+      return this->value_.real_;
+    case nullValue:
+      return 0.0;
+    case booleanValue:
+      return this->value_.bool_ ? 1.0 : 0.0;
+    default:
+      break;
   }
   JSON_FAIL_MESSAGE("Value is not convertible to double.");
 }
 
-float Value::asFloat() const {
-  switch (type_) {
-  case intValue:
-    return static_cast<float>(value_.int_);
-  case uintValue:
+float Value::asFloat() const
+{
+  switch (this->type_) {
+    case intValue:
+      return static_cast<float>(this->value_.int_);
+    case uintValue:
 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-    return static_cast<float>(value_.uint_);
+      return static_cast<float>(this->value_.uint_);
 #else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-    // This can fail (silently?) if the value is bigger than MAX_FLOAT.
-    return static_cast<float>(integerToDouble(value_.uint_));
+      // This can fail (silently?) if the value is bigger than MAX_FLOAT.
+      return static_cast<float>(integerToDouble(value_.uint_));
 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
-  case realValue:
-    return static_cast<float>(value_.real_);
-  case nullValue:
-    return 0.0;
-  case booleanValue:
-    return value_.bool_ ? 1.0f : 0.0f;
-  default:
-    break;
+    case realValue:
+      return static_cast<float>(this->value_.real_);
+    case nullValue:
+      return 0.0;
+    case booleanValue:
+      return this->value_.bool_ ? 1.0f : 0.0f;
+    default:
+      break;
   }
   JSON_FAIL_MESSAGE("Value is not convertible to float.");
 }
 
-bool Value::asBool() const {
-  switch (type_) {
-  case booleanValue:
-    return value_.bool_;
-  case nullValue:
-    return false;
-  case intValue:
-    return value_.int_ ? true : false;
-  case uintValue:
-    return value_.uint_ ? true : false;
-  case realValue:
-    // This is kind of strange. Not recommended.
-    return (value_.real_ != 0.0) ? true : false;
-  default:
-    break;
+bool Value::asBool() const
+{
+  switch (this->type_) {
+    case booleanValue:
+      return this->value_.bool_;
+    case nullValue:
+      return false;
+    case intValue:
+      return this->value_.int_ ? true : false;
+    case uintValue:
+      return this->value_.uint_ ? true : false;
+    case realValue:
+      // This is kind of strange. Not recommended.
+      return (this->value_.real_ != 0.0) ? true : false;
+    default:
+      break;
   }
   JSON_FAIL_MESSAGE("Value is not convertible to bool.");
 }
 
-bool Value::isConvertibleTo(ValueType other) const {
+bool Value::isConvertibleTo(ValueType other) const
+{
   switch (other) {
-  case nullValue:
-    return (isNumeric() && asDouble() == 0.0) ||
-           (type_ == booleanValue && value_.bool_ == false) ||
-           (type_ == stringValue && asString().empty()) ||
-           (type_ == arrayValue && value_.map_->size() == 0) ||
-           (type_ == objectValue && value_.map_->size() == 0) ||
-           type_ == nullValue;
-  case intValue:
-    return isInt() ||
-           (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
-           type_ == booleanValue || type_ == nullValue;
-  case uintValue:
-    return isUInt() ||
-           (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
-           type_ == booleanValue || type_ == nullValue;
-  case realValue:
-    return isNumeric() || type_ == booleanValue || type_ == nullValue;
-  case booleanValue:
-    return isNumeric() || type_ == booleanValue || type_ == nullValue;
-  case stringValue:
-    return isNumeric() || type_ == booleanValue || type_ == stringValue ||
-           type_ == nullValue;
-  case arrayValue:
-    return type_ == arrayValue || type_ == nullValue;
-  case objectValue:
-    return type_ == objectValue || type_ == nullValue;
+    case nullValue:
+      return (this->isNumeric() && this->asDouble() == 0.0) ||
+        (this->type_ == booleanValue && this->value_.bool_ == false) ||
+        (this->type_ == stringValue && this->asString().empty()) ||
+        (this->type_ == arrayValue && this->value_.map_->size() == 0) ||
+        (this->type_ == objectValue && this->value_.map_->size() == 0) ||
+        this->type_ == nullValue;
+    case intValue:
+      return this->isInt() ||
+        (this->type_ == realValue &&
+         InRange(this->value_.real_, minInt, maxInt)) ||
+        this->type_ == booleanValue || this->type_ == nullValue;
+    case uintValue:
+      return this->isUInt() ||
+        (this->type_ == realValue &&
+         InRange(this->value_.real_, 0, maxUInt)) ||
+        this->type_ == booleanValue || this->type_ == nullValue;
+    case realValue:
+      return this->isNumeric() || this->type_ == booleanValue ||
+        this->type_ == nullValue;
+    case booleanValue:
+      return this->isNumeric() || this->type_ == booleanValue ||
+        this->type_ == nullValue;
+    case stringValue:
+      return this->isNumeric() || this->type_ == booleanValue ||
+        this->type_ == stringValue || this->type_ == nullValue;
+    case arrayValue:
+      return this->type_ == arrayValue || this->type_ == nullValue;
+    case objectValue:
+      return this->type_ == objectValue || this->type_ == nullValue;
   }
   JSON_ASSERT_UNREACHABLE;
   return false;
 }
 
 /// Number of values in array or object
-ArrayIndex Value::size() const {
-  switch (type_) {
-  case nullValue:
-  case intValue:
-  case uintValue:
-  case realValue:
-  case booleanValue:
-  case stringValue:
-    return 0;
-  case arrayValue: // size of the array is highest index + 1
-    if (!value_.map_->empty()) {
-      ObjectValues::const_iterator itLast = value_.map_->end();
-      --itLast;
-      return (*itLast).first.index() + 1;
-    }
-    return 0;
-  case objectValue:
-    return ArrayIndex(value_.map_->size());
+ArrayIndex Value::size() const
+{
+  switch (this->type_) {
+    case nullValue:
+    case intValue:
+    case uintValue:
+    case realValue:
+    case booleanValue:
+    case stringValue:
+      return 0;
+    case arrayValue: // size of the array is highest index + 1
+      if (!this->value_.map_->empty()) {
+        ObjectValues::const_iterator itLast = this->value_.map_->end();
+        --itLast;
+        return (*itLast).first.index() + 1;
+      }
+      return 0;
+    case objectValue:
+      return ArrayIndex(this->value_.map_->size());
   }
   JSON_ASSERT_UNREACHABLE;
   return 0; // unreachable;
 }
 
-bool Value::empty() const {
-  if (isNull() || isArray() || isObject())
-    return size() == 0u;
+bool Value::empty() const
+{
+  if (this->isNull() || this->isArray() || this->isObject())
+    return this->size() == 0u;
   else
     return false;
 }
 
-bool Value::operator!() const { return isNull(); }
+bool Value::operator!() const
+{
+  return this->isNull();
+}
 
-void Value::clear() {
+void Value::clear()
+{
   JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
-                          type_ == objectValue,
+                        type_ == objectValue,
                       "in Json::Value::clear(): requires complex value");
-  start_ = 0;
-  limit_ = 0;
-  switch (type_) {
-  case arrayValue:
-  case objectValue:
-    value_.map_->clear();
-    break;
-  default:
-    break;
+  this->start_ = 0;
+  this->limit_ = 0;
+  switch (this->type_) {
+    case arrayValue:
+    case objectValue:
+      this->value_.map_->clear();
+      break;
+    default:
+      break;
   }
 }
 
-void Value::resize(ArrayIndex newSize) {
+void Value::resize(ArrayIndex newSize)
+{
   JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
                       "in Json::Value::resize(): requires arrayValue");
-  if (type_ == nullValue)
+  if (this->type_ == nullValue)
     *this = Value(arrayValue);
-  ArrayIndex oldSize = size();
+  ArrayIndex oldSize = this->size();
   if (newSize == 0)
-    clear();
+    this->clear();
   else if (newSize > oldSize)
     (*this)[newSize - 1];
   else {
     for (ArrayIndex index = newSize; index < oldSize; ++index) {
-      value_.map_->erase(index);
+      this->value_.map_->erase(index);
     }
     JSON_ASSERT(size() == newSize);
   }
 }
 
-Value& Value::operator[](ArrayIndex index) {
+Value& Value::operator[](ArrayIndex index)
+{
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == arrayValue,
-      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
-  if (type_ == nullValue)
+    type_ == nullValue || type_ == arrayValue,
+    "in Json::Value::operator[](ArrayIndex): requires arrayValue");
+  if (this->type_ == nullValue)
     *this = Value(arrayValue);
   CZString key(index);
-  ObjectValues::iterator it = value_.map_->lower_bound(key);
-  if (it != value_.map_->end() && (*it).first == key)
+  ObjectValues::iterator it = this->value_.map_->lower_bound(key);
+  if (it != this->value_.map_->end() && (*it).first == key)
     return (*it).second;
 
   ObjectValues::value_type defaultValue(key, nullSingleton());
-  it = value_.map_->insert(it, defaultValue);
+  it = this->value_.map_->insert(it, defaultValue);
   return (*it).second;
 }
 
-Value& Value::operator[](int index) {
+Value& Value::operator[](int index)
+{
   JSON_ASSERT_MESSAGE(
-      index >= 0,
-      "in Json::Value::operator[](int index): index cannot be negative");
+    index >= 0,
+    "in Json::Value::operator[](int index): index cannot be negative");
   return (*this)[ArrayIndex(index)];
 }
 
-const Value& Value::operator[](ArrayIndex index) const {
+const Value& Value::operator[](ArrayIndex index) const
+{
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == arrayValue,
-      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
-  if (type_ == nullValue)
+    type_ == nullValue || type_ == arrayValue,
+    "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
+  if (this->type_ == nullValue)
     return nullSingleton();
   CZString key(index);
-  ObjectValues::const_iterator it = value_.map_->find(key);
-  if (it == value_.map_->end())
+  ObjectValues::const_iterator it = this->value_.map_->find(key);
+  if (it == this->value_.map_->end())
     return nullSingleton();
   return (*it).second;
 }
 
-const Value& Value::operator[](int index) const {
+const Value& Value::operator[](int index) const
+{
   JSON_ASSERT_MESSAGE(
-      index >= 0,
-      "in Json::Value::operator[](int index) const: index cannot be negative");
+    index >= 0,
+    "in Json::Value::operator[](int index) const: index cannot be negative");
   return (*this)[ArrayIndex(index)];
 }
 
-void Value::initBasic(ValueType vtype, bool allocated) {
-  type_ = vtype;
-  allocated_ = allocated;
-  comments_ = 0;
-  start_ = 0;
-  limit_ = 0;
+void Value::initBasic(ValueType vtype, bool allocated)
+{
+  this->type_ = vtype;
+  this->allocated_ = allocated;
+  this->comments_ = 0;
+  this->start_ = 0;
+  this->limit_ = 0;
 }
 
 // Access an object value by name, create a null member if it does not exist.
 // @pre Type of '*this' is object or null.
 // @param key is null-terminated.
-Value& Value::resolveReference(const char* key) {
+Value& Value::resolveReference(const char* key)
+{
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
-      "in Json::Value::resolveReference(): requires objectValue");
-  if (type_ == nullValue)
+    type_ == nullValue || type_ == objectValue,
+    "in Json::Value::resolveReference(): requires objectValue");
+  if (this->type_ == nullValue)
     *this = Value(objectValue);
-  CZString actualKey(
-      key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
-  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
-  if (it != value_.map_->end() && (*it).first == actualKey)
+  CZString actualKey(key, static_cast<unsigned>(strlen(key)),
+                     CZString::noDuplication); // NOTE!
+  ObjectValues::iterator it = this->value_.map_->lower_bound(actualKey);
+  if (it != this->value_.map_->end() && (*it).first == actualKey)
     return (*it).second;
 
   ObjectValues::value_type defaultValue(actualKey, nullSingleton());
-  it = value_.map_->insert(it, defaultValue);
+  it = this->value_.map_->insert(it, defaultValue);
   Value& value = (*it).second;
   return value;
 }
@@ -1074,198 +1219,223 @@ Value& Value::resolveReference(const char* key) {
 Value& Value::resolveReference(char const* key, char const* cend)
 {
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
-      "in Json::Value::resolveReference(key, end): requires objectValue");
-  if (type_ == nullValue)
+    type_ == nullValue || type_ == objectValue,
+    "in Json::Value::resolveReference(key, end): requires objectValue");
+  if (this->type_ == nullValue)
     *this = Value(objectValue);
-  CZString actualKey(
-      key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
-  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
-  if (it != value_.map_->end() && (*it).first == actualKey)
+  CZString actualKey(key, static_cast<unsigned>(cend - key),
+                     CZString::duplicateOnCopy);
+  ObjectValues::iterator it = this->value_.map_->lower_bound(actualKey);
+  if (it != this->value_.map_->end() && (*it).first == actualKey)
     return (*it).second;
 
   ObjectValues::value_type defaultValue(actualKey, nullSingleton());
-  it = value_.map_->insert(it, defaultValue);
+  it = this->value_.map_->insert(it, defaultValue);
   Value& value = (*it).second;
   return value;
 }
 
-Value Value::get(ArrayIndex index, const Value& defaultValue) const {
+Value Value::get(ArrayIndex index, const Value& defaultValue) const
+{
   const Value* value = &((*this)[index]);
   return value == &nullSingleton() ? defaultValue : *value;
 }
 
-bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
+bool Value::isValidIndex(ArrayIndex index) const
+{
+  return index < this->size();
+}
 
 Value const* Value::find(char const* key, char const* cend) const
 {
-  JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
-      "in Json::Value::find(key, end, found): requires objectValue or nullValue");
-  if (type_ == nullValue) return NULL;
-  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
-  ObjectValues::const_iterator it = value_.map_->find(actualKey);
-  if (it == value_.map_->end()) return NULL;
+  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+                      "in Json::Value::find(key, end, found): requires "
+                      "objectValue or nullValue");
+  if (this->type_ == nullValue)
+    return NULL;
+  CZString actualKey(key, static_cast<unsigned>(cend - key),
+                     CZString::noDuplication);
+  ObjectValues::const_iterator it = this->value_.map_->find(actualKey);
+  if (it == this->value_.map_->end())
+    return NULL;
   return &(*it).second;
 }
 const Value& Value::operator[](const char* key) const
 {
-  Value const* found = find(key, key + strlen(key));
-  if (!found) return nullSingleton();
+  Value const* found = this->find(key, key + strlen(key));
+  if (!found)
+    return nullSingleton();
   return *found;
 }
 Value const& Value::operator[](JSONCPP_STRING const& key) const
 {
-  Value const* found = find(key.data(), key.data() + key.length());
-  if (!found) return nullSingleton();
+  Value const* found = this->find(key.data(), key.data() + key.length());
+  if (!found)
+    return nullSingleton();
   return *found;
 }
 
-Value& Value::operator[](const char* key) {
-  return resolveReference(key, key + strlen(key));
+Value& Value::operator[](const char* key)
+{
+  return this->resolveReference(key, key + strlen(key));
 }
 
-Value& Value::operator[](const JSONCPP_STRING& key) {
-  return resolveReference(key.data(), key.data() + key.length());
+Value& Value::operator[](const JSONCPP_STRING& key)
+{
+  return this->resolveReference(key.data(), key.data() + key.length());
 }
 
-Value& Value::operator[](const StaticString& key) {
-  return resolveReference(key.c_str());
+Value& Value::operator[](const StaticString& key)
+{
+  return this->resolveReference(key.c_str());
 }
 
 #ifdef JSON_USE_CPPTL
-Value& Value::operator[](const CppTL::ConstString& key) {
+Value& Value::operator[](const CppTL::ConstString& key)
+{
   return resolveReference(key.c_str(), key.end_c_str());
 }
 Value const& Value::operator[](CppTL::ConstString const& key) const
 {
   Value const* found = find(key.c_str(), key.end_c_str());
-  if (!found) return nullSingleton();
+  if (!found)
+    return nullSingleton();
   return *found;
 }
 #endif
 
-Value& Value::append(const Value& value) { return (*this)[size()] = value; }
+Value& Value::append(const Value& value)
+{
+  return (*this)[this->size()] = value;
+}
 
 #if JSON_HAS_RVALUE_REFERENCES
-  Value& Value::append(Value&& value) { return (*this)[size()] = value; }
+Value& Value::append(Value&& value)
+{
+  return (*this)[this->size()] = value;
+}
 #endif
 
-Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
+Value Value::get(char const* key, char const* cend,
+                 Value const& defaultValue) const
 {
-  Value const* found = find(key, cend);
+  Value const* found = this->find(key, cend);
   return !found ? defaultValue : *found;
 }
 Value Value::get(char const* key, Value const& defaultValue) const
 {
-  return get(key, key + strlen(key), defaultValue);
+  return this->get(key, key + strlen(key), defaultValue);
 }
 Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const
 {
-  return get(key.data(), key.data() + key.length(), defaultValue);
+  return this->get(key.data(), key.data() + key.length(), defaultValue);
 }
 
-
 bool Value::removeMember(const char* key, const char* cend, Value* removed)
 {
-  if (type_ != objectValue) {
+  if (this->type_ != objectValue) {
     return false;
   }
-  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
-  ObjectValues::iterator it = value_.map_->find(actualKey);
-  if (it == value_.map_->end())
+  CZString actualKey(key, static_cast<unsigned>(cend - key),
+                     CZString::noDuplication);
+  ObjectValues::iterator it = this->value_.map_->find(actualKey);
+  if (it == this->value_.map_->end())
     return false;
   *removed = it->second;
-  value_.map_->erase(it);
+  this->value_.map_->erase(it);
   return true;
 }
 bool Value::removeMember(const char* key, Value* removed)
 {
-  return removeMember(key, key + strlen(key), removed);
+  return this->removeMember(key, key + strlen(key), removed);
 }
 bool Value::removeMember(JSONCPP_STRING const& key, Value* removed)
 {
-  return removeMember(key.data(), key.data() + key.length(), removed);
+  return this->removeMember(key.data(), key.data() + key.length(), removed);
 }
 Value Value::removeMember(const char* key)
 {
   JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
                       "in Json::Value::removeMember(): requires objectValue");
-  if (type_ == nullValue)
+  if (this->type_ == nullValue)
     return nullSingleton();
 
-  Value removed;  // null
-  removeMember(key, key + strlen(key), &removed);
+  Value removed; // null
+  this->removeMember(key, key + strlen(key), &removed);
   return removed; // still null if removeMember() did nothing
 }
 Value Value::removeMember(const JSONCPP_STRING& key)
 {
-  return removeMember(key.c_str());
+  return this->removeMember(key.c_str());
 }
 
-bool Value::removeIndex(ArrayIndex index, Value* removed) {
-  if (type_ != arrayValue) {
+bool Value::removeIndex(ArrayIndex index, Value* removed)
+{
+  if (this->type_ != arrayValue) {
     return false;
   }
   CZString key(index);
-  ObjectValues::iterator it = value_.map_->find(key);
-  if (it == value_.map_->end()) {
+  ObjectValues::iterator it = this->value_.map_->find(key);
+  if (it == this->value_.map_->end()) {
     return false;
   }
   *removed = it->second;
-  ArrayIndex oldSize = size();
+  ArrayIndex oldSize = this->size();
   // shift left all items left, into the place of the "removed"
-  for (ArrayIndex i = index; i < (oldSize - 1); ++i){
+  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
     CZString keey(i);
-    (*value_.map_)[keey] = (*this)[i + 1];
+    (*this->value_.map_)[keey] = (*this)[i + 1];
   }
   // erase the last one ("leftover")
   CZString keyLast(oldSize - 1);
-  ObjectValues::iterator itLast = value_.map_->find(keyLast);
-  value_.map_->erase(itLast);
+  ObjectValues::iterator itLast = this->value_.map_->find(keyLast);
+  this->value_.map_->erase(itLast);
   return true;
 }
 
 #ifdef JSON_USE_CPPTL
 Value Value::get(const CppTL::ConstString& key,
-                 const Value& defaultValue) const {
+                 const Value& defaultValue) const
+{
   return get(key.c_str(), key.end_c_str(), defaultValue);
 }
 #endif
 
 bool Value::isMember(char const* key, char const* cend) const
 {
-  Value const* value = find(key, cend);
+  Value const* value = this->find(key, cend);
   return NULL != value;
 }
 bool Value::isMember(char const* key) const
 {
-  return isMember(key, key + strlen(key));
+  return this->isMember(key, key + strlen(key));
 }
 bool Value::isMember(JSONCPP_STRING const& key) const
 {
-  return isMember(key.data(), key.data() + key.length());
+  return this->isMember(key.data(), key.data() + key.length());
 }
 
 #ifdef JSON_USE_CPPTL
-bool Value::isMember(const CppTL::ConstString& key) const {
+bool Value::isMember(const CppTL::ConstString& key) const
+{
   return isMember(key.c_str(), key.end_c_str());
 }
 #endif
 
-Value::Members Value::getMemberNames() const {
+Value::Members Value::getMemberNames() const
+{
   JSON_ASSERT_MESSAGE(
-      type_ == nullValue || type_ == objectValue,
-      "in Json::Value::getMemberNames(), value must be objectValue");
-  if (type_ == nullValue)
+    type_ == nullValue || type_ == objectValue,
+    "in Json::Value::getMemberNames(), value must be objectValue");
+  if (this->type_ == nullValue)
     return Value::Members();
   Members members;
-  members.reserve(value_.map_->size());
-  ObjectValues::const_iterator it = value_.map_->begin();
-  ObjectValues::const_iterator itEnd = value_.map_->end();
+  members.reserve(this->value_.map_->size());
+  ObjectValues::const_iterator it = this->value_.map_->begin();
+  ObjectValues::const_iterator itEnd = this->value_.map_->end();
   for (; it != itEnd; ++it) {
-    members.push_back(JSONCPP_STRING((*it).first.data(),
-                                  (*it).first.length()));
+    members.push_back(
+      JSONCPP_STRING((*it).first.data(), (*it).first.length()));
   }
   return members;
 }
@@ -1277,8 +1447,8 @@ Value::Members Value::getMemberNames() const {
 //   if ( type_ == objectValue )
 //   {
 //      return CppTL::Enum::any(  CppTL::Enum::transform(
-//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
-//         MemberNamesTransform() ) );
+//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>()
+//         ), MemberNamesTransform() ) );
 //   }
 //   return EnumMemberNames();
 //}
@@ -1295,99 +1465,114 @@ Value::Members Value::getMemberNames() const {
 //
 //# endif
 
-static bool IsIntegral(double d) {
+static bool IsIntegral(double d)
+{
   double integral_part;
   return modf(d, &integral_part) == 0.0;
 }
 
-bool Value::isNull() const { return type_ == nullValue; }
+bool Value::isNull() const
+{
+  return this->type_ == nullValue;
+}
 
-bool Value::isBool() const { return type_ == booleanValue; }
+bool Value::isBool() const
+{
+  return this->type_ == booleanValue;
+}
 
-bool Value::isInt() const {
-  switch (type_) {
-  case intValue:
+bool Value::isInt() const
+{
+  switch (this->type_) {
+    case intValue:
 #if defined(JSON_HAS_INT64)
-    return value_.int_ >= minInt && value_.int_ <= maxInt;
+      return this->value_.int_ >= minInt && this->value_.int_ <= maxInt;
 #else
-    return true;
+      return true;
 #endif
-  case uintValue:
-    return value_.uint_ <= UInt(maxInt);
-  case realValue:
-    return value_.real_ >= minInt && value_.real_ <= maxInt &&
-           IsIntegral(value_.real_);
-  default:
-    break;
+    case uintValue:
+      return this->value_.uint_ <= UInt(maxInt);
+    case realValue:
+      return this->value_.real_ >= minInt && this->value_.real_ <= maxInt &&
+        IsIntegral(this->value_.real_);
+    default:
+      break;
   }
   return false;
 }
 
-bool Value::isUInt() const {
-  switch (type_) {
-  case intValue:
+bool Value::isUInt() const
+{
+  switch (this->type_) {
+    case intValue:
 #if defined(JSON_HAS_INT64)
-    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+      return this->value_.int_ >= 0 &&
+        LargestUInt(this->value_.int_) <= LargestUInt(maxUInt);
 #else
-    return value_.int_ >= 0;
+      return value_.int_ >= 0;
 #endif
-  case uintValue:
+    case uintValue:
 #if defined(JSON_HAS_INT64)
-    return value_.uint_ <= maxUInt;
+      return this->value_.uint_ <= maxUInt;
 #else
-    return true;
+      return true;
 #endif
-  case realValue:
-    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
-           IsIntegral(value_.real_);
-  default:
-    break;
+    case realValue:
+      return this->value_.real_ >= 0 && this->value_.real_ <= maxUInt &&
+        IsIntegral(this->value_.real_);
+    default:
+      break;
   }
   return false;
 }
 
-bool Value::isInt64() const {
+bool Value::isInt64() const
+{
 #if defined(JSON_HAS_INT64)
-  switch (type_) {
-  case intValue:
-    return true;
-  case uintValue:
-    return value_.uint_ <= UInt64(maxInt64);
-  case realValue:
-    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
-    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
-    // require the value to be strictly less than the limit.
-    return value_.real_ >= double(minInt64) &&
-           value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
-  default:
-    break;
+  switch (this->type_) {
+    case intValue:
+      return true;
+    case uintValue:
+      return this->value_.uint_ <= UInt64(maxInt64);
+    case realValue:
+      // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+      // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+      // require the value to be strictly less than the limit.
+      return this->value_.real_ >= double(minInt64) &&
+        this->value_.real_ < double(maxInt64) &&
+        IsIntegral(this->value_.real_);
+    default:
+      break;
   }
 #endif // JSON_HAS_INT64
   return false;
 }
 
-bool Value::isUInt64() const {
+bool Value::isUInt64() const
+{
 #if defined(JSON_HAS_INT64)
-  switch (type_) {
-  case intValue:
-    return value_.int_ >= 0;
-  case uintValue:
-    return true;
-  case realValue:
-    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
-    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
-    // require the value to be strictly less than the limit.
-    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
-           IsIntegral(value_.real_);
-  default:
-    break;
+  switch (this->type_) {
+    case intValue:
+      return this->value_.int_ >= 0;
+    case uintValue:
+      return true;
+    case realValue:
+      // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+      // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+      // require the value to be strictly less than the limit.
+      return this->value_.real_ >= 0 &&
+        this->value_.real_ < maxUInt64AsDouble &&
+        IsIntegral(this->value_.real_);
+    default:
+      break;
   }
 #endif // JSON_HAS_INT64
   return false;
 }
 
-bool Value::isIntegral() const {
-  switch (type_) {
+bool Value::isIntegral() const
+{
+  switch (this->type_) {
     case intValue:
     case uintValue:
       return true;
@@ -1396,9 +1581,12 @@ bool Value::isIntegral() const {
       // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
       // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
       // require the value to be strictly less than the limit.
-      return value_.real_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
+      return this->value_.real_ >= double(minInt64) &&
+        this->value_.real_ < maxUInt64AsDouble &&
+        IsIntegral(this->value_.real_);
 #else
-      return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_);
+      return value_.real_ >= minInt && value_.real_ <= maxUInt &&
+        IsIntegral(value_.real_);
 #endif // JSON_HAS_INT64
     default:
       break;
@@ -1406,53 +1594,89 @@ bool Value::isIntegral() const {
   return false;
 }
 
-bool Value::isDouble() const { return type_ == intValue || type_ == uintValue || type_ == realValue; }
+bool Value::isDouble() const
+{
+  return this->type_ == intValue || this->type_ == uintValue ||
+    this->type_ == realValue;
+}
 
-bool Value::isNumeric() const { return isDouble(); }
+bool Value::isNumeric() const
+{
+  return this->isDouble();
+}
 
-bool Value::isString() const { return type_ == stringValue; }
+bool Value::isString() const
+{
+  return this->type_ == stringValue;
+}
 
-bool Value::isArray() const { return type_ == arrayValue; }
+bool Value::isArray() const
+{
+  return this->type_ == arrayValue;
+}
 
-bool Value::isObject() const { return type_ == objectValue; }
+bool Value::isObject() const
+{
+  return this->type_ == objectValue;
+}
 
-void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
-  if (!comments_)
-    comments_ = new CommentInfo[numberOfCommentPlacement];
-  if ((len > 0) && (comment[len-1] == '\n')) {
+void Value::setComment(const char* comment, size_t len,
+                       CommentPlacement placement)
+{
+  if (!this->comments_)
+    this->comments_ = new CommentInfo[numberOfCommentPlacement];
+  if ((len > 0) && (comment[len - 1] == '\n')) {
     // Always discard trailing newline, to aid indentation.
     len -= 1;
   }
-  comments_[placement].setComment(comment, len);
+  this->comments_[placement].setComment(comment, len);
 }
 
-void Value::setComment(const char* comment, CommentPlacement placement) {
-  setComment(comment, strlen(comment), placement);
+void Value::setComment(const char* comment, CommentPlacement placement)
+{
+  this->setComment(comment, strlen(comment), placement);
 }
 
-void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) {
-  setComment(comment.c_str(), comment.length(), placement);
+void Value::setComment(const JSONCPP_STRING& comment,
+                       CommentPlacement placement)
+{
+  this->setComment(comment.c_str(), comment.length(), placement);
 }
 
-bool Value::hasComment(CommentPlacement placement) const {
-  return comments_ != 0 && comments_[placement].comment_ != 0;
+bool Value::hasComment(CommentPlacement placement) const
+{
+  return this->comments_ != 0 && this->comments_[placement].comment_ != 0;
 }
 
-JSONCPP_STRING Value::getComment(CommentPlacement placement) const {
-  if (hasComment(placement))
-    return comments_[placement].comment_;
+JSONCPP_STRING Value::getComment(CommentPlacement placement) const
+{
+  if (this->hasComment(placement))
+    return this->comments_[placement].comment_;
   return "";
 }
 
-void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
+void Value::setOffsetStart(ptrdiff_t start)
+{
+  this->start_ = start;
+}
 
-void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
+void Value::setOffsetLimit(ptrdiff_t limit)
+{
+  this->limit_ = limit;
+}
 
-ptrdiff_t Value::getOffsetStart() const { return start_; }
+ptrdiff_t Value::getOffsetStart() const
+{
+  return this->start_;
+}
 
-ptrdiff_t Value::getOffsetLimit() const { return limit_; }
+ptrdiff_t Value::getOffsetLimit() const
+{
+  return this->limit_;
+}
 
-JSONCPP_STRING Value::toStyledString() const {
+JSONCPP_STRING Value::toStyledString() const
+{
   StreamWriterBuilder builder;
 
   JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : "";
@@ -1462,54 +1686,58 @@ JSONCPP_STRING Value::toStyledString() const {
   return out;
 }
 
-Value::const_iterator Value::begin() const {
-  switch (type_) {
-  case arrayValue:
-  case objectValue:
-    if (value_.map_)
-      return const_iterator(value_.map_->begin());
-    break;
-  default:
-    break;
+Value::const_iterator Value::begin() const
+{
+  switch (this->type_) {
+    case arrayValue:
+    case objectValue:
+      if (this->value_.map_)
+        return const_iterator(this->value_.map_->begin());
+      break;
+    default:
+      break;
   }
   return const_iterator();
 }
 
-Value::const_iterator Value::end() const {
-  switch (type_) {
-  case arrayValue:
-  case objectValue:
-    if (value_.map_)
-      return const_iterator(value_.map_->end());
-    break;
-  default:
-    break;
+Value::const_iterator Value::end() const
+{
+  switch (this->type_) {
+    case arrayValue:
+    case objectValue:
+      if (this->value_.map_)
+        return const_iterator(this->value_.map_->end());
+      break;
+    default:
+      break;
   }
   return const_iterator();
 }
 
-Value::iterator Value::begin() {
-  switch (type_) {
-  case arrayValue:
-  case objectValue:
-    if (value_.map_)
-      return iterator(value_.map_->begin());
-    break;
-  default:
-    break;
+Value::iterator Value::begin()
+{
+  switch (this->type_) {
+    case arrayValue:
+    case objectValue:
+      if (this->value_.map_)
+        return iterator(this->value_.map_->begin());
+      break;
+    default:
+      break;
   }
   return iterator();
 }
 
-Value::iterator Value::end() {
-  switch (type_) {
-  case arrayValue:
-  case objectValue:
-    if (value_.map_)
-      return iterator(value_.map_->end());
-    break;
-  default:
-    break;
+Value::iterator Value::end()
+{
+  switch (this->type_) {
+    case arrayValue:
+    case objectValue:
+      if (this->value_.map_)
+        return iterator(this->value_.map_->end());
+      break;
+    default:
+      break;
   }
   return iterator();
 }
@@ -1517,26 +1745,41 @@ Value::iterator Value::end() {
 // class PathArgument
 // //////////////////////////////////////////////////////////////////
 
-PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
+PathArgument::PathArgument()
+  : key_()
+  , index_()
+  , kind_(kindNone)
+{
+}
 
 PathArgument::PathArgument(ArrayIndex index)
-    : key_(), index_(index), kind_(kindIndex) {}
+  : key_()
+  , index_(index)
+  , kind_(kindIndex)
+{
+}
 
 PathArgument::PathArgument(const char* key)
-    : key_(key), index_(), kind_(kindKey) {}
+  : key_(key)
+  , index_()
+  , kind_(kindKey)
+{
+}
 
 PathArgument::PathArgument(const JSONCPP_STRING& key)
-    : key_(key.c_str()), index_(), kind_(kindKey) {}
+  : key_(key.c_str())
+  , index_()
+  , kind_(kindKey)
+{
+}
 
 // class Path
 // //////////////////////////////////////////////////////////////////
 
-Path::Path(const JSONCPP_STRING& path,
-           const PathArgument& a1,
-           const PathArgument& a2,
-           const PathArgument& a3,
-           const PathArgument& a4,
-           const PathArgument& a5) {
+Path::Path(const JSONCPP_STRING& path, const PathArgument& a1,
+           const PathArgument& a2, const PathArgument& a3,
+           const PathArgument& a4, const PathArgument& a5)
+{
   InArgs in;
   in.reserve(5);
   in.push_back(&a1);
@@ -1544,10 +1787,11 @@ Path::Path(const JSONCPP_STRING& path,
   in.push_back(&a3);
   in.push_back(&a4);
   in.push_back(&a5);
-  makePath(path, in);
+  this->makePath(path, in);
 }
 
-void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {
+void Path::makePath(const JSONCPP_STRING& path, const InArgs& in)
+{
   const char* current = path.c_str();
   const char* end = current + path.length();
   InArgs::const_iterator itInArg = in.begin();
@@ -1555,17 +1799,17 @@ void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {
     if (*current == '[') {
       ++current;
       if (*current == '%')
-        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+        this->addPathInArg(path, in, itInArg, PathArgument::kindIndex);
       else {
         ArrayIndex index = 0;
         for (; current != end && *current >= '0' && *current <= '9'; ++current)
           index = index * 10 + ArrayIndex(*current - '0');
-        args_.push_back(index);
+        this->args_.push_back(index);
       }
       if (current == end || *++current != ']')
-        invalidPath(path, int(current - path.c_str()));
+        this->invalidPath(path, int(current - path.c_str()));
     } else if (*current == '%') {
-      addPathInArg(path, in, itInArg, PathArgument::kindKey);
+      this->addPathInArg(path, in, itInArg, PathArgument::kindKey);
       ++current;
     } else if (*current == '.' || *current == ']') {
       ++current;
@@ -1573,31 +1817,34 @@ void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) {
       const char* beginName = current;
       while (current != end && !strchr("[.", *current))
         ++current;
-      args_.push_back(JSONCPP_STRING(beginName, current));
+      this->args_.push_back(JSONCPP_STRING(beginName, current));
     }
   }
 }
 
-void Path::addPathInArg(const JSONCPP_STRING& /*path*/,
-                        const InArgs& in,
+void Path::addPathInArg(const JSONCPP_STRING& /*path*/, const InArgs& in,
                         InArgs::const_iterator& itInArg,
-                        PathArgument::Kind kind) {
+                        PathArgument::Kind kind)
+{
   if (itInArg == in.end()) {
     // Error: missing argument %d
   } else if ((*itInArg)->kind_ != kind) {
     // Error: bad argument type
   } else {
-    args_.push_back(**itInArg++);
+    this->args_.push_back(**itInArg++);
   }
 }
 
-void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) {
+void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/)
+{
   // Error: invalid path.
 }
 
-const Value& Path::resolve(const Value& root) const {
+const Value& Path::resolve(const Value& root) const
+{
   const Value* node = &root;
-  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+  for (Args::const_iterator it = this->args_.begin(); it != this->args_.end();
+       ++it) {
     const PathArgument& arg = *it;
     if (arg.kind_ == PathArgument::kindIndex) {
       if (!node->isArray() || !node->isValidIndex(arg.index_)) {
@@ -1621,9 +1868,11 @@ const Value& Path::resolve(const Value& root) const {
   return *node;
 }
 
-Value Path::resolve(const Value& root, const Value& defaultValue) const {
+Value Path::resolve(const Value& root, const Value& defaultValue) const
+{
   const Value* node = &root;
-  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+  for (Args::const_iterator it = this->args_.begin(); it != this->args_.end();
+       ++it) {
     const PathArgument& arg = *it;
     if (arg.kind_ == PathArgument::kindIndex) {
       if (!node->isArray() || !node->isValidIndex(arg.index_))
@@ -1640,9 +1889,11 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
   return *node;
 }
 
-Value& Path::make(Value& root) const {
+Value& Path::make(Value& root) const
+{
   Value* node = &root;
-  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+  for (Args::const_iterator it = this->args_.begin(); it != this->args_.end();
+       ++it) {
     const PathArgument& arg = *it;
     if (arg.kind_ == PathArgument::kindIndex) {
       if (!node->isArray()) {
index fc86505..803cfab 100644 (file)
 // Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
 // Distributed under MIT license, or public domain if desired and
 // recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+// See file LICENSE for detail or copy at
+// http://jsoncpp.sourceforge.net/LICENSE
 
 #if !defined(JSON_IS_AMALGAMATION)
-#include <json/writer.h>
-#include "json_tool.h"
+#  include <json/writer.h>
+
+#  include "json_tool.h"
 #endif // if !defined(JSON_IS_AMALGAMATION)
+#include <cassert>
+#include <cstdio>
+#include <cstring>
 #include <iomanip>
 #include <memory>
+#include <set>
 #include <sstream>
 #include <utility>
-#include <set>
-#include <cassert>
-#include <cstring>
-#include <cstdio>
 
-#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
-#include <float.h>
-#define isfinite _finite
-#elif defined(__sun) && defined(__SVR4) //Solaris
-#if !defined(isfinite)
-#include <ieeefp.h>
-#define isfinite finite
-#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1200 &&                                  \
+  _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
+#  include <float.h>
+#  define isfinite _finite
+#elif defined(__sun) && defined(__SVR4) // Solaris
+#  if !defined(isfinite)
+#    include <ieeefp.h>
+#    define isfinite finite
+#  endif
 #elif defined(_AIX)
-#if !defined(isfinite)
-#include <math.h>
-#define isfinite finite
-#endif
+#  if !defined(isfinite)
+#    include <math.h>
+#    define isfinite finite
+#  endif
 #elif defined(__hpux)
-#if !defined(isfinite) && !defined(__GNUC__)
-#if defined(__ia64) && !defined(finite)
-#define isfinite(x) ((sizeof(x) == sizeof(float) ? \
-                     _Isfinitef(x) : _IsFinite(x)))
-#else
-#include <math.h>
-#define isfinite finite
-#endif
-#endif
+#  if !defined(isfinite) && !defined(__GNUC__)
+#    if defined(__ia64) && !defined(finite)
+#      define isfinite(x)                                                     \
+        ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
+#    else
+#      include <math.h>
+#      define isfinite finite
+#    endif
+#  endif
 #else
-#include <cmath>
-#if !(defined(__QNXNTO__)) // QNX already defines isfinite
-#define isfinite std::isfinite
-#endif
+#  include <cmath>
+#  if !(defined(__QNXNTO__)) // QNX already defines isfinite
+#    define isfinite std::isfinite
+#  endif
 #endif
 
 #if defined(_MSC_VER)
-#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
-#define snprintf sprintf_s
-#elif _MSC_VER >= 1900 // VC++ 14.0 and above
-#define snprintf std::snprintf
-#else
-#define snprintf _snprintf
-#endif
+#  if !defined(WINCE) && defined(__STDC_SECURE_LIB__) &&                      \
+    _MSC_VER >= 1500 // VC++ 9.0 and above
+#    define snprintf sprintf_s
+#  elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#    define snprintf std::snprintf
+#  else
+#    define snprintf _snprintf
+#  endif
 #elif defined(__ANDROID__) || defined(__QNXNTO__)
-#define snprintf snprintf
+#  define snprintf snprintf
 #elif __cplusplus >= 201103L
-#if !defined(__MINGW32__) && !defined(__CYGWIN__)
-#define snprintf std::snprintf
-#endif
+#  if !defined(__MINGW32__) && !defined(__CYGWIN__)
+#    define snprintf std::snprintf
+#  endif
 #endif
 
-#if defined(__BORLANDC__)  
-#include <float.h>
-#define isfinite _finite
-#define snprintf _snprintf
+#if defined(__BORLANDC__)
+#  include <float.h>
+#  define isfinite _finite
+#  define snprintf _snprintf
 #endif
 
 // Solaris
 #if defined(__sun)
-# include <ieeefp.h>
-# if !defined(isfinite)
-#  define isfinite finite
-# endif
+#  include <ieeefp.h>
+#  if !defined(isfinite)
+#    define isfinite finite
+#  endif
 #endif
 
 // AIX
 #if defined(_AIX)
-# if !defined(isfinite)
-#  define isfinite finite
-# endif
+#  if !defined(isfinite)
+#    define isfinite finite
+#  endif
 #endif
 
 // HP-UX
 #if defined(__hpux)
-# if !defined(isfinite)
-#  if defined(__ia64) && !defined(finite) && !defined(__GNUC__)
-#   define isfinite(x) ((sizeof(x) == sizeof(float) ? \
-                        _Isfinitef(x) : _Isfinite(x)))
-#  else
-#   include <math.h>
-#   define isfinite finite
+#  if !defined(isfinite)
+#    if defined(__ia64) && !defined(finite) && !defined(__GNUC__)
+#      define isfinite(x)                                                     \
+        ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _Isfinite(x)))
+#    else
+#      include <math.h>
+#      define isfinite finite
+#    endif
 #  endif
-# endif
 #endif
 
 // Ancient glibc
 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
-# if !defined(isfinite)
-#  define isfinite __finite
-# endif
+#  if !defined(isfinite)
+#    define isfinite __finite
+#  endif
 #endif
 
 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
 // Disable warning about strdup being deprecated.
-#pragma warning(disable : 4996)
+#  pragma warning(disable : 4996)
 #endif
 
 namespace Json {
@@ -113,10 +117,11 @@ namespace Json {
 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
 typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
 #else
-typedef std::auto_ptr<StreamWriter>   StreamWriterPtr;
+typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
 #endif
 
-static bool containsControlCharacter(const char* str) {
+static bool containsControlCharacter(const char* str)
+{
   while (*str) {
     if (isControlCharacter(*(str++)))
       return true;
@@ -124,17 +129,19 @@ static bool containsControlCharacter(const char* str) {
   return false;
 }
 
-static bool containsControlCharacter0(const char* str, unsigned len) {
+static bool containsControlCharacter0(const char* str, unsigned len)
+{
   char const* end = str + len;
   while (end != str) {
-    if (isControlCharacter(*str) || 0==*str)
+    if (isControlCharacter(*str) || 0 == *str)
       return true;
     ++str;
   }
   return false;
 }
 
-JSONCPP_STRING valueToString(LargestInt value) {
+JSONCPP_STRING valueToString(LargestInt value)
+{
   UIntToStringBuffer buffer;
   char* current = buffer + sizeof(buffer);
   if (value == Value::minLargestInt) {
@@ -150,7 +157,8 @@ JSONCPP_STRING valueToString(LargestInt value) {
   return current;
 }
 
-JSONCPP_STRING valueToString(LargestUInt value) {
+JSONCPP_STRING valueToString(LargestUInt value)
+{
   UIntToStringBuffer buffer;
   char* current = buffer + sizeof(buffer);
   uintToString(value, current);
@@ -160,18 +168,22 @@ JSONCPP_STRING valueToString(LargestUInt value) {
 
 #if defined(JSON_HAS_INT64)
 
-JSONCPP_STRING valueToString(Int value) {
+JSONCPP_STRING valueToString(Int value)
+{
   return valueToString(LargestInt(value));
 }
 
-JSONCPP_STRING valueToString(UInt value) {
+JSONCPP_STRING valueToString(UInt value)
+{
   return valueToString(LargestUInt(value));
 }
 
 #endif // # if defined(JSON_HAS_INT64)
 
 namespace {
-JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
+JSONCPP_STRING valueToString(double value, bool useSpecialFloats,
+                             unsigned int precision)
+{
   // Allocate a buffer that is more than large enough to store the 16 digits of
   // precision requested below.
   char buffer[36];
@@ -187,7 +199,8 @@ JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int p
     len = snprintf(buffer, sizeof(buffer), formatString, value);
     fixNumericLocale(buffer, buffer + len);
 
-    // try to ensure we preserve the fact that this was given to us as a double on input
+    // try to ensure we preserve the fact that this was given to us as a double
+    // on input
     if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
       strcat(buffer, ".0");
     }
@@ -195,11 +208,14 @@ JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int p
   } else {
     // IEEE standard states that NaN values will not compare to themselves
     if (value != value) {
-      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
+      len =
+        snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
     } else if (value < 0) {
-      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
+      len = snprintf(buffer, sizeof(buffer),
+                     useSpecialFloats ? "-Infinity" : "-1e+9999");
     } else {
-      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
+      len = snprintf(buffer, sizeof(buffer),
+                     useSpecialFloats ? "Infinity" : "1e+9999");
     }
   }
   assert(len >= 0);
@@ -207,11 +223,18 @@ JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int p
 }
 }
 
-JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
+JSONCPP_STRING valueToString(double value)
+{
+  return valueToString(value, false, 17);
+}
 
-JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
+JSONCPP_STRING valueToString(bool value)
+{
+  return value ? "true" : "false";
+}
 
-JSONCPP_STRING valueToQuotedString(const char* value) {
+JSONCPP_STRING valueToQuotedString(const char* value)
+{
   if (value == NULL)
     return "";
   // Not sure how to handle unicode...
@@ -222,51 +245,50 @@ JSONCPP_STRING valueToQuotedString(const char* value) {
   // Appending to JSONCPP_STRING is not efficient, but this should be rare.
   // (Note: forward slashes are *not* rare, but I am not escaping them.)
   JSONCPP_STRING::size_type maxsize =
-      strlen(value) * 2 + 3; // allescaped+quotes+NULL
+    strlen(value) * 2 + 3; // allescaped+quotes+NULL
   JSONCPP_STRING result;
   result.reserve(maxsize); // to avoid lots of mallocs
   result += "\"";
   for (const char* c = value; *c != 0; ++c) {
     switch (*c) {
-    case '\"':
-      result += "\\\"";
-      break;
-    case '\\':
-      result += "\\\\";
-      break;
-    case '\b':
-      result += "\\b";
-      break;
-    case '\f':
-      result += "\\f";
-      break;
-    case '\n':
-      result += "\\n";
-      break;
-    case '\r':
-      result += "\\r";
-      break;
-    case '\t':
-      result += "\\t";
-      break;
-    // case '/':
-    // Even though \/ is considered a legal escape in JSON, a bare
-    // slash is also legal, so I see no reason to escape it.
-    // (I hope I am not misunderstanding something.
-    // blep notes: actually escaping \/ may be useful in javascript to avoid </
-    // sequence.
-    // Should add a flag to allow this compatibility mode and prevent this
-    // sequence from occurring.
-    default:
-      if (isControlCharacter(*c)) {
-        JSONCPP_OSTRINGSTREAM oss;
-        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
-            << std::setw(4) << static_cast<int>(*c);
-        result += oss.str();
-      } else {
-        result += *c;
-      }
-      break;
+      case '\"':
+        result += "\\\"";
+        break;
+      case '\\':
+        result += "\\\\";
+        break;
+      case '\b':
+        result += "\\b";
+        break;
+      case '\f':
+        result += "\\f";
+        break;
+      case '\n':
+        result += "\\n";
+        break;
+      case '\r':
+        result += "\\r";
+        break;
+      case '\t':
+        result += "\\t";
+        break;
+      // case '/':
+      // Even though \/ is considered a legal escape in JSON, a bare
+      // slash is also legal, so I see no reason to escape it.
+      // (I hope I am not misunderstanding something.
+      // blep notes: actually escaping \/ may be useful in javascript to avoid
+      // </ sequence. Should add a flag to allow this compatibility mode and
+      // prevent this sequence from occurring.
+      default:
+        if (isControlCharacter(*c)) {
+          JSONCPP_OSTRINGSTREAM oss;
+          oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+              << std::setw(4) << static_cast<int>(*c);
+          result += oss.str();
+        } else {
+          result += *c;
+        }
+        break;
     }
   }
   result += "\"";
@@ -274,7 +296,8 @@ JSONCPP_STRING valueToQuotedString(const char* value) {
 }
 
 // https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
-static char const* strnpbrk(char const* s, char const* accept, size_t n) {
+static char const* strnpbrk(char const* s, char const* accept, size_t n)
+{
   assert((s || !n) && accept);
 
   char const* const end = s + n;
@@ -288,7 +311,8 @@ static char const* strnpbrk(char const* s, char const* accept, size_t n) {
   }
   return NULL;
 }
-static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
+static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length)
+{
   if (value == NULL)
     return "";
   // Not sure how to handle unicode...
@@ -298,53 +322,51 @@ static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
   // We have to walk value and escape any special characters.
   // Appending to JSONCPP_STRING is not efficient, but this should be rare.
   // (Note: forward slashes are *not* rare, but I am not escaping them.)
-  JSONCPP_STRING::size_type maxsize =
-      length * 2 + 3; // allescaped+quotes+NULL
+  JSONCPP_STRING::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL
   JSONCPP_STRING result;
   result.reserve(maxsize); // to avoid lots of mallocs
   result += "\"";
   char const* end = value + length;
   for (const char* c = value; c != end; ++c) {
     switch (*c) {
-    case '\"':
-      result += "\\\"";
-      break;
-    case '\\':
-      result += "\\\\";
-      break;
-    case '\b':
-      result += "\\b";
-      break;
-    case '\f':
-      result += "\\f";
-      break;
-    case '\n':
-      result += "\\n";
-      break;
-    case '\r':
-      result += "\\r";
-      break;
-    case '\t':
-      result += "\\t";
-      break;
-    // case '/':
-    // Even though \/ is considered a legal escape in JSON, a bare
-    // slash is also legal, so I see no reason to escape it.
-    // (I hope I am not misunderstanding something.)
-    // blep notes: actually escaping \/ may be useful in javascript to avoid </
-    // sequence.
-    // Should add a flag to allow this compatibility mode and prevent this
-    // sequence from occurring.
-    default:
-      if ((isControlCharacter(*c)) || (*c == 0)) {
-        JSONCPP_OSTRINGSTREAM oss;
-        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
-            << std::setw(4) << static_cast<int>(*c);
-        result += oss.str();
-      } else {
-        result += *c;
-      }
-      break;
+      case '\"':
+        result += "\\\"";
+        break;
+      case '\\':
+        result += "\\\\";
+        break;
+      case '\b':
+        result += "\\b";
+        break;
+      case '\f':
+        result += "\\f";
+        break;
+      case '\n':
+        result += "\\n";
+        break;
+      case '\r':
+        result += "\\r";
+        break;
+      case '\t':
+        result += "\\t";
+        break;
+      // case '/':
+      // Even though \/ is considered a legal escape in JSON, a bare
+      // slash is also legal, so I see no reason to escape it.
+      // (I hope I am not misunderstanding something.)
+      // blep notes: actually escaping \/ may be useful in javascript to avoid
+      // </ sequence. Should add a flag to allow this compatibility mode and
+      // prevent this sequence from occurring.
+      default:
+        if ((isControlCharacter(*c)) || (*c == 0)) {
+          JSONCPP_OSTRINGSTREAM oss;
+          oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+              << std::setw(4) << static_cast<int>(*c);
+          result += oss.str();
+        } else {
+          result += *c;
+        }
+        break;
     }
   }
   result += "\"";
@@ -353,80 +375,98 @@ static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) {
 
 // Class Writer
 // //////////////////////////////////////////////////////////////////
-Writer::~Writer() {}
+Writer::~Writer()
+{
+}
 
 // Class FastWriter
 // //////////////////////////////////////////////////////////////////
 
 FastWriter::FastWriter()
-    : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
-      omitEndingLineFeed_(false) {}
+  : yamlCompatiblityEnabled_(false)
+  , dropNullPlaceholders_(false)
+  , omitEndingLineFeed_(false)
+{
+}
 
-void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
+void FastWriter::enableYAMLCompatibility()
+{
+  this->yamlCompatiblityEnabled_ = true;
+}
 
-void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
+void FastWriter::dropNullPlaceholders()
+{
+  this->dropNullPlaceholders_ = true;
+}
 
-void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
+void FastWriter::omitEndingLineFeed()
+{
+  this->omitEndingLineFeed_ = true;
+}
 
-JSONCPP_STRING FastWriter::write(const Value& root) {
-  document_.clear();
-  writeValue(root);
-  if (!omitEndingLineFeed_)
-    document_ += "\n";
-  return document_;
+JSONCPP_STRING FastWriter::write(const Value& root)
+{
+  this->document_.clear();
+  this->writeValue(root);
+  if (!this->omitEndingLineFeed_)
+    this->document_ += "\n";
+  return this->document_;
 }
 
-void FastWriter::writeValue(const Value& value) {
+void FastWriter::writeValue(const Value& value)
+{
   switch (value.type()) {
-  case nullValue:
-    if (!dropNullPlaceholders_)
-      document_ += "null";
-    break;
-  case intValue:
-    document_ += valueToString(value.asLargestInt());
-    break;
-  case uintValue:
-    document_ += valueToString(value.asLargestUInt());
-    break;
-  case realValue:
-    document_ += valueToString(value.asDouble());
-    break;
-  case stringValue:
-  {
-    // Is NULL possible for value.string_? No.
-    char const* str;
-    char const* end;
-    bool ok = value.getString(&str, &end);
-    if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
-    break;
-  }
-  case booleanValue:
-    document_ += valueToString(value.asBool());
-    break;
-  case arrayValue: {
-    document_ += '[';
-    ArrayIndex size = value.size();
-    for (ArrayIndex index = 0; index < size; ++index) {
-      if (index > 0)
-        document_ += ',';
-      writeValue(value[index]);
-    }
-    document_ += ']';
-  } break;
-  case objectValue: {
-    Value::Members members(value.getMemberNames());
-    document_ += '{';
-    for (Value::Members::iterator it = members.begin(); it != members.end();
-         ++it) {
-      const JSONCPP_STRING& name = *it;
-      if (it != members.begin())
-        document_ += ',';
-      document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
-      document_ += yamlCompatiblityEnabled_ ? ": " : ":";
-      writeValue(value[name]);
+    case nullValue:
+      if (!this->dropNullPlaceholders_)
+        this->document_ += "null";
+      break;
+    case intValue:
+      this->document_ += valueToString(value.asLargestInt());
+      break;
+    case uintValue:
+      this->document_ += valueToString(value.asLargestUInt());
+      break;
+    case realValue:
+      this->document_ += valueToString(value.asDouble());
+      break;
+    case stringValue: {
+      // Is NULL possible for value.string_? No.
+      char const* str;
+      char const* end;
+      bool ok = value.getString(&str, &end);
+      if (ok)
+        this->document_ +=
+          valueToQuotedStringN(str, static_cast<unsigned>(end - str));
+      break;
     }
-    document_ += '}';
-  } break;
+    case booleanValue:
+      this->document_ += valueToString(value.asBool());
+      break;
+    case arrayValue: {
+      this->document_ += '[';
+      ArrayIndex size = value.size();
+      for (ArrayIndex index = 0; index < size; ++index) {
+        if (index > 0)
+          this->document_ += ',';
+        this->writeValue(value[index]);
+      }
+      this->document_ += ']';
+    } break;
+    case objectValue: {
+      Value::Members members(value.getMemberNames());
+      this->document_ += '{';
+      for (Value::Members::iterator it = members.begin(); it != members.end();
+           ++it) {
+        const JSONCPP_STRING& name = *it;
+        if (it != members.begin())
+          this->document_ += ',';
+        this->document_ += valueToQuotedStringN(
+          name.data(), static_cast<unsigned>(name.length()));
+        this->document_ += this->yamlCompatiblityEnabled_ ? ": " : ":";
+        this->writeValue(value[name]);
+      }
+      this->document_ += '}';
+    } break;
   }
 }
 
@@ -434,454 +474,498 @@ void FastWriter::writeValue(const Value& value) {
 // //////////////////////////////////////////////////////////////////
 
 StyledWriter::StyledWriter()
-    : rightMargin_(74), indentSize_(3), addChildValues_() {}
+  : rightMargin_(74)
+  , indentSize_(3)
+  , addChildValues_()
+{
+}
 
-JSONCPP_STRING StyledWriter::write(const Value& root) {
-  document_.clear();
-  addChildValues_ = false;
-  indentString_.clear();
-  writeCommentBeforeValue(root);
-  writeValue(root);
-  writeCommentAfterValueOnSameLine(root);
-  document_ += "\n";
-  return document_;
+JSONCPP_STRING StyledWriter::write(const Value& root)
+{
+  this->document_.clear();
+  this->addChildValues_ = false;
+  this->indentString_.clear();
+  this->writeCommentBeforeValue(root);
+  this->writeValue(root);
+  this->writeCommentAfterValueOnSameLine(root);
+  this->document_ += "\n";
+  return this->document_;
 }
 
-void StyledWriter::writeValue(const Value& value) {
+void StyledWriter::writeValue(const Value& value)
+{
   switch (value.type()) {
-  case nullValue:
-    pushValue("null");
-    break;
-  case intValue:
-    pushValue(valueToString(value.asLargestInt()));
-    break;
-  case uintValue:
-    pushValue(valueToString(value.asLargestUInt()));
-    break;
-  case realValue:
-    pushValue(valueToString(value.asDouble()));
-    break;
-  case stringValue:
-  {
-    // Is NULL possible for value.string_? No.
-    char const* str;
-    char const* end;
-    bool ok = value.getString(&str, &end);
-    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
-    else pushValue("");
-    break;
-  }
-  case booleanValue:
-    pushValue(valueToString(value.asBool()));
-    break;
-  case arrayValue:
-    writeArrayValue(value);
-    break;
-  case objectValue: {
-    Value::Members members(value.getMemberNames());
-    if (members.empty())
-      pushValue("{}");
-    else {
-      writeWithIndent("{");
-      indent();
-      Value::Members::iterator it = members.begin();
-      for (;;) {
-        const JSONCPP_STRING& name = *it;
-        const Value& childValue = value[name];
-        writeCommentBeforeValue(childValue);
-        writeWithIndent(valueToQuotedString(name.c_str()));
-        document_ += " : ";
-        writeValue(childValue);
-        if (++it == members.end()) {
-          writeCommentAfterValueOnSameLine(childValue);
-          break;
+    case nullValue:
+      this->pushValue("null");
+      break;
+    case intValue:
+      this->pushValue(valueToString(value.asLargestInt()));
+      break;
+    case uintValue:
+      this->pushValue(valueToString(value.asLargestUInt()));
+      break;
+    case realValue:
+      this->pushValue(valueToString(value.asDouble()));
+      break;
+    case stringValue: {
+      // Is NULL possible for value.string_? No.
+      char const* str;
+      char const* end;
+      bool ok = value.getString(&str, &end);
+      if (ok)
+        this->pushValue(
+          valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+      else
+        this->pushValue("");
+      break;
+    }
+    case booleanValue:
+      this->pushValue(valueToString(value.asBool()));
+      break;
+    case arrayValue:
+      this->writeArrayValue(value);
+      break;
+    case objectValue: {
+      Value::Members members(value.getMemberNames());
+      if (members.empty())
+        this->pushValue("{}");
+      else {
+        this->writeWithIndent("{");
+        this->indent();
+        Value::Members::iterator it = members.begin();
+        for (;;) {
+          const JSONCPP_STRING& name = *it;
+          const Value& childValue = value[name];
+          this->writeCommentBeforeValue(childValue);
+          this->writeWithIndent(valueToQuotedString(name.c_str()));
+          this->document_ += " : ";
+          this->writeValue(childValue);
+          if (++it == members.end()) {
+            this->writeCommentAfterValueOnSameLine(childValue);
+            break;
+          }
+          this->document_ += ',';
+          this->writeCommentAfterValueOnSameLine(childValue);
         }
-        document_ += ',';
-        writeCommentAfterValueOnSameLine(childValue);
+        this->unindent();
+        this->writeWithIndent("}");
       }
-      unindent();
-      writeWithIndent("}");
-    }
-  } break;
+    } break;
   }
 }
 
-void StyledWriter::writeArrayValue(const Value& value) {
+void StyledWriter::writeArrayValue(const Value& value)
+{
   unsigned size = value.size();
   if (size == 0)
-    pushValue("[]");
+    this->pushValue("[]");
   else {
-    bool isArrayMultiLine = isMultineArray(value);
+    bool isArrayMultiLine = this->isMultineArray(value);
     if (isArrayMultiLine) {
-      writeWithIndent("[");
-      indent();
-      bool hasChildValue = !childValues_.empty();
+      this->writeWithIndent("[");
+      this->indent();
+      bool hasChildValue = !this->childValues_.empty();
       unsigned index = 0;
       for (;;) {
         const Value& childValue = value[index];
-        writeCommentBeforeValue(childValue);
+        this->writeCommentBeforeValue(childValue);
         if (hasChildValue)
-          writeWithIndent(childValues_[index]);
+          this->writeWithIndent(this->childValues_[index]);
         else {
-          writeIndent();
-          writeValue(childValue);
+          this->writeIndent();
+          this->writeValue(childValue);
         }
         if (++index == size) {
-          writeCommentAfterValueOnSameLine(childValue);
+          this->writeCommentAfterValueOnSameLine(childValue);
           break;
         }
-        document_ += ',';
-        writeCommentAfterValueOnSameLine(childValue);
+        this->document_ += ',';
+        this->writeCommentAfterValueOnSameLine(childValue);
       }
-      unindent();
-      writeWithIndent("]");
+      this->unindent();
+      this->writeWithIndent("]");
     } else // output on a single line
     {
-      assert(childValues_.size() == size);
-      document_ += "[ ";
+      assert(this->childValues_.size() == size);
+      this->document_ += "[ ";
       for (unsigned index = 0; index < size; ++index) {
         if (index > 0)
-          document_ += ", ";
-        document_ += childValues_[index];
+          this->document_ += ", ";
+        this->document_ += this->childValues_[index];
       }
-      document_ += " ]";
+      this->document_ += " ]";
     }
   }
 }
 
-bool StyledWriter::isMultineArray(const Value& value) {
+bool StyledWriter::isMultineArray(const Value& value)
+{
   ArrayIndex const size = value.size();
-  bool isMultiLine = size * 3 >= rightMargin_;
-  childValues_.clear();
+  bool isMultiLine = size * 3 >= this->rightMargin_;
+  this->childValues_.clear();
   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     const Value& childValue = value[index];
     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
-                        childValue.size() > 0);
+                   childValue.size() > 0);
   }
   if (!isMultiLine) // check if line length > max line length
   {
-    childValues_.reserve(size);
-    addChildValues_ = true;
+    this->childValues_.reserve(size);
+    this->addChildValues_ = true;
     ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
     for (ArrayIndex index = 0; index < size; ++index) {
-      if (hasCommentForValue(value[index])) {
+      if (this->hasCommentForValue(value[index])) {
         isMultiLine = true;
       }
-      writeValue(value[index]);
-      lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+      this->writeValue(value[index]);
+      lineLength +=
+        static_cast<ArrayIndex>(this->childValues_[index].length());
     }
-    addChildValues_ = false;
-    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+    this->addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= this->rightMargin_;
   }
   return isMultiLine;
 }
 
-void StyledWriter::pushValue(const JSONCPP_STRING& value) {
-  if (addChildValues_)
-    childValues_.push_back(value);
+void StyledWriter::pushValue(const JSONCPP_STRING& value)
+{
+  if (this->addChildValues_)
+    this->childValues_.push_back(value);
   else
-    document_ += value;
+    this->document_ += value;
 }
 
-void StyledWriter::writeIndent() {
-  if (!document_.empty()) {
-    char last = document_[document_.length() - 1];
+void StyledWriter::writeIndent()
+{
+  if (!this->document_.empty()) {
+    char last = this->document_[this->document_.length() - 1];
     if (last == ' ') // already indented
       return;
     if (last != '\n') // Comments may add new-line
-      document_ += '\n';
+      this->document_ += '\n';
   }
-  document_ += indentString_;
+  this->document_ += this->indentString_;
 }
 
-void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) {
-  writeIndent();
-  document_ += value;
+void StyledWriter::writeWithIndent(const JSONCPP_STRING& value)
+{
+  this->writeIndent();
+  this->document_ += value;
 }
 
-void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); }
+void StyledWriter::indent()
+{
+  this->indentString_ += JSONCPP_STRING(this->indentSize_, ' ');
+}
 
-void StyledWriter::unindent() {
-  assert(indentString_.size() >= indentSize_);
-  indentString_.resize(indentString_.size() - indentSize_);
+void StyledWriter::unindent()
+{
+  assert(this->indentString_.size() >= this->indentSize_);
+  this->indentString_.resize(this->indentString_.size() - this->indentSize_);
 }
 
-void StyledWriter::writeCommentBeforeValue(const Value& root) {
+void StyledWriter::writeCommentBeforeValue(const Value& root)
+{
   if (!root.hasComment(commentBefore))
     return;
 
-  document_ += "\n";
-  writeIndent();
+  this->document_ += "\n";
+  this->writeIndent();
   const JSONCPP_STRING& comment = root.getComment(commentBefore);
   JSONCPP_STRING::const_iterator iter = comment.begin();
   while (iter != comment.end()) {
-    document_ += *iter;
-    if (*iter == '\n' &&
-       (iter != comment.end() && *(iter + 1) == '/'))
-      writeIndent();
+    this->document_ += *iter;
+    if (*iter == '\n' && (iter != comment.end() && *(iter + 1) == '/'))
+      this->writeIndent();
     ++iter;
   }
 
   // Comments are stripped of trailing newlines, so add one here
-  document_ += "\n";
+  this->document_ += "\n";
 }
 
-void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root)
+{
   if (root.hasComment(commentAfterOnSameLine))
-    document_ += " " + root.getComment(commentAfterOnSameLine);
+    this->document_ += " " + root.getComment(commentAfterOnSameLine);
 
   if (root.hasComment(commentAfter)) {
-    document_ += "\n";
-    document_ += root.getComment(commentAfter);
-    document_ += "\n";
+    this->document_ += "\n";
+    this->document_ += root.getComment(commentAfter);
+    this->document_ += "\n";
   }
 }
 
-bool StyledWriter::hasCommentForValue(const Value& value) {
+bool StyledWriter::hasCommentForValue(const Value& value)
+{
   return value.hasComment(commentBefore) ||
-         value.hasComment(commentAfterOnSameLine) ||
-         value.hasComment(commentAfter);
+    value.hasComment(commentAfterOnSameLine) || value.hasComment(commentAfter);
 }
 
 // Class StyledStreamWriter
 // //////////////////////////////////////////////////////////////////
 
 StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation)
-    : document_(NULL), rightMargin_(74), indentation_(indentation),
-      addChildValues_() {}
-
-void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) {
-  document_ = &out;
-  addChildValues_ = false;
-  indentString_.clear();
-  indented_ = true;
-  writeCommentBeforeValue(root);
-  if (!indented_) writeIndent();
-  indented_ = true;
-  writeValue(root);
-  writeCommentAfterValueOnSameLine(root);
-  *document_ << "\n";
-  document_ = NULL; // Forget the stream, for safety.
-}
-
-void StyledStreamWriter::writeValue(const Value& value) {
+  : document_(NULL)
+  , rightMargin_(74)
+  , indentation_(indentation)
+  , addChildValues_()
+{
+}
+
+void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root)
+{
+  this->document_ = &out;
+  this->addChildValues_ = false;
+  this->indentString_.clear();
+  this->indented_ = true;
+  this->writeCommentBeforeValue(root);
+  if (!this->indented_)
+    this->writeIndent();
+  this->indented_ = true;
+  this->writeValue(root);
+  this->writeCommentAfterValueOnSameLine(root);
+  *this->document_ << "\n";
+  this->document_ = NULL; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value& value)
+{
   switch (value.type()) {
-  case nullValue:
-    pushValue("null");
-    break;
-  case intValue:
-    pushValue(valueToString(value.asLargestInt()));
-    break;
-  case uintValue:
-    pushValue(valueToString(value.asLargestUInt()));
-    break;
-  case realValue:
-    pushValue(valueToString(value.asDouble()));
-    break;
-  case stringValue:
-  {
-    // Is NULL possible for value.string_? No.
-    char const* str;
-    char const* end;
-    bool ok = value.getString(&str, &end);
-    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
-    else pushValue("");
-    break;
-  }
-  case booleanValue:
-    pushValue(valueToString(value.asBool()));
-    break;
-  case arrayValue:
-    writeArrayValue(value);
-    break;
-  case objectValue: {
-    Value::Members members(value.getMemberNames());
-    if (members.empty())
-      pushValue("{}");
-    else {
-      writeWithIndent("{");
-      indent();
-      Value::Members::iterator it = members.begin();
-      for (;;) {
-        const JSONCPP_STRING& name = *it;
-        const Value& childValue = value[name];
-        writeCommentBeforeValue(childValue);
-        writeWithIndent(valueToQuotedString(name.c_str()));
-        *document_ << " : ";
-        writeValue(childValue);
-        if (++it == members.end()) {
-          writeCommentAfterValueOnSameLine(childValue);
-          break;
+    case nullValue:
+      this->pushValue("null");
+      break;
+    case intValue:
+      this->pushValue(valueToString(value.asLargestInt()));
+      break;
+    case uintValue:
+      this->pushValue(valueToString(value.asLargestUInt()));
+      break;
+    case realValue:
+      this->pushValue(valueToString(value.asDouble()));
+      break;
+    case stringValue: {
+      // Is NULL possible for value.string_? No.
+      char const* str;
+      char const* end;
+      bool ok = value.getString(&str, &end);
+      if (ok)
+        this->pushValue(
+          valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+      else
+        this->pushValue("");
+      break;
+    }
+    case booleanValue:
+      this->pushValue(valueToString(value.asBool()));
+      break;
+    case arrayValue:
+      this->writeArrayValue(value);
+      break;
+    case objectValue: {
+      Value::Members members(value.getMemberNames());
+      if (members.empty())
+        this->pushValue("{}");
+      else {
+        this->writeWithIndent("{");
+        this->indent();
+        Value::Members::iterator it = members.begin();
+        for (;;) {
+          const JSONCPP_STRING& name = *it;
+          const Value& childValue = value[name];
+          this->writeCommentBeforeValue(childValue);
+          this->writeWithIndent(valueToQuotedString(name.c_str()));
+          *this->document_ << " : ";
+          this->writeValue(childValue);
+          if (++it == members.end()) {
+            this->writeCommentAfterValueOnSameLine(childValue);
+            break;
+          }
+          *this->document_ << ",";
+          this->writeCommentAfterValueOnSameLine(childValue);
         }
-        *document_ << ",";
-        writeCommentAfterValueOnSameLine(childValue);
+        this->unindent();
+        this->writeWithIndent("}");
       }
-      unindent();
-      writeWithIndent("}");
-    }
-  } break;
+    } break;
   }
 }
 
-void StyledStreamWriter::writeArrayValue(const Value& value) {
+void StyledStreamWriter::writeArrayValue(const Value& value)
+{
   unsigned size = value.size();
   if (size == 0)
-    pushValue("[]");
+    this->pushValue("[]");
   else {
-    bool isArrayMultiLine = isMultineArray(value);
+    bool isArrayMultiLine = this->isMultineArray(value);
     if (isArrayMultiLine) {
-      writeWithIndent("[");
-      indent();
-      bool hasChildValue = !childValues_.empty();
+      this->writeWithIndent("[");
+      this->indent();
+      bool hasChildValue = !this->childValues_.empty();
       unsigned index = 0;
       for (;;) {
         const Value& childValue = value[index];
-        writeCommentBeforeValue(childValue);
+        this->writeCommentBeforeValue(childValue);
         if (hasChildValue)
-          writeWithIndent(childValues_[index]);
+          this->writeWithIndent(this->childValues_[index]);
         else {
-          if (!indented_) writeIndent();
-          indented_ = true;
-          writeValue(childValue);
-          indented_ = false;
+          if (!this->indented_)
+            this->writeIndent();
+          this->indented_ = true;
+          this->writeValue(childValue);
+          this->indented_ = false;
         }
         if (++index == size) {
-          writeCommentAfterValueOnSameLine(childValue);
+          this->writeCommentAfterValueOnSameLine(childValue);
           break;
         }
-        *document_ << ",";
-        writeCommentAfterValueOnSameLine(childValue);
+        *this->document_ << ",";
+        this->writeCommentAfterValueOnSameLine(childValue);
       }
-      unindent();
-      writeWithIndent("]");
+      this->unindent();
+      this->writeWithIndent("]");
     } else // output on a single line
     {
-      assert(childValues_.size() == size);
-      *document_ << "[ ";
+      assert(this->childValues_.size() == size);
+      *this->document_ << "[ ";
       for (unsigned index = 0; index < size; ++index) {
         if (index > 0)
-          *document_ << ", ";
-        *document_ << childValues_[index];
+          *this->document_ << ", ";
+        *this->document_ << this->childValues_[index];
       }
-      *document_ << " ]";
+      *this->document_ << " ]";
     }
   }
 }
 
-bool StyledStreamWriter::isMultineArray(const Value& value) {
+bool StyledStreamWriter::isMultineArray(const Value& value)
+{
   ArrayIndex const size = value.size();
-  bool isMultiLine = size * 3 >= rightMargin_;
-  childValues_.clear();
+  bool isMultiLine = size * 3 >= this->rightMargin_;
+  this->childValues_.clear();
   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     const Value& childValue = value[index];
     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
-                        childValue.size() > 0);
+                   childValue.size() > 0);
   }
   if (!isMultiLine) // check if line length > max line length
   {
-    childValues_.reserve(size);
-    addChildValues_ = true;
+    this->childValues_.reserve(size);
+    this->addChildValues_ = true;
     ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
     for (ArrayIndex index = 0; index < size; ++index) {
-      if (hasCommentForValue(value[index])) {
+      if (this->hasCommentForValue(value[index])) {
         isMultiLine = true;
       }
-      writeValue(value[index]);
-      lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+      this->writeValue(value[index]);
+      lineLength +=
+        static_cast<ArrayIndex>(this->childValues_[index].length());
     }
-    addChildValues_ = false;
-    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+    this->addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= this->rightMargin_;
   }
   return isMultiLine;
 }
 
-void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) {
-  if (addChildValues_)
-    childValues_.push_back(value);
+void StyledStreamWriter::pushValue(const JSONCPP_STRING& value)
+{
+  if (this->addChildValues_)
+    this->childValues_.push_back(value);
   else
-    *document_ << value;
+    *this->document_ << value;
 }
 
-void StyledStreamWriter::writeIndent() {
+void StyledStreamWriter::writeIndent()
+{
   // blep intended this to look at the so-far-written string
   // to determine whether we are already indented, but
   // with a stream we cannot do that. So we rely on some saved state.
   // The caller checks indented_.
-  *document_ << '\n' << indentString_;
+  *this->document_ << '\n' << this->indentString_;
 }
 
-void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) {
-  if (!indented_) writeIndent();
-  *document_ << value;
-  indented_ = false;
+void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value)
+{
+  if (!this->indented_)
+    this->writeIndent();
+  *this->document_ << value;
+  this->indented_ = false;
 }
 
-void StyledStreamWriter::indent() { indentString_ += indentation_; }
+void StyledStreamWriter::indent()
+{
+  this->indentString_ += this->indentation_;
+}
 
-void StyledStreamWriter::unindent() {
-  assert(indentString_.size() >= indentation_.size());
-  indentString_.resize(indentString_.size() - indentation_.size());
+void StyledStreamWriter::unindent()
+{
+  assert(this->indentString_.size() >= this->indentation_.size());
+  this->indentString_.resize(this->indentString_.size() -
+                             this->indentation_.size());
 }
 
-void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
+void StyledStreamWriter::writeCommentBeforeValue(const Value& root)
+{
   if (!root.hasComment(commentBefore))
     return;
 
-  if (!indented_) writeIndent();
+  if (!this->indented_)
+    this->writeIndent();
   const JSONCPP_STRING& comment = root.getComment(commentBefore);
   JSONCPP_STRING::const_iterator iter = comment.begin();
   while (iter != comment.end()) {
-    *document_ << *iter;
-    if (*iter == '\n' &&
-       (iter != comment.end() && *(iter + 1) == '/'))
+    *this->document_ << *iter;
+    if (*iter == '\n' && (iter != comment.end() && *(iter + 1) == '/'))
       // writeIndent();  // would include newline
-      *document_ << indentString_;
+      *this->document_ << this->indentString_;
     ++iter;
   }
-  indented_ = false;
+  this->indented_ = false;
 }
 
-void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root)
+{
   if (root.hasComment(commentAfterOnSameLine))
-    *document_ << ' ' << root.getComment(commentAfterOnSameLine);
+    *this->document_ << ' ' << root.getComment(commentAfterOnSameLine);
 
   if (root.hasComment(commentAfter)) {
-    writeIndent();
-    *document_ << root.getComment(commentAfter);
+    this->writeIndent();
+    *this->document_ << root.getComment(commentAfter);
   }
-  indented_ = false;
+  this->indented_ = false;
 }
 
-bool StyledStreamWriter::hasCommentForValue(const Value& value) {
+bool StyledStreamWriter::hasCommentForValue(const Value& value)
+{
   return value.hasComment(commentBefore) ||
-         value.hasComment(commentAfterOnSameLine) ||
-         value.hasComment(commentAfter);
+    value.hasComment(commentAfterOnSameLine) || value.hasComment(commentAfter);
 }
 
 //////////////////////////
 // BuiltStyledStreamWriter
 
 /// Scoped enums are not available until C++11.
-struct CommentStyle {
+struct CommentStyle
+{
   /// Decide whether to write comments.
-  enum Enum {
-    None,  ///< Drop all comments.
-    Most,  ///< Recover odd behavior of previous versions (not implemented yet).
-    All  ///< Keep all comments.
+  enum Enum
+  {
+    None, ///< Drop all comments.
+    Most, ///< Recover odd behavior of previous versions (not implemented yet).
+    All   ///< Keep all comments.
   };
 };
 
 struct BuiltStyledStreamWriter : public StreamWriter
 {
-  BuiltStyledStreamWriter(
-      JSONCPP_STRING const& indentation,
-      CommentStyle::Enum cs,
-      JSONCPP_STRING const& colonSymbol,
-      JSONCPP_STRING const& nullSymbol,
-      JSONCPP_STRING const& endingLineFeedSymbol,
-      bool useSpecialFloats,
-      unsigned int precision);
+  BuiltStyledStreamWriter(JSONCPP_STRING const& indentation,
+                          CommentStyle::Enum cs,
+                          JSONCPP_STRING const& colonSymbol,
+                          JSONCPP_STRING const& nullSymbol,
+                          JSONCPP_STRING const& endingLineFeedSymbol,
+                          bool useSpecialFloats, unsigned int precision);
   int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
+
 private:
   void writeValue(Value const& value);
   void writeArrayValue(Value const& value);
@@ -911,13 +995,10 @@ private:
   unsigned int precision_;
 };
 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
-      JSONCPP_STRING const& indentation,
-      CommentStyle::Enum cs,
-      JSONCPP_STRING const& colonSymbol,
-      JSONCPP_STRING const& nullSymbol,
-      JSONCPP_STRING const& endingLineFeedSymbol,
-      bool useSpecialFloats,
-      unsigned int precision)
+  JSONCPP_STRING const& indentation, CommentStyle::Enum cs,
+  JSONCPP_STRING const& colonSymbol, JSONCPP_STRING const& nullSymbol,
+  JSONCPP_STRING const& endingLineFeedSymbol, bool useSpecialFloats,
+  unsigned int precision)
   : rightMargin_(74)
   , indentation_(indentation)
   , cs_(cs)
@@ -932,247 +1013,276 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
 }
 int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
 {
-  sout_ = sout;
-  addChildValues_ = false;
-  indented_ = true;
-  indentString_.clear();
-  writeCommentBeforeValue(root);
-  if (!indented_) writeIndent();
-  indented_ = true;
-  writeValue(root);
-  writeCommentAfterValueOnSameLine(root);
-  *sout_ << endingLineFeedSymbol_;
-  sout_ = NULL;
+  this->sout_ = sout;
+  this->addChildValues_ = false;
+  this->indented_ = true;
+  this->indentString_.clear();
+  this->writeCommentBeforeValue(root);
+  if (!this->indented_)
+    this->writeIndent();
+  this->indented_ = true;
+  this->writeValue(root);
+  this->writeCommentAfterValueOnSameLine(root);
+  *this->sout_ << this->endingLineFeedSymbol_;
+  this->sout_ = NULL;
   return 0;
 }
-void BuiltStyledStreamWriter::writeValue(Value const& value) {
+void BuiltStyledStreamWriter::writeValue(Value const& value)
+{
   switch (value.type()) {
-  case nullValue:
-    pushValue(nullSymbol_);
-    break;
-  case intValue:
-    pushValue(valueToString(value.asLargestInt()));
-    break;
-  case uintValue:
-    pushValue(valueToString(value.asLargestUInt()));
-    break;
-  case realValue:
-    pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
-    break;
-  case stringValue:
-  {
-    // Is NULL is possible for value.string_? No.
-    char const* str;
-    char const* end;
-    bool ok = value.getString(&str, &end);
-    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
-    else pushValue("");
-    break;
-  }
-  case booleanValue:
-    pushValue(valueToString(value.asBool()));
-    break;
-  case arrayValue:
-    writeArrayValue(value);
-    break;
-  case objectValue: {
-    Value::Members members(value.getMemberNames());
-    if (members.empty())
-      pushValue("{}");
-    else {
-      writeWithIndent("{");
-      indent();
-      Value::Members::iterator it = members.begin();
-      for (;;) {
-        JSONCPP_STRING const& name = *it;
-        Value const& childValue = value[name];
-        writeCommentBeforeValue(childValue);
-        writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
-        *sout_ << colonSymbol_;
-        writeValue(childValue);
-        if (++it == members.end()) {
-          writeCommentAfterValueOnSameLine(childValue);
-          break;
+    case nullValue:
+      this->pushValue(this->nullSymbol_);
+      break;
+    case intValue:
+      this->pushValue(valueToString(value.asLargestInt()));
+      break;
+    case uintValue:
+      this->pushValue(valueToString(value.asLargestUInt()));
+      break;
+    case realValue:
+      this->pushValue(valueToString(value.asDouble(), this->useSpecialFloats_,
+                                    this->precision_));
+      break;
+    case stringValue: {
+      // Is NULL is possible for value.string_? No.
+      char const* str;
+      char const* end;
+      bool ok = value.getString(&str, &end);
+      if (ok)
+        this->pushValue(
+          valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+      else
+        this->pushValue("");
+      break;
+    }
+    case booleanValue:
+      this->pushValue(valueToString(value.asBool()));
+      break;
+    case arrayValue:
+      this->writeArrayValue(value);
+      break;
+    case objectValue: {
+      Value::Members members(value.getMemberNames());
+      if (members.empty())
+        this->pushValue("{}");
+      else {
+        this->writeWithIndent("{");
+        this->indent();
+        Value::Members::iterator it = members.begin();
+        for (;;) {
+          JSONCPP_STRING const& name = *it;
+          Value const& childValue = value[name];
+          this->writeCommentBeforeValue(childValue);
+          this->writeWithIndent(valueToQuotedStringN(
+            name.data(), static_cast<unsigned>(name.length())));
+          *this->sout_ << this->colonSymbol_;
+          this->writeValue(childValue);
+          if (++it == members.end()) {
+            this->writeCommentAfterValueOnSameLine(childValue);
+            break;
+          }
+          *this->sout_ << ",";
+          this->writeCommentAfterValueOnSameLine(childValue);
         }
-        *sout_ << ",";
-        writeCommentAfterValueOnSameLine(childValue);
+        this->unindent();
+        this->writeWithIndent("}");
       }
-      unindent();
-      writeWithIndent("}");
-    }
-  } break;
+    } break;
   }
 }
 
-void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
+void BuiltStyledStreamWriter::writeArrayValue(Value const& value)
+{
   unsigned size = value.size();
   if (size == 0)
-    pushValue("[]");
+    this->pushValue("[]");
   else {
-    bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
+    bool isMultiLine =
+      (this->cs_ == CommentStyle::All) || this->isMultineArray(value);
     if (isMultiLine) {
-      writeWithIndent("[");
-      indent();
-      bool hasChildValue = !childValues_.empty();
+      this->writeWithIndent("[");
+      this->indent();
+      bool hasChildValue = !this->childValues_.empty();
       unsigned index = 0;
       for (;;) {
         Value const& childValue = value[index];
-        writeCommentBeforeValue(childValue);
+        this->writeCommentBeforeValue(childValue);
         if (hasChildValue)
-          writeWithIndent(childValues_[index]);
+          this->writeWithIndent(this->childValues_[index]);
         else {
-          if (!indented_) writeIndent();
-          indented_ = true;
-          writeValue(childValue);
-          indented_ = false;
+          if (!this->indented_)
+            this->writeIndent();
+          this->indented_ = true;
+          this->writeValue(childValue);
+          this->indented_ = false;
         }
         if (++index == size) {
-          writeCommentAfterValueOnSameLine(childValue);
+          this->writeCommentAfterValueOnSameLine(childValue);
           break;
         }
-        *sout_ << ",";
-        writeCommentAfterValueOnSameLine(childValue);
+        *this->sout_ << ",";
+        this->writeCommentAfterValueOnSameLine(childValue);
       }
-      unindent();
-      writeWithIndent("]");
+      this->unindent();
+      this->writeWithIndent("]");
     } else // output on a single line
     {
-      assert(childValues_.size() == size);
-      *sout_ << "[";
-      if (!indentation_.empty()) *sout_ << " ";
+      assert(this->childValues_.size() == size);
+      *this->sout_ << "[";
+      if (!this->indentation_.empty())
+        *this->sout_ << " ";
       for (unsigned index = 0; index < size; ++index) {
         if (index > 0)
-          *sout_ << ((!indentation_.empty()) ? ", " : ",");
-        *sout_ << childValues_[index];
+          *this->sout_ << ((!this->indentation_.empty()) ? ", " : ",");
+        *this->sout_ << this->childValues_[index];
       }
-      if (!indentation_.empty()) *sout_ << " ";
-      *sout_ << "]";
+      if (!this->indentation_.empty())
+        *this->sout_ << " ";
+      *this->sout_ << "]";
     }
   }
 }
 
-bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
+bool BuiltStyledStreamWriter::isMultineArray(Value const& value)
+{
   ArrayIndex const size = value.size();
-  bool isMultiLine = size * 3 >= rightMargin_;
-  childValues_.clear();
+  bool isMultiLine = size * 3 >= this->rightMargin_;
+  this->childValues_.clear();
   for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
     Value const& childValue = value[index];
     isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
-                        childValue.size() > 0);
+                   childValue.size() > 0);
   }
   if (!isMultiLine) // check if line length > max line length
   {
-    childValues_.reserve(size);
-    addChildValues_ = true;
+    this->childValues_.reserve(size);
+    this->addChildValues_ = true;
     ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
     for (ArrayIndex index = 0; index < size; ++index) {
       if (hasCommentForValue(value[index])) {
         isMultiLine = true;
       }
-      writeValue(value[index]);
-      lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+      this->writeValue(value[index]);
+      lineLength +=
+        static_cast<ArrayIndex>(this->childValues_[index].length());
     }
-    addChildValues_ = false;
-    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+    this->addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= this->rightMargin_;
   }
   return isMultiLine;
 }
 
-void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) {
-  if (addChildValues_)
-    childValues_.push_back(value);
+void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value)
+{
+  if (this->addChildValues_)
+    this->childValues_.push_back(value);
   else
-    *sout_ << value;
+    *this->sout_ << value;
 }
 
-void BuiltStyledStreamWriter::writeIndent() {
+void BuiltStyledStreamWriter::writeIndent()
+{
   // blep intended this to look at the so-far-written string
   // to determine whether we are already indented, but
   // with a stream we cannot do that. So we rely on some saved state.
   // The caller checks indented_.
 
-  if (!indentation_.empty()) {
+  if (!this->indentation_.empty()) {
     // In this case, drop newlines too.
-    *sout_ << '\n' << indentString_;
+    *this->sout_ << '\n' << this->indentString_;
   }
 }
 
-void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) {
-  if (!indented_) writeIndent();
-  *sout_ << value;
-  indented_ = false;
+void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value)
+{
+  if (!this->indented_)
+    this->writeIndent();
+  *this->sout_ << value;
+  this->indented_ = false;
 }
 
-void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
+void BuiltStyledStreamWriter::indent()
+{
+  this->indentString_ += this->indentation_;
+}
 
-void BuiltStyledStreamWriter::unindent() {
-  assert(indentString_.size() >= indentation_.size());
-  indentString_.resize(indentString_.size() - indentation_.size());
+void BuiltStyledStreamWriter::unindent()
+{
+  assert(this->indentString_.size() >= this->indentation_.size());
+  this->indentString_.resize(this->indentString_.size() -
+                             this->indentation_.size());
 }
 
-void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
-  if (cs_ == CommentStyle::None) return;
+void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root)
+{
+  if (this->cs_ == CommentStyle::None)
+    return;
   if (!root.hasComment(commentBefore))
     return;
 
-  if (!indented_) writeIndent();
+  if (!this->indented_)
+    this->writeIndent();
   const JSONCPP_STRING& comment = root.getComment(commentBefore);
   JSONCPP_STRING::const_iterator iter = comment.begin();
   while (iter != comment.end()) {
-    *sout_ << *iter;
-    if (*iter == '\n' &&
-       (iter != comment.end() && *(iter + 1) == '/'))
+    *this->sout_ << *iter;
+    if (*iter == '\n' && (iter != comment.end() && *(iter + 1) == '/'))
       // writeIndent();  // would write extra newline
-      *sout_ << indentString_;
+      *this->sout_ << this->indentString_;
     ++iter;
   }
-  indented_ = false;
+  this->indented_ = false;
 }
 
-void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
-  if (cs_ == CommentStyle::None) return;
+void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
+  Value const& root)
+{
+  if (this->cs_ == CommentStyle::None)
+    return;
   if (root.hasComment(commentAfterOnSameLine))
-    *sout_ << " " + root.getComment(commentAfterOnSameLine);
+    *this->sout_ << " " + root.getComment(commentAfterOnSameLine);
 
   if (root.hasComment(commentAfter)) {
-    writeIndent();
-    *sout_ << root.getComment(commentAfter);
+    this->writeIndent();
+    *this->sout_ << root.getComment(commentAfter);
   }
 }
 
 // static
-bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
+bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value)
+{
   return value.hasComment(commentBefore) ||
-         value.hasComment(commentAfterOnSameLine) ||
-         value.hasComment(commentAfter);
+    value.hasComment(commentAfterOnSameLine) || value.hasComment(commentAfter);
 }
 
 ///////////////
 // StreamWriter
 
 StreamWriter::StreamWriter()
-    : sout_(NULL)
+  : sout_(NULL)
 {
 }
 StreamWriter::~StreamWriter()
 {
 }
 StreamWriter::Factory::~Factory()
-{}
+{
+}
 StreamWriterBuilder::StreamWriterBuilder()
 {
-  setDefaults(&settings_);
+  setDefaults(&this->settings_);
 }
 StreamWriterBuilder::~StreamWriterBuilder()
-{}
+{
+}
 StreamWriter* StreamWriterBuilder::newStreamWriter() const
 {
-  JSONCPP_STRING indentation = settings_["indentation"].asString();
-  JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
-  bool eyc = settings_["enableYAMLCompatibility"].asBool();
-  bool dnp = settings_["dropNullPlaceholders"].asBool();
-  bool usf = settings_["useSpecialFloats"].asBool(); 
-  unsigned int pre = settings_["precision"].asUInt();
+  JSONCPP_STRING indentation = this->settings_["indentation"].asString();
+  JSONCPP_STRING cs_str = this->settings_["commentStyle"].asString();
+  bool eyc = this->settings_["enableYAMLCompatibility"].asBool();
+  bool dnp = this->settings_["dropNullPlaceholders"].asBool();
+  bool usf = this->settings_["useSpecialFloats"].asBool();
+  unsigned int pre = this->settings_["precision"].asUInt();
   CommentStyle::Enum cs = CommentStyle::All;
   if (cs_str == "All") {
     cs = CommentStyle::All;
@@ -1191,11 +1301,11 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
   if (dnp) {
     nullSymbol.clear();
   }
-  if (pre > 17) pre = 17;
+  if (pre > 17)
+    pre = 17;
   JSONCPP_STRING endingLineFeedSymbol;
-  return new BuiltStyledStreamWriter(
-      indentation, cs,
-      colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
+  return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
+                                     endingLineFeedSymbol, usf, pre);
 }
 static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
 {
@@ -1210,23 +1320,24 @@ static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
 bool StreamWriterBuilder::validate(Json::Value* invalid) const
 {
   Json::Value my_invalid;
-  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
+  if (!invalid)
+    invalid = &my_invalid; // so we do not need to test for NULL
   Json::Value& inv = *invalid;
   std::set<JSONCPP_STRING> valid_keys;
   getValidWriterKeys(&valid_keys);
-  Value::Members keys = settings_.getMemberNames();
+  Value::Members keys = this->settings_.getMemberNames();
   size_t n = keys.size();
   for (size_t i = 0; i < n; ++i) {
     JSONCPP_STRING const& key = keys[i];
     if (valid_keys.find(key) == valid_keys.end()) {
-      inv[key] = settings_[key];
+      inv[key] = this->settings_[key];
     }
   }
   return 0u == inv.size();
 }
 Value& StreamWriterBuilder::operator[](JSONCPP_STRING key)
 {
-  return settings_[key];
+  return this->settings_[key];
 }
 // static
 void StreamWriterBuilder::setDefaults(Json::Value* settings)
@@ -1241,14 +1352,17 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
   //! [StreamWriterBuilderDefaults]
 }
 
-JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) {
+JSONCPP_STRING writeString(StreamWriter::Factory const& builder,
+                           Value const& root)
+{
   JSONCPP_OSTRINGSTREAM sout;
   StreamWriterPtr const writer(builder.newStreamWriter());
   writer->write(root, &sout);
   return sout.str();
 }
 
-JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) {
+JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root)
+{
   StreamWriterBuilder builder;
   StreamWriterPtr const writer(builder.newStreamWriter());
   writer->write(root, &sout);
index bfcaf30..689d98a 100644 (file)
@@ -94,7 +94,7 @@ SET(CMAKE_REQUIRED_FLAGS)
 
 # Disable warnings to avoid changing 3rd party code.
 IF(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -1475,9 +1475,15 @@ CHECK_C_SOURCE_COMPILES(
   "#include <sys/sysmacros.h>\nint main() { return major(256); }"
   MAJOR_IN_SYSMACROS)
 
+CMAKE_PUSH_CHECK_STATE()
+SET(CMAKE_REQUIRED_LIBRARIES ${LIBLZMA_LIBRARIES})
+SET(CMAKE_REQUIRED_INCLUDES ${LIBLZMA_INCLUDE_DIR})
+
 CHECK_C_SOURCE_COMPILES(
   "#include <lzma.h>\n#if LZMA_VERSION < 50020000\n#error unsupported\n#endif\nint main(void){lzma_stream_encoder_mt(0, 0); return 0;}"
-  HAVE_LZMA_STREAM_ENCODER_MT)
+HAVE_LZMA_STREAM_ENCODER_MT)
+
+CMAKE_POP_CHECK_STATE()
 
 IF(HAVE_STRERROR_R)
   SET(HAVE_DECL_STRERROR_R 1)
index 9d1aa49..65ea691 100644 (file)
@@ -173,7 +173,7 @@ arc4_init(void)
 }
 
 static inline void
-arc4_addrandom(uint8_t *dat, int datlen)
+arc4_addrandom(u_char *dat, int datlen)
 {
        int     n;
        uint8_t si;
@@ -196,7 +196,7 @@ arc4_stir(void)
        struct {
                struct timeval  tv;
                pid_t           pid;
-               uint8_t         rnd[KEYSIZE];
+               u_char          rnd[KEYSIZE];
        } rdat;
 
        if (!rs_initialized) {
@@ -216,7 +216,7 @@ arc4_stir(void)
                /* We'll just take whatever was on the stack too... */
        }
 
-       arc4_addrandom((uint8_t *)&rdat, KEYSIZE);
+       arc4_addrandom((u_char *)&rdat, KEYSIZE);
 
        /*
         * Discard early keystream, as per recommendations in:
@@ -258,7 +258,7 @@ arc4_getbyte(void)
 static void
 arc4random_buf(void *_buf, size_t n)
 {
-       uint8_t *buf = (uint8_t *)_buf;
+       u_char *buf = (u_char *)_buf;
        _ARC4_LOCK();
        arc4_stir_if_needed();
        while (n--) {
index 6b6fae6..32a14dc 100644 (file)
@@ -148,7 +148,7 @@ INCLUDE_DIRECTORIES(
 
 # Disable warnings to avoid changing 3rd party code.
 IF(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 1b025fc..37e2399 100644 (file)
@@ -2,7 +2,7 @@ project(librhash C)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 92d2411..f8b47af 100644 (file)
@@ -2,7 +2,7 @@ project(libuv C)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 3a11ace..17cc6dd 100644 (file)
@@ -1,6 +1,6 @@
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 0584c55..d266af9 100644 (file)
@@ -2,7 +2,7 @@ PROJECT(CMZLIB)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 4f4f91f..323151c 100644 (file)
@@ -2,7 +2,7 @@ project(zstd C)
 
 # Disable warnings to avoid changing 3rd party code.
 if(CMAKE_C_COMPILER_ID MATCHES
-    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$")
+    "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM)$")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
index 9a5d840..2ebc78c 100644 (file)
@@ -68,16 +68,22 @@ public:
 
   optional& operator=(nullopt_t) noexcept;
   optional& operator=(const optional& other);
-  optional& operator=(optional&& other) noexcept;
 
-  template <
-    typename U = T,
-    typename = typename std::enable_if<
-      !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
-      std::is_constructible<T, U>::value && std::is_assignable<T&, U>::value &&
+  template <typename U = T>
+  typename std::enable_if<std::is_constructible<T, U&&>::value &&
+                            std::is_assignable<T&, U&&>::value,
+                          optional&>::type
+  operator=(optional<U>&& other) noexcept;
+
+  template <typename U = T>
+  typename std::enable_if<
+    !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
+      std::is_constructible<T, U&&>::value &&
+      std::is_assignable<T&, U&&>::value &&
       (!std::is_scalar<T>::value ||
-       !std::is_same<typename std::decay<U>::type, T>::value)>::type>
-  optional& operator=(U&& v);
+       !std::is_same<typename std::decay<U>::type, T>::value),
+    optional&>::type
+  operator=(U&& v);
 
   const T* operator->() const;
   T* operator->();
@@ -134,19 +140,24 @@ optional<T> make_optional(Args&&... args)
 
 template <typename T>
 optional<T>::optional(nullopt_t) noexcept
+  : optional()
 {
 }
 
 template <typename T>
 optional<T>::optional(const optional& other)
 {
-  *this = other;
+  if (other.has_value()) {
+    this->emplace(*other);
+  }
 }
 
 template <typename T>
 optional<T>::optional(optional&& other) noexcept
 {
-  *this = std::move(other);
+  if (other.has_value()) {
+    this->emplace(std::move(*other));
+  }
 }
 
 template <typename T>
@@ -192,7 +203,11 @@ optional<T>& optional<T>::operator=(const optional& other)
 }
 
 template <typename T>
-optional<T>& optional<T>::operator=(optional&& other) noexcept
+template <typename U>
+typename std::enable_if<std::is_constructible<T, U&&>::value &&
+                          std::is_assignable<T&, U&&>::value,
+                        optional<T>&>::type
+optional<T>::operator=(optional<U>&& other) noexcept
 {
   if (other.has_value()) {
     if (this->has_value()) {
@@ -207,8 +222,15 @@ optional<T>& optional<T>::operator=(optional&& other) noexcept
 }
 
 template <typename T>
-template <typename U, typename>
-optional<T>& optional<T>::operator=(U&& v)
+template <typename U>
+typename std::enable_if<
+  !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
+    std::is_constructible<T, U&&>::value &&
+    std::is_assignable<T&, U&&>::value &&
+    (!std::is_scalar<T>::value ||
+     !std::is_same<typename std::decay<U>::type, T>::value),
+  optional<T>&>::type
+optional<T>::operator=(U&& v)
 {
   if (this->has_value()) {
     this->value() = v;
@@ -291,7 +313,7 @@ bool operator!=(const optional<T>& opt, nullopt_t) noexcept
 }
 
 template <typename T>
-bool operator<(const optional<T>& opt, nullopt_t) noexcept
+bool operator<(const optional<T>& /*opt*/, nullopt_t) noexcept
 {
   return false;
 }
@@ -309,7 +331,7 @@ bool operator>(const optional<T>& opt, nullopt_t) noexcept
 }
 
 template <typename T>
-bool operator>=(const optional<T>& opt, nullopt_t) noexcept
+bool operator>=(const optional<T>& /*opt*/, nullopt_t) noexcept
 {
   return true;
 }
@@ -333,13 +355,13 @@ bool operator<(nullopt_t, const optional<T>& opt) noexcept
 }
 
 template <typename T>
-bool operator<=(nullopt_t, const optional<T>& opt) noexcept
+bool operator<=(nullopt_t, const optional<T>& /*opt*/) noexcept
 {
   return true;
 }
 
 template <typename T>
-bool operator>(nullopt_t, const optional<T>& opt) noexcept
+bool operator>(nullopt_t, const optional<T>& /*opt*/) noexcept
 {
   return false;
 }
index 7ec3687..f85d57e 100755 (executable)
--- a/bootstrap
+++ b/bootstrap
@@ -289,10 +289,10 @@ CMAKE_CXX_SOURCES="\
   cmBuildCommand \
   cmCMakeMinimumRequired \
   cmCMakePath \
+  cmCMakePathCommand \
   cmCMakePolicyCommand \
   cmCPackPropertiesGenerator \
   cmCacheManager \
-  cmCheckCustomOutputs \
   cmCommand \
   cmCommandArgumentParserHelper \
   cmCommands \
@@ -307,6 +307,7 @@ CMAKE_CXX_SOURCES="\
   cmContinueCommand \
   cmCoreTryCompile \
   cmCreateTestSourceList \
+  cmCryptoHash \
   cmCustomCommand \
   cmCustomCommandGenerator \
   cmCustomCommandLines \
@@ -412,6 +413,8 @@ CMAKE_CXX_SOURCES="\
   cmProjectCommand \
   cmPropertyDefinition \
   cmPropertyMap \
+  cmGccDepfileLexerHelper \
+  cmGccDepfileReader \
   cmReturnCommand \
   cmRulePlaceholderExpander \
   cmRuntimeDependencyArchive \
@@ -452,6 +455,7 @@ CMAKE_CXX_SOURCES="\
   cmTest \
   cmTestGenerator \
   cmTimestamp \
+  cmTransformDepfile \
   cmTryCompileCommand \
   cmTryRunCommand \
   cmUnsetCommand \
@@ -491,6 +495,7 @@ LexerParser_CXX_SOURCES="\
   cmCommandArgumentParser \
   cmExprLexer \
   cmExprParser \
+  cmGccDepfileLexer \
 "
 
 LexerParser_C_SOURCES="\
@@ -535,6 +540,18 @@ KWSYS_FILES="\
   SystemTools.hxx \
   Terminal.h"
 
+LIBRHASH_C_SOURCES="\
+  librhash/algorithms.c \
+  librhash/byte_order.c \
+  librhash/hex.c \
+  librhash/md5.c \
+  librhash/rhash.c \
+  librhash/sha1.c \
+  librhash/sha256.c \
+  librhash/sha3.c \
+  librhash/sha512.c \
+  "
+
 if ${cmake_system_mingw}; then
   LIBUV_C_SOURCES="\
     src/fs-poll.c \
@@ -927,11 +944,10 @@ while test $# != 0; do
 done
 
 # Make sure the generator is valid
-if test "${cmake_bootstrap_generator}" != "MSYS Makefiles" -a \
-    "${cmake_bootstrap_generator}" != "Unix Makefiles" -a \
-    "${cmake_bootstrap_generator}" != "Ninja"; then
-  cmake_error 10 "Invalid generator: ${cmake_bootstrap_generator}"
-fi
+case "${cmake_bootstrap_generator}" in
+  'MSYS Makefiles'|'Unix Makefiles'|'Ninja') ;;
+  *) cmake_error 10 "Invalid generator: ${cmake_bootstrap_generator}"
+esac
 
 # If verbose, display some information about bootstrap
 if test -n "${cmake_verbose}"; then
@@ -1012,7 +1028,6 @@ cmake_ld_flags=${LDFLAGS}
 # Add generator-specific files
 if test "${cmake_bootstrap_generator}" = "Ninja"; then
   CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \
-    cmCryptoHash \
     cmFortranParserImpl \
     cmGlobalNinjaGenerator \
     cmLocalNinjaGenerator \
@@ -1033,32 +1048,21 @@ if test "${cmake_bootstrap_generator}" = "Ninja"; then
     src/lib_json/json_value.cpp \
     src/lib_json/json_writer.cpp \
     "
-
-  LIBRHASH_C_SOURCES="\
-    librhash/algorithms.c \
-    librhash/byte_order.c \
-    librhash/hex.c \
-    librhash/md5.c \
-    librhash/rhash.c \
-    librhash/sha1.c \
-    librhash/sha256.c \
-    librhash/sha3.c \
-    librhash/sha512.c \
-    "
 else
   CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \
     cmDepends \
     cmDependsC \
+    cmDependsCompiler \
     cmGlobalUnixMakefileGenerator3 \
     cmLocalUnixMakefileGenerator3 \
     cmMakefileExecutableTargetGenerator \
     cmMakefileLibraryTargetGenerator \
     cmMakefileTargetGenerator \
     cmMakefileUtilityTargetGenerator \
+    cmProcessTools \
     "
 
   JSONCPP_CXX_SOURCES=
-  LIBRHASH_C_SOURCES=
 fi
 
 # Add Cygwin-specific flags
@@ -1191,8 +1195,8 @@ for std in 11 99 90; do
   for compiler in ${cmake_c_compilers}; do
     for std_flag in '' $std_flags; do
       for thread_flag in '' $thread_flags; do
-        echo "Checking whether '${compiler} ${cmake_c_flags} ${std_flag} ${thread_flag}' works." >> cmake_bootstrap.log 2>&1
-        if cmake_try_run "${compiler}" "${cmake_c_flags} ${std_flag} ${thread_flag}" \
+        echo "Checking whether '${compiler} ${cmake_c_flags} ${cmake_ld_flags} ${std_flag} ${thread_flag}' works." >> cmake_bootstrap.log 2>&1
+        if cmake_try_run "${compiler}" "${cmake_c_flags} ${cmake_ld_flags} ${std_flag} ${thread_flag}" \
           "${TMPFILE}.c" >> cmake_bootstrap.log 2>&1; then
           cmake_c_compiler="${compiler}"
           cmake_c_flags="${cmake_c_flags} ${std_flag} ${thread_flag}"
@@ -1312,8 +1316,8 @@ for std in 17 14 11; do
   for compiler in ${cmake_cxx_compilers}; do
     for std_flag in '' $std_flags; do
       for thread_flag in '' $thread_flags; do
-        echo "Checking whether '${compiler} ${cmake_cxx_flags} ${std_flag} ${thread_flag}' works." >> cmake_bootstrap.log 2>&1
-        if cmake_try_run "${compiler}" "${cmake_cxx_flags} ${std_flag} ${thread_flag}" \
+        echo "Checking whether '${compiler} ${cmake_cxx_flags} ${cmake_ld_flags} ${std_flag} ${thread_flag}' works." >> cmake_bootstrap.log 2>&1
+        if cmake_try_run "${compiler}" "${cmake_cxx_flags} ${cmake_ld_flags} ${std_flag} ${thread_flag}" \
           "${TMPFILE}.cxx" >> cmake_bootstrap.log 2>&1; then
           cmake_cxx_compiler="${compiler}"
           cmake_cxx_flags="${cmake_cxx_flags} ${std_flag} ${thread_flag} "
@@ -1341,8 +1345,8 @@ cmake_cxx_features="make_unique filesystem"
 
 for feature in ${cmake_cxx_features}; do
   eval "cmake_have_cxx_${feature}=0"
-  echo "Checking whether '${cmake_cxx_compiler} ${cmake_cxx_flags}' supports '${feature}'." >> cmake_bootstrap.log 2>&1
-  if cmake_try_run "${cmake_cxx_compiler}" "${cmake_cxx_flags}" \
+  echo "Checking whether '${cmake_cxx_compiler} ${cmake_cxx_flags} ${cmake_ld_flags}' supports '${feature}'." >> cmake_bootstrap.log 2>&1
+  if cmake_try_run "${cmake_cxx_compiler}" "${cmake_cxx_flags} ${cmake_ld_flags}" \
                    "${cmake_source_dir}/Source/Checks/cm_cxx_${feature}.cxx" >> cmake_bootstrap.log 2>&1; then
     eval "cmake_have_cxx_${feature}=1"
   fi
@@ -1449,7 +1453,7 @@ KWSYS_CXX_HAS_UTIMES=0
 KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP=1
 
 if cmake_try_run "${cmake_cxx_compiler}" \
-  "${cmake_cxx_flags} -DTEST_KWSYS_CXX_HAS_SETENV" \
+  "${cmake_cxx_flags} ${cmake_ld_flags} -DTEST_KWSYS_CXX_HAS_SETENV" \
   "${cmake_source_dir}/Source/kwsys/kwsysPlatformTestsCXX.cxx" >> cmake_bootstrap.log 2>&1; then
   KWSYS_CXX_HAS_SETENV=1
   echo "${cmake_cxx_compiler} has setenv"
@@ -1458,7 +1462,7 @@ else
 fi
 
 if cmake_try_run "${cmake_cxx_compiler}" \
-  "${cmake_cxx_flags} -DTEST_KWSYS_CXX_HAS_UNSETENV" \
+  "${cmake_cxx_flags} ${cmake_ld_flags} -DTEST_KWSYS_CXX_HAS_UNSETENV" \
   "${cmake_source_dir}/Source/kwsys/kwsysPlatformTestsCXX.cxx" >> cmake_bootstrap.log 2>&1; then
   KWSYS_CXX_HAS_UNSETENV=1
   echo "${cmake_cxx_compiler} has unsetenv"
@@ -1467,7 +1471,7 @@ else
 fi
 
 if cmake_try_run "${cmake_cxx_compiler}" \
-  "${cmake_cxx_flags} -DTEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H" \
+  "${cmake_cxx_flags} ${cmake_ld_flags} -DTEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H" \
   "${cmake_source_dir}/Source/kwsys/kwsysPlatformTestsCXX.cxx" >> cmake_bootstrap.log 2>&1; then
   KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=1
   echo "${cmake_cxx_compiler} has environ in stdlib.h"
@@ -1476,7 +1480,7 @@ else
 fi
 
 if cmake_try_run "${cmake_cxx_compiler}" \
-  "${cmake_cxx_flags} -DTEST_KWSYS_STL_HAS_WSTRING" \
+  "${cmake_cxx_flags} ${cmake_ld_flags} -DTEST_KWSYS_STL_HAS_WSTRING" \
   "${cmake_source_dir}/Source/kwsys/kwsysPlatformTestsCXX.cxx" >> cmake_bootstrap.log 2>&1; then
   KWSYS_STL_HAS_WSTRING=1
   echo "${cmake_cxx_compiler} has stl wstring"
@@ -1485,7 +1489,7 @@ else
 fi
 
 if cmake_try_run "${cmake_cxx_compiler}" \
-  "${cmake_cxx_flags} -DTEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H" \
+  "${cmake_cxx_flags} ${cmake_ld_flags} -DTEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H" \
   "${cmake_source_dir}/Source/kwsys/kwsysPlatformTestsCXX.cxx" >> cmake_bootstrap.log 2>&1; then
   KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H=1
   echo "${cmake_cxx_compiler} has <ext/stdio_filebuf.h>"
@@ -1628,17 +1632,17 @@ if test "x${bootstrap_system_libuv}" = "x"; then
     objs="${objs} uv-`cmake_obj ${a}`"
   done
 fi
+if test "x${bootstrap_system_librhash}" = "x"; then
+  for a in ${LIBRHASH_C_SOURCES}; do
+    objs="${objs} rhash-`cmake_obj ${a}`"
+  done
+fi
 if test "${cmake_bootstrap_generator}" = "Ninja"; then
   if test "x${bootstrap_system_jsoncpp}" = "x"; then
     for a in ${JSONCPP_CXX_SOURCES}; do
       objs="${objs} jsoncpp-`cmake_obj ${a}`"
     done
   fi
-  if test "x${bootstrap_system_librhash}" = "x"; then
-    for a in ${LIBRHASH_C_SOURCES}; do
-      objs="${objs} rhash-`cmake_obj ${a}`"
-    done
-  fi
 fi
 
 libs=""
@@ -1698,6 +1702,15 @@ else
   libs="${libs} -luv"
 fi
 
+if test "x${bootstrap_system_librhash}" != "x"; then
+  if test `which pkg-config`; then
+    use_librhash_flags="`pkg-config --cflags librhash`"
+    cmake_c_flags="${cmake_c_flags} ${use_librhash_flags}"
+    cmake_cxx_flags="${cmake_cxx_flags} ${use_librhash_flags}"
+  fi
+  libs="${libs} -lrhash"
+fi
+
 if test "${cmake_bootstrap_generator}" = "Ninja"; then
   jsoncpp_cxx_flags=
   if test "x${bootstrap_system_jsoncpp}" = "x"; then
@@ -1709,15 +1722,6 @@ if test "${cmake_bootstrap_generator}" = "Ninja"; then
     fi
     libs="${libs} -ljsoncpp"
   fi
-
-  if test "x${bootstrap_system_librhash}" != "x"; then
-    if test `which pkg-config`; then
-      use_librhash_flags="`pkg-config --cflags librhash`"
-      cmake_c_flags="${cmake_c_flags} ${use_librhash_flags}"
-      cmake_cxx_flags="${cmake_cxx_flags} ${use_librhash_flags}"
-    fi
-    libs="${libs} -lrhash"
-  fi
 fi
 
 if test "x${cmake_ansi_cxx_flags}" != "x"; then
@@ -1841,6 +1845,12 @@ if test "x${bootstrap_system_libuv}" = "x"; then
     write_source_rule "c" "uv-`cmake_obj ${a}`" "${src}" "${uv_c_flags}"
   done
 fi
+if test "x${bootstrap_system_librhash}" = "x"; then
+  for a in ${LIBRHASH_C_SOURCES}; do
+    src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/cmlibrhash/${a}"`
+    write_source_rule "c" "rhash-`cmake_obj ${a}`" "${src}" ""
+  done
+fi
 if test "${cmake_bootstrap_generator}" = "Ninja"; then
   if test "x${bootstrap_system_jsoncpp}" = "x"; then
     for a in ${JSONCPP_CXX_SOURCES}; do
@@ -1848,12 +1858,6 @@ if test "${cmake_bootstrap_generator}" = "Ninja"; then
       write_source_rule "cxx" "jsoncpp-`cmake_obj ${a}`" "${src}" "${jsoncpp_cxx_flags}"
     done
   fi
-  if test "x${bootstrap_system_librhash}" = "x"; then
-    for a in ${LIBRHASH_C_SOURCES}; do
-      src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/cmlibrhash/${a}"`
-      write_source_rule "c" "rhash-`cmake_obj ${a}`" "${src}" ""
-    done
-  fi
 fi
 if test "${cmake_bootstrap_generator}" = "Ninja"; then
   echo "